diff options
Diffstat (limited to 'nixos/modules')
110 files changed, 2654 insertions, 681 deletions
diff --git a/nixos/modules/config/fonts/fontconfig.nix b/nixos/modules/config/fonts/fontconfig.nix index 6f17bd396a0b..922a9cf961df 100644 --- a/nixos/modules/config/fonts/fontconfig.nix +++ b/nixos/modules/config/fonts/fontconfig.nix @@ -142,7 +142,7 @@ with lib; config = let fontconfig = config.fonts.fontconfig; fcBool = x: "<bool>" + (if x then "true" else "false") + "</bool>"; - nixosConf = '' + renderConf = '' <?xml version='1.0'?> <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'> <fontconfig> @@ -169,6 +169,21 @@ with lib; </edit> </match> + ${optionalString (fontconfig.dpi != 0) '' + <match target="pattern"> + <edit name="dpi" mode="assign"> + <double>${toString fontconfig.dpi}</double> + </edit> + </match> + ''} + + </fontconfig> + ''; + genericAliasConf = '' + <?xml version='1.0'?> + <!DOCTYPE fontconfig SYSTEM 'fonts.dtd'> + <fontconfig> + <!-- Default fonts --> ${optionalString (fontconfig.defaultFonts.sansSerif != []) '' <alias> @@ -201,14 +216,6 @@ with lib; </alias> ''} - ${optionalString (fontconfig.dpi != 0) '' - <match target="pattern"> - <edit name="dpi" mode="assign"> - <double>${toString fontconfig.dpi}</double> - </edit> - </match> - ''} - </fontconfig> ''; in mkIf fontconfig.enable { @@ -219,7 +226,8 @@ with lib; environment.etc."fonts/fonts.conf".source = pkgs.makeFontsConf { fontconfig = pkgs.fontconfig_210; fontDirectories = config.fonts.fonts; }; - environment.etc."fonts/conf.d/98-nixos.conf".text = nixosConf; + environment.etc."fonts/conf.d/10-nixos-rendering.conf".text = renderConf; + environment.etc."fonts/conf.d/60-nixos-generic-alias.conf".text = genericAliasConf; # Versioned fontconfig > 2.10. Take shared fonts.conf from fontconfig. # Otherwise specify only font directories. @@ -236,7 +244,8 @@ with lib; </fontconfig> ''; - environment.etc."fonts/${pkgs.fontconfig.configVersion}/conf.d/98-nixos.conf".text = nixosConf; + environment.etc."fonts/${pkgs.fontconfig.configVersion}/conf.d/10-nixos-rendering.conf".text = renderConf; + environment.etc."fonts/${pkgs.fontconfig.configVersion}/conf.d/60-nixos-generic-alias.conf".text = genericAliasConf; environment.etc."fonts/${pkgs.fontconfig.configVersion}/conf.d/99-user.conf" = { enable = fontconfig.includeUserConf; diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix index 62390f452ba2..3a9a09ee87c1 100644 --- a/nixos/modules/config/system-path.nix +++ b/nixos/modules/config/system-path.nix @@ -45,6 +45,7 @@ let pkgs.strace pkgs.su pkgs.time + pkgs.texinfoInteractive pkgs.utillinux extraManpages ]; @@ -57,7 +58,7 @@ in environment = { systemPackages = mkOption { - type = types.listOf types.path; + type = types.listOf types.package; default = []; example = literalExample "[ pkgs.firefox pkgs.thunderbird ]"; description = '' @@ -105,12 +106,14 @@ in "/lib" "/man" "/sbin" + "/share/doc" "/share/emacs" - "/share/vim-plugins" - "/share/org" "/share/info" - "/share/terminfo" "/share/man" + "/share/nano" + "/share/org" + "/share/terminfo" + "/share/vim-plugins" ]; system.path = pkgs.buildEnv { @@ -136,6 +139,13 @@ in if [ -x $out/bin/update-desktop-database -a -w $out/share/applications ]; then $out/bin/update-desktop-database $out/share/applications fi + + if [ -x $out/bin/install-info -a -w $out/share/info ]; then + shopt -s nullglob + for i in $out/share/info/*.info $out/share/info/*.info.gz; do + $out/bin/install-info $i $out/share/info/dir + done + fi ''; }; diff --git a/nixos/modules/config/timezone.nix b/nixos/modules/config/timezone.nix index 068571393116..b9844b4adade 100644 --- a/nixos/modules/config/timezone.nix +++ b/nixos/modules/config/timezone.nix @@ -26,6 +26,7 @@ in hardwareClockInLocalTime = mkOption { default = false; + type = types.bool; description = "If set, keep the hardware clock in local time instead of UTC."; }; diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index 478f433b431c..adc014eed415 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -216,7 +216,7 @@ let exist. If <option>users.mutableUsers</option> is true, the password can be changed subsequently using the <command>passwd</command> command. Otherwise, it's - equivalent to setting the <option>password</option> option. + equivalent to setting the <option>hashedPassword</option> option. ${hashedPasswordDescription} ''; @@ -336,13 +336,13 @@ let map (range: "${user.name}:${toString range.startUid}:${toString range.count}\n") user.subUidRanges); - subuidFile = concatStrings (map mkSubuidEntry (attrValues cfg.extraUsers)); + subuidFile = concatStrings (map mkSubuidEntry (attrValues cfg.users)); mkSubgidEntry = user: concatStrings ( map (range: "${user.name}:${toString range.startGid}:${toString range.count}\n") user.subGidRanges); - subgidFile = concatStrings (map mkSubgidEntry (attrValues cfg.extraUsers)); + subgidFile = concatStrings (map mkSubgidEntry (attrValues cfg.users)); idsAreUnique = set: idAttr: !(fold (name: args@{ dup, acc }: let @@ -354,8 +354,8 @@ let else { dup = false; acc = newAcc; } ) { dup = false; acc = {}; } (builtins.attrNames set)).dup; - uidsAreUnique = idsAreUnique (filterAttrs (n: u: u.uid != null) cfg.extraUsers) "uid"; - gidsAreUnique = idsAreUnique (filterAttrs (n: g: g.gid != null) cfg.extraGroups) "gid"; + uidsAreUnique = idsAreUnique (filterAttrs (n: u: u.uid != null) cfg.users) "uid"; + gidsAreUnique = idsAreUnique (filterAttrs (n: g: g.gid != null) cfg.groups) "gid"; spec = pkgs.writeText "users-groups.json" (builtins.toJSON { inherit (cfg) mutableUsers; @@ -364,13 +364,13 @@ let name uid group description home shell createHome isSystemUser password passwordFile hashedPassword initialPassword initialHashedPassword; - }) cfg.extraUsers; + }) cfg.users; groups = mapAttrsToList (n: g: { inherit (g) name gid; members = g.members ++ (mapAttrsToList (n: u: u.name) ( - filterAttrs (n: u: elem g.name u.extraGroups) cfg.extraUsers + filterAttrs (n: u: elem g.name u.extraGroups) cfg.users )); - }) cfg.extraGroups; + }) cfg.groups; }); in { @@ -388,10 +388,10 @@ in { <literal>groupadd</literal> commands. On system activation, the existing contents of the <literal>/etc/passwd</literal> and <literal>/etc/group</literal> files will be merged with the - contents generated from the <literal>users.extraUsers</literal> and - <literal>users.extraGroups</literal> options. + contents generated from the <literal>users.users</literal> and + <literal>users.groups</literal> options. The initial password for a user will be set - according to <literal>users.extraUsers</literal>, but existing passwords + according to <literal>users.users</literal>, but existing passwords will not be changed. <warning><para> @@ -399,7 +399,7 @@ in { group files will simply be replaced on system activation. This also holds for the user passwords; all changed passwords will be reset according to the - <literal>users.extraUsers</literal> configuration on activation. + <literal>users.users</literal> configuration on activation. </para></warning> ''; }; @@ -412,7 +412,7 @@ in { ''; }; - users.extraUsers = mkOption { + users.users = mkOption { default = {}; type = types.loaOf types.optionSet; example = { @@ -433,7 +433,7 @@ in { options = [ userOpts ]; }; - users.extraGroups = mkOption { + users.groups = mkOption { default = {}; example = { students.gid = 1001; @@ -461,7 +461,7 @@ in { config = { - users.extraUsers = { + users.users = { root = { uid = ids.uids.root; description = "System administrator"; @@ -478,7 +478,7 @@ in { }; }; - users.extraGroups = { + users.groups = { root.gid = ids.gids.root; wheel.gid = ids.gids.wheel; disk.gid = ids.gids.disk; @@ -525,6 +525,27 @@ in { { assertion = !cfg.enforceIdUniqueness || (uidsAreUnique && gidsAreUnique); message = "UIDs and GIDs must be unique!"; } + { # If mutableUsers is false, to prevent users creating a + # configuration that locks them out of the system, ensure that + # there is at least one "privileged" account that has a + # password or an SSH authorized key. Privileged accounts are + # root and users in the wheel group. + assertion = !cfg.mutableUsers -> + any id (mapAttrsToList (name: cfg: + (name == "root" + || cfg.group == "wheel" + || elem "wheel" cfg.extraGroups) + && + ((cfg.hashedPassword != null && cfg.hashedPassword != "!") + || cfg.password != null + || cfg.passwordFile != null + || cfg.openssh.authorizedKeys.keys != [] + || cfg.openssh.authorizedKeys.keyFiles != []) + ) cfg.users); + message = '' + Neither the root account nor any wheel user has a password or SSH authorized key. + You must set one to prevent being locked out of your system.''; + } ]; }; diff --git a/nixos/modules/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix index e4bdeb55cadc..1a04baef1930 100644 --- a/nixos/modules/hardware/all-firmware.nix +++ b/nixos/modules/hardware/all-firmware.nix @@ -22,9 +22,7 @@ with lib; ###### implementation config = mkIf config.hardware.enableAllFirmware { - hardware.firmware = [ - "${pkgs.firmwareLinuxNonfree}/lib/firmware" - ]; + hardware.firmware = [ pkgs.firmwareLinuxNonfree ]; }; } diff --git a/nixos/modules/hardware/video/bumblebee.nix b/nixos/modules/hardware/video/bumblebee.nix index e341eac4a819..e2202e1e17df 100644 --- a/nixos/modules/hardware/video/bumblebee.nix +++ b/nixos/modules/hardware/video/bumblebee.nix @@ -52,9 +52,9 @@ in systemd.services.bumblebeed = { description = "Bumblebee Hybrid Graphics Switcher"; wantedBy = [ "display-manager.service" ]; - script = "bumblebeed --use-syslog -g ${config.hardware.bumblebee.group}"; path = [ kernel.bbswitch bumblebee ]; serviceConfig = { + ExecStart = "${bumblebee}/bin/bumblebeed --use-syslog -g ${config.hardware.bumblebee.group}"; Restart = "always"; RestartSec = 60; CPUSchedulingPolicy = "idle"; diff --git a/nixos/modules/hardware/video/encoder/wis-go7007.nix b/nixos/modules/hardware/video/encoder/wis-go7007.nix index c0eb2b814b33..e9b3cf72a8dd 100644 --- a/nixos/modules/hardware/video/encoder/wis-go7007.nix +++ b/nixos/modules/hardware/video/encoder/wis-go7007.nix @@ -5,11 +5,11 @@ let in { - boot.extraModulePackages = [wis_go7007]; + boot.extraModulePackages = [ wis_go7007 ]; - environment.systemPackages = [wis_go7007]; + environment.systemPackages = [ wis_go7007 ]; - hardware.firmware = ["${wis_go7007}/firmware"]; + hardware.firmware = [ wis_go7007 ]; - services.udev.packages = [wis_go7007]; + services.udev.packages = [ wis_go7007 ]; } diff --git a/nixos/modules/installer/cd-dvd/channel.nix b/nixos/modules/installer/cd-dvd/channel.nix index ca0e233f9e3f..eccb19da5cb3 100644 --- a/nixos/modules/installer/cd-dvd/channel.nix +++ b/nixos/modules/installer/cd-dvd/channel.nix @@ -9,18 +9,17 @@ let # We need a copy of the Nix expressions for Nixpkgs and NixOS on the # CD. These are installed into the "nixos" channel of the root - # user, as expected by nixos-rebuild/nixos-install. + # user, as expected by nixos-rebuild/nixos-install. FIXME: merge + # with make-channel.nix. channelSources = pkgs.runCommand "nixos-${config.system.nixosVersion}" - { expr = readFile ../../../lib/channel-expr.nix; } + { } '' - mkdir -p $out/nixos - cp -prd ${pkgs.path} $out/nixos/nixpkgs - ln -s nixpkgs/nixos $out/nixos/nixos + mkdir -p $out + cp -prd ${pkgs.path} $out/nixos chmod -R u+w $out/nixos - rm -rf $out/nixos/nixpkgs/.git - echo -n ${config.system.nixosVersion} > $out/nixos/nixpkgs/.version - echo -n "" > $out/nixos/nixpkgs/.version-suffix - echo "$expr" > $out/nixos/default.nix + ln -s . $out/nixos/nixpkgs + rm -rf $out/nixos/.git + echo -n ${config.system.nixosVersionSuffix} > $out/nixos/.version-suffix ''; in diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index c9abff2ecfc0..fa9cc6fa20b9 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -30,8 +30,7 @@ let # * COM32 entries (chainload, reboot, poweroff) are not recognized. They # result in incorrect boot entries. - baseIsolinuxCfg = - '' + baseIsolinuxCfg = '' SERIAL 0 38400 TIMEOUT ${builtins.toString syslinuxTimeout} UI vesamenu.c32 @@ -44,7 +43,7 @@ let LINUX /boot/bzImage APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} INITRD /boot/initrd - ''; + ''; isolinuxMemtest86Entry = '' LABEL memtest @@ -55,12 +54,12 @@ let isolinuxCfg = baseIsolinuxCfg + (optionalString config.boot.loader.grub.memtest86.enable isolinuxMemtest86Entry); - # The efi boot image + # The EFI boot image. efiDir = pkgs.runCommand "efi-directory" {} '' mkdir -p $out/EFI/boot cp -v ${pkgs.gummiboot}/lib/gummiboot/gummiboot${targetArch}.efi $out/EFI/boot/boot${targetArch}.efi mkdir -p $out/loader/entries - echo "title NixOS LiveCD" > $out/loader/entries/nixos-livecd.conf + echo "title NixOS Live CD" > $out/loader/entries/nixos-livecd.conf echo "linux /boot/bzImage" >> $out/loader/entries/nixos-livecd.conf echo "initrd /boot/initrd" >> $out/loader/entries/nixos-livecd.conf echo "options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}" >> $out/loader/entries/nixos-livecd.conf @@ -218,6 +217,8 @@ in system.boot.loader.kernelFile = "bzImage"; environment.systemPackages = [ pkgs.grub2 pkgs.grub2_efi pkgs.syslinux ]; + boot.consoleLogLevel = mkDefault 7; + # In stage 1 of the boot, mount the CD as the root FS by label so # that we don't need to know its device. We pass the label of the # root filesystem on the kernel command line, rather than in @@ -229,6 +230,7 @@ in boot.kernelParams = [ "root=LABEL=${config.isoImage.volumeID}" "boot.shell_on_fail" + "nomodeset" ]; fileSystems."/" = @@ -268,6 +270,8 @@ in boot.initrd.availableKernelModules = [ "squashfs" "iso9660" "usb-storage" ]; + boot.blacklistedKernelModules = [ "nouveau" ]; + boot.initrd.kernelModules = [ "loop" ]; # Closures to be copied to the Nix store on the CD, namely the init diff --git a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix new file mode 100644 index 000000000000..0ca57a4635f4 --- /dev/null +++ b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix @@ -0,0 +1,40 @@ +{ config, lib, pkgs, ... }: + +let + extlinux-conf-builder = + import ../../system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix { + inherit pkgs; + }; +in +{ + imports = [ + ../../profiles/minimal.nix + ../../profiles/installation-device.nix + ./sd-image.nix + ]; + + assertions = lib.singleton { + assertion = pkgs.stdenv.system == "armv7l-linux"; + message = "sd-image-armv7l-multiplatform.nix can be only built natively on ARMv7; " + + "it cannot be cross compiled"; + }; + + boot.loader.grub.enable = false; + boot.loader.generic-extlinux-compatible.enable = true; + + # FIXME: change this to linuxPackages_latest once v4.2 is out + boot.kernelPackages = pkgs.linuxPackages_testing; + boot.kernelParams = ["console=ttyS0,115200n8" "console=ttyAMA0,115200n8" "console=tty0"]; + + # FIXME: fix manual evaluation on ARM + services.nixosManual.enable = lib.mkOverride 0 false; + + # FIXME: this probably should be in installation-device.nix + users.extraUsers.root.initialHashedPassword = ""; + + sdImage = { + populateBootCommands = '' + ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./boot + ''; + }; +} diff --git a/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix new file mode 100644 index 000000000000..199a252ad2b5 --- /dev/null +++ b/nixos/modules/installer/cd-dvd/sd-image-raspberrypi.nix @@ -0,0 +1,46 @@ +{ config, lib, pkgs, ... }: + +let + extlinux-conf-builder = + import ../../system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix { + inherit pkgs; + }; +in +{ + imports = [ + ../../profiles/minimal.nix + ../../profiles/installation-device.nix + ./sd-image.nix + ]; + + assertions = lib.singleton { + assertion = pkgs.stdenv.system == "armv6l-linux"; + message = "sd-image-raspberrypi.nix can be only built natively on ARMv6; " + + "it cannot be cross compiled"; + }; + + # Needed by RPi firmware + nixpkgs.config.allowUnfree = true; + + boot.loader.grub.enable = false; + boot.loader.generic-extlinux-compatible.enable = true; + + boot.kernelPackages = pkgs.linuxPackages_rpi; + + # FIXME: fix manual evaluation on ARM + services.nixosManual.enable = lib.mkOverride 0 false; + + # FIXME: this probably should be in installation-device.nix + users.extraUsers.root.initialHashedPassword = ""; + + sdImage = { + populateBootCommands = '' + for f in bootcode.bin fixup.dat start.elf; do + cp ${pkgs.raspberrypifw}/share/raspberrypi/boot/$f boot/ + done + cp ${pkgs.ubootRaspberryPi}/u-boot.bin boot/u-boot-rpi.bin + echo 'kernel u-boot-rpi.bin' > boot/config.txt + ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./boot + ''; + }; +} diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix new file mode 100644 index 000000000000..12b4f3045614 --- /dev/null +++ b/nixos/modules/installer/cd-dvd/sd-image.nix @@ -0,0 +1,127 @@ +# This module creates a bootable SD card image containing the given NixOS +# configuration. The generated image is MBR partitioned, with a FAT /boot +# partition, and ext4 root partition. The generated image is sized to fit +# its contents, and a boot script automatically resizes the root partition +# to fit the device on the first boot. +# +# The derivation for the SD image will be placed in +# config.system.build.sdImage + +{ config, lib, pkgs, ... }: + +with lib; + +let + rootfsImage = import ../../../lib/make-ext4-fs.nix { + inherit pkgs; + inherit (config.sdImage) storePaths; + volumeLabel = "NIXOS_SD"; + }; +in +{ + options.sdImage = { + storePaths = mkOption { + type = with types; listOf package; + example = literalExample "[ pkgs.stdenv ]"; + description = '' + Derivations to be included in the Nix store in the generated SD image. + ''; + }; + + bootSize = mkOption { + type = types.int; + default = 128; + description = '' + Size of the /boot partition, in megabytes. + ''; + }; + + populateBootCommands = mkOption { + example = literalExample "'' cp \${pkgs.myBootLoader}/u-boot.bin boot/ ''"; + description = '' + Shell commands to populate the ./boot directory. + All files in that directory are copied to the + /boot partition on the SD image. + ''; + }; + }; + + config = { + fileSystems = { + "/boot" = { + device = "/dev/disk/by-label/NIXOS_BOOT"; + fsType = "vfat"; + }; + "/" = { + device = "/dev/disk/by-label/NIXOS_SD"; + fsType = "ext4"; + }; + }; + + sdImage.storePaths = [ config.system.build.toplevel ]; + + system.build.sdImage = pkgs.stdenv.mkDerivation { + name = "sd-image-${pkgs.stdenv.system}.img"; + + buildInputs = with pkgs; [ dosfstools e2fsprogs mtools libfaketime utillinux ]; + + buildCommand = '' + # Create the image file sized to fit /boot and /, plus 4M of slack + rootSizeBlocks=$(du -B 512 --apparent-size ${rootfsImage} | awk '{ print $1 }') + bootSizeBlocks=$((${toString config.sdImage.bootSize} * 1024 * 1024 / 512)) + imageSize=$((rootSizeBlocks * 512 + bootSizeBlocks * 512 + 4096 * 1024)) + truncate -s $imageSize $out + + # type=b is 'W95 FAT32', type=83 is 'Linux'. + sfdisk $out <<EOF + label: dos + label-id: 0x2178694e + + start=1M, size=$bootSizeBlocks, type=b, bootable + type=83 + EOF + + # Copy the rootfs into the SD image + eval $(partx $out -o START,SECTORS --nr 2 --pairs) + dd conv=notrunc if=${rootfsImage} of=$out seek=$START count=$SECTORS + + # Create a FAT32 /boot partition of suitable size into bootpart.img + eval $(partx $out -o START,SECTORS --nr 1 --pairs) + truncate -s $((SECTORS * 512)) bootpart.img + faketime "1970-01-01 00:00:00" mkfs.vfat -i 0x2178694e -n NIXOS_BOOT bootpart.img + + # Populate the files intended for /boot + mkdir boot + ${config.sdImage.populateBootCommands} + + # Copy the populated /boot into the SD image + (cd boot; mcopy -bpsvm -i ../bootpart.img ./* ::) + dd conv=notrunc if=bootpart.img of=$out seek=$START count=$SECTORS + ''; + }; + + boot.postBootCommands = '' + # On the first boot do some maintenance tasks + if [ -f /nix-path-registration ]; then + # Figure out device names for the boot device and root filesystem. + rootPart=$(readlink -f /dev/disk/by-label/NIXOS_SD) + bootDevice=$(lsblk -npo PKNAME $rootPart) + + # Resize the root partition and the filesystem to fit the disk + echo ",+," | sfdisk -N2 --no-reread $bootDevice + ${pkgs.parted}/bin/partprobe + ${pkgs.e2fsprogs}/bin/resize2fs $rootPart + + # Register the contents of the initial Nix store + ${config.nix.package}/bin/nix-store --load-db < /nix-path-registration + + # nixos-rebuild also requires a "system" profile and an /etc/NIXOS tag. + touch /etc/NIXOS + ${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system + + # Prevents this from running on later boots. + rm -f /nix-path-registration + fi + ''; + }; +} diff --git a/nixos/modules/installer/tools/auto-upgrade.nix b/nixos/modules/installer/tools/auto-upgrade.nix new file mode 100644 index 000000000000..b2676b05a02c --- /dev/null +++ b/nixos/modules/installer/tools/auto-upgrade.nix @@ -0,0 +1,81 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let cfg = config.system.autoUpgrade; in + +{ + + options = { + + system.autoUpgrade = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to periodically upgrade NixOS to the latest + version. If enabled, a systemd timer will run + <literal>nixos-rebuild switch --upgrade</literal> once a + day. + ''; + }; + + channel = mkOption { + type = types.nullOr types.str; + default = null; + example = https://nixos.org/channels/nixos-14.12-small; + description = '' + The URI of the NixOS channel to use for automatic + upgrades. By default, this is the channel set using + <command>nix-channel</command> (run <literal>nix-channel + --list</literal> to see the current value). + ''; + }; + + flags = mkOption { + type = types.listOf types.str; + default = []; + example = [ "-I" "stuff=/home/alice/nixos-stuff" "--option" "extra-binary-caches" "http://my-cache.example.org/" ]; + description = '' + Any additional flags passed to <command>nixos-rebuild</command>. + ''; + }; + + }; + + }; + + config = { + + system.autoUpgrade.flags = + [ "--no-build-output" ] + ++ (if cfg.channel == null + then [ "--upgrade" ] + else [ "-I" "nixpkgs=${cfg.channel}/nixexprs.tar.xz" ]); + + systemd.services.nixos-upgrade = { + description = "NixOS Upgrade"; + + restartIfChanged = false; + unitConfig.X-StopOnRemoval = false; + + serviceConfig.Type = "oneshot"; + + environment = config.nix.envVars // + { inherit (config.environment.sessionVariables) NIX_PATH SSL_CERT_FILE; + HOME = "/root"; + }; + + path = [ pkgs.gnutar pkgs.xz config.nix.package ]; + + script = '' + ${config.system.build.nixos-rebuild}/bin/nixos-rebuild test ${toString cfg.flags} + ''; + + startAt = mkIf cfg.enable "04:40"; + }; + + }; + +} diff --git a/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh b/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh index f9cbfffde704..4e981c074a57 100644 --- a/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh +++ b/nixos/modules/installer/tools/nixos-build-vms/nixos-build-vms.sh @@ -53,5 +53,5 @@ fi # Build a network of VMs -nix-build '<nixos/modules/installer/tools/nixos-build-vms/build-vms.nix>' \ +nix-build '<nixpkgs/nixos/modules/installer/tools/nixos-build-vms/build-vms.nix>' \ --argstr networkExpr $networkExpr $noOutLinkArg $showTraceArg diff --git a/nixos/modules/installer/tools/nixos-checkout.nix b/nixos/modules/installer/tools/nixos-checkout.nix index 9cdd8a74a188..07274e139f7d 100644 --- a/nixos/modules/installer/tools/nixos-checkout.nix +++ b/nixos/modules/installer/tools/nixos-checkout.nix @@ -27,7 +27,7 @@ let if [ -z "$(type -P git)" ]; then echo "installing Git..." - nix-env -iA nixos.pkgs.git || nix-env -i git + nix-env -iA nixos.git fi # Move any old nixpkgs directories out of the way. diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl index 187ea7635eb5..39ef4c51ba10 100644 --- a/nixos/modules/installer/tools/nixos-generate-config.pl +++ b/nixos/modules/installer/tools/nixos-generate-config.pl @@ -235,7 +235,7 @@ chomp $virt; # Check if we're a VirtualBox guest. If so, enable the guest # additions. if ($virt eq "oracle") { - push @attrs, "services.virtualboxGuest.enable = true;" + push @attrs, "virtualisation.virtualbox.guest.enable = true;" } @@ -544,6 +544,9 @@ $bootLoaderConfig # uid = 1000; # }; + # The NixOS release to be compatible with for stateful data such as databases. + system.stateVersion = "@nixosRelease@"; + } EOF } else { diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh index b1f4772d5705..f7fe6245d6d9 100644 --- a/nixos/modules/installer/tools/nixos-install.sh +++ b/nixos/modules/installer/tools/nixos-install.sh @@ -256,14 +256,8 @@ NIXOS_INSTALL_GRUB=1 chroot $mountPoint \ chroot $mountPoint /nix/var/nix/profiles/system/activate -# Some systems may not be prepared to use NixOS' paths. -export PATH=/run/current-system/sw/bin:/run/current-system/sw/sbin:$PATH -export NIX_PATH=/nix/var/nix/profiles/per-user/root/channels/nixos:nixpkgs=/etc/nixos/nixpkgs -export NIX_PATH=$NIX_PATH:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels - - # Ask the user to set a root password. -if [ "$(chroot $mountPoint nix-instantiate --eval '<nixpkgs/nixos>' -A config.users.mutableUsers)" = true ] && [ -t 0 ] ; then +if [ "$(chroot $mountPoint /run/current-system/sw/bin/sh -l -c "nix-instantiate --eval '<nixpkgs/nixos>' -A config.users.mutableUsers")" = true ] && [ -t 0 ] ; then echo "setting root password..." chroot $mountPoint /var/setuid-wrappers/passwd fi diff --git a/nixos/modules/installer/tools/nixos-rebuild.sh b/nixos/modules/installer/tools/nixos-rebuild.sh index ccafa30856c5..7d0e5913cfb1 100644 --- a/nixos/modules/installer/tools/nixos-rebuild.sh +++ b/nixos/modules/installer/tools/nixos-rebuild.sh @@ -157,9 +157,9 @@ if [ -n "$buildNix" ]; then if ! nix-build '<nixpkgs>' -A nix -o $tmpDir/nix "${extraBuildFlags[@]}" > /dev/null; then machine="$(uname -m)" if [ "$machine" = x86_64 ]; then - nixStorePath=/nix/store/ffig6yaggbh12dh9y5pnf1grf5lqyipz-nix-1.8 + nixStorePath=/nix/store/664kxr14kfgx4dl095crvmr7pbh9xlh5-nix-1.9 elif [[ "$machine" =~ i.86 ]]; then - nixStorePath=/nix/store/lglhfp4mimfa5wzjjf1kqz6f5wlsj2mn-nix-1.8 + nixStorePath=/nix/store/p7xdvz72xx3rhm121jclsbdmmcds7xh6-nix-1.9 else echo "$0: unsupported platform" exit 1 diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix index 99a74b6d59ed..04e4c1eb9459 100644 --- a/nixos/modules/installer/tools/tools.nix +++ b/nixos/modules/installer/tools/tools.nix @@ -40,6 +40,7 @@ let src = ./nixos-generate-config.pl; path = [ pkgs.btrfsProgs ]; perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl"; + inherit (config.system) nixosRelease; }; nixos-option = makeProg { @@ -56,7 +57,9 @@ let in { + config = { + environment.systemPackages = [ nixos-build-vms nixos-install @@ -69,5 +72,7 @@ in system.build = { inherit nixos-install nixos-generate-config nixos-option nixos-rebuild; }; + }; + } diff --git a/nixos/modules/misc/assertions.nix b/nixos/modules/misc/assertions.nix index c42de038e61f..3b50e60a0ffb 100644 --- a/nixos/modules/misc/assertions.nix +++ b/nixos/modules/misc/assertions.nix @@ -30,5 +30,5 @@ with lib; }; }; - # impl of assertions is in <nixos/modules/system/activation/top-level.nix> + # impl of assertions is in <nixpkgs/nixos/modules/system/activation/top-level.nix> } diff --git a/nixos/modules/misc/extra-arguments.nix b/nixos/modules/misc/extra-arguments.nix index ff2ff7cd4322..19002b17dace 100644 --- a/nixos/modules/misc/extra-arguments.nix +++ b/nixos/modules/misc/extra-arguments.nix @@ -2,8 +2,13 @@ { _module.args = { - pkgs_i686 = import ../../lib/nixpkgs.nix { + pkgs_i686 = import ../../.. { system = "i686-linux"; + # FIXME: we enable config.allowUnfree to make packages like + # nvidia-x11 available. This isn't a problem because if the user has + # ‘nixpkgs.config.allowUnfree = false’, then evaluation will fail on + # the 64-bit package anyway. However, it would be cleaner to respect + # nixpkgs.config here. config.allowUnfree = true; }; diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index fd75db1abe77..1e5393f26b54 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -226,6 +226,9 @@ gitit = 202; riemanntools = 203; subsonic = 204; + riak = 205; + shout = 206; + gateone = 207; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -430,6 +433,9 @@ gitit = 202; riemanntools = 203; subsonic = 204; + riak = 205; + #shout = 206; #unused + gateone = 207; # 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/locate.nix b/nixos/modules/misc/locate.nix index f3ed2aaba09d..4f9c8d4e5ba1 100644 --- a/nixos/modules/misc/locate.nix +++ b/nixos/modules/misc/locate.nix @@ -35,7 +35,7 @@ in { type = types.listOf types.str; default = [ ]; description = '' - Extra flags to append to <command>updatedb</command>. + Extra flags to pass to <command>updatedb</command>. ''; }; @@ -56,6 +56,14 @@ in { ''; }; + includeStore = mkOption { + type = types.bool; + default = false; + description = '' + Whether to include <filename>/nix/store</filename> in the locate database. + ''; + }; + }; }; @@ -63,7 +71,6 @@ in { ###### implementation config = { - systemd.services.update-locatedb = { description = "Update Locate Database"; path = [ pkgs.su ]; @@ -71,8 +78,9 @@ in { '' mkdir -m 0755 -p $(dirname ${toString cfg.output}) exec updatedb \ - --localuser=${cfg.localuser} \ - --output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags} + --localuser=${cfg.localuser} \ + ${optionalString (!cfg.includeStore) "--prunepaths='/nix/store'"} \ + --output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags} ''; serviceConfig.Nice = 19; serviceConfig.IOSchedulingClass = "idle"; diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix index fb5516c953c2..5eb38c510b48 100644 --- a/nixos/modules/misc/nixpkgs.nix +++ b/nixos/modules/misc/nixpkgs.nix @@ -72,7 +72,7 @@ in }; config = { - _module.args.pkgs = import ../../lib/nixpkgs.nix { + _module.args.pkgs = import ../../.. { system = config.nixpkgs.system; inherit (config.nixpkgs) config; diff --git a/nixos/modules/misc/version.nix b/nixos/modules/misc/version.nix index 5afdcf214f27..b4b0281fe587 100644 --- a/nixos/modules/misc/version.nix +++ b/nixos/modules/misc/version.nix @@ -6,12 +6,35 @@ with lib; options = { + system.stateVersion = mkOption { + type = types.str; + default = config.system.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). + ''; + }; + system.nixosVersion = mkOption { internal = true; type = types.str; description = "NixOS version."; }; + system.nixosRelease = mkOption { + readOnly = true; + type = types.str; + default = readFile "${toString pkgs.path}/.version"; + description = "NixOS release."; + }; + system.nixosVersionSuffix = mkOption { internal = true; type = types.str; @@ -25,7 +48,7 @@ with lib; }; system.nixosCodeName = mkOption { - internal = true; + readOnly = true; type = types.str; description = "NixOS release code name."; }; @@ -41,8 +64,7 @@ with lib; config = { - system.nixosVersion = - mkDefault (readFile "${toString pkgs.path}/.version" + config.system.nixosVersionSuffix); + system.nixosVersion = mkDefault (config.system.nixosRelease + config.system.nixosVersionSuffix); system.nixosVersionSuffix = let suffixFile = "${toString pkgs.path}/.version-suffix"; in @@ -53,7 +75,7 @@ with lib; mkDefault (if pathExists fn then readFile fn else "master"); # Note: code names must only increase in alphabetical order. - system.nixosCodeName = "Dingo"; + system.nixosCodeName = "Emu"; # Generate /etc/os-release. See # http://0pointer.de/public/systemd-man/os-release.html for the diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index f771bced5ef6..6734fa0b862b 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -41,6 +41,7 @@ ./hardware/video/bumblebee.nix ./hardware/video/nvidia.nix ./hardware/video/ati.nix + ./installer/tools/auto-upgrade.nix ./installer/tools/nixos-checkout.nix ./installer/tools/tools.nix ./misc/assertions.nix @@ -60,7 +61,6 @@ ./programs/command-not-found/command-not-found.nix ./programs/dconf.nix ./programs/environment.nix - ./programs/info.nix ./programs/ibus.nix ./programs/kbdlight.nix ./programs/light.nix @@ -72,9 +72,9 @@ ./programs/ssmtp.nix ./programs/uim.nix ./programs/venus.nix - ./programs/virtualbox-host.nix ./programs/wvdial.nix ./programs/freetds.nix + ./programs/xfs_quota.nix ./programs/zsh/zsh.nix ./rename.nix ./security/apparmor.nix @@ -131,6 +131,7 @@ ./services/databases/opentsdb.nix ./services/databases/postgresql.nix ./services/databases/redis.nix + ./services/databases/riak.nix ./services/databases/virtuoso.nix ./services/desktops/accountsservice.nix ./services/desktops/geoclue2.nix @@ -278,15 +279,18 @@ ./services/networking/dnsmasq.nix ./services/networking/docker-registry-server.nix ./services/networking/ejabberd.nix + ./services/networking/fan.nix ./services/networking/firefox/sync-server.nix ./services/networking/firewall.nix ./services/networking/flashpolicyd.nix ./services/networking/freenet.nix + ./services/networking/gateone.nix ./services/networking/git-daemon.nix ./services/networking/gnunet.nix ./services/networking/gogoclient.nix ./services/networking/gvpe.nix ./services/networking/haproxy.nix + ./services/networking/heyefi.nix ./services/networking/hostapd.nix ./services/networking/i2pd.nix ./services/networking/i2p.nix @@ -326,6 +330,8 @@ ./services/networking/searx.nix ./services/networking/seeks.nix ./services/networking/skydns.nix + ./services/networking/shout.nix + ./services/networking/softether.nix ./services/networking/spiped.nix ./services/networking/sslh.nix ./services/networking/ssh/lshd.nix @@ -387,6 +393,7 @@ ./services/web-servers/lighttpd/default.nix ./services/web-servers/lighttpd/gitweb.nix ./services/web-servers/nginx/default.nix + ./services/web-servers/nginx/reverse_proxy.nix ./services/web-servers/phpfpm.nix ./services/web-servers/shellinabox.nix ./services/web-servers/tomcat.nix @@ -483,6 +490,7 @@ ./virtualisation/openvswitch.nix ./virtualisation/parallels-guest.nix ./virtualisation/virtualbox-guest.nix + ./virtualisation/virtualbox-host.nix ./virtualisation/vmware-guest.nix ./virtualisation/xen-dom0.nix ] diff --git a/nixos/modules/profiles/clone-config.nix b/nixos/modules/profiles/clone-config.nix index f0d60bb6c428..77d86f8d7405 100644 --- a/nixos/modules/profiles/clone-config.nix +++ b/nixos/modules/profiles/clone-config.nix @@ -30,7 +30,7 @@ let relocatedModuleFiles = let relocateNixOS = path: - "<nixos" + removePrefix nixosPath (toString path) + ">"; + "<nixpkgs/nixos" + removePrefix nixosPath (toString path) + ">"; relocateOthers = null; in { nixos = map relocateNixOS partitionedModuleFiles.nixos; diff --git a/nixos/modules/profiles/minimal.nix b/nixos/modules/profiles/minimal.nix index 3b18ae129b93..c353da227aeb 100644 --- a/nixos/modules/profiles/minimal.nix +++ b/nixos/modules/profiles/minimal.nix @@ -7,6 +7,8 @@ with lib; { environment.noXlibs = mkDefault true; - i18n.supportedLocales = [ config.i18n.defaultLocale ]; + + # This isn't perfect, but let's expect the user specifies an UTF-8 defaultLocale + i18n.supportedLocales = [ (config.i18n.defaultLocale + "/UTF-8") ]; services.nixosManual.enable = mkDefault false; } diff --git a/nixos/modules/programs/command-not-found/command-not-found.nix b/nixos/modules/programs/command-not-found/command-not-found.nix index bead2dcdcf90..9524d91ea3bc 100644 --- a/nixos/modules/programs/command-not-found/command-not-found.nix +++ b/nixos/modules/programs/command-not-found/command-not-found.nix @@ -57,9 +57,9 @@ in if [ $? = 126 ]; then "$@" fi - else + else # Indicate than there was an error so ZSH falls back to its default handler - return 127 + return 127 fi } ''; diff --git a/nixos/modules/programs/command-not-found/command-not-found.pl b/nixos/modules/programs/command-not-found/command-not-found.pl index 916649059d37..b233d973a4ab 100644 --- a/nixos/modules/programs/command-not-found/command-not-found.pl +++ b/nixos/modules/programs/command-not-found/command-not-found.pl @@ -30,11 +30,11 @@ The program ‘$program’ is currently not installed. It is provided by the package ‘$package’, which I will now install for you. EOF ; - exit 126 if system("nix-env", "-i", $package) == 0; + exit 126 if system("nix-env", "-iA", "nixos.$package") == 0; } else { print STDERR <<EOF; The program ‘$program’ is currently not installed. You can install it by typing: - nix-env -i $package + nix-env -iA nixos.$package EOF } } else { @@ -42,7 +42,7 @@ EOF The program ‘$program’ is currently not installed. It is provided by several packages. You can install it by typing one of the following: EOF - print STDERR " nix-env -i $_->{package}\n" foreach @$res; + print STDERR " nix-env -iA nixos.$_->{package}\n" foreach @$res; } exit 127; diff --git a/nixos/modules/programs/environment.nix b/nixos/modules/programs/environment.nix index dce757ceb623..52f6cc221119 100644 --- a/nixos/modules/programs/environment.nix +++ b/nixos/modules/programs/environment.nix @@ -23,15 +23,6 @@ in EDITOR = mkDefault "nano"; }; - environment.sessionVariables = - { NIX_PATH = - [ "/nix/var/nix/profiles/per-user/root/channels/nixos" - "nixpkgs=/etc/nixos/nixpkgs" - "nixos-config=/etc/nixos/configuration.nix" - "/nix/var/nix/profiles/per-user/root/channels" - ]; - }; - environment.profiles = [ "$HOME/.nix-profile" "/nix/var/nix/profiles/default" diff --git a/nixos/modules/programs/info.nix b/nixos/modules/programs/info.nix deleted file mode 100644 index 253f9e877693..000000000000 --- a/nixos/modules/programs/info.nix +++ /dev/null @@ -1,38 +0,0 @@ -{config, pkgs, ...}: - -let - - texinfo = pkgs.texinfoInteractive; - - # Quick hack to make the `info' command work properly. `info' needs - # a "dir" file containing all the installed Info files, which we - # don't have (it would be impure to have a package installation - # update some global "dir" file). So this wrapper script around - # "info" builds a temporary "dir" file on the fly. This is a bit - # slow (on a cold cache) but not unacceptably so. - infoWrapper = pkgs.writeScriptBin "info" - '' - #! ${pkgs.stdenv.shell} - - dir=$(mktemp --tmpdir -d "info.dir.XXXXXX") - - if test -z "$dir"; then exit 1; fi - - trap 'rm -rf "$dir"' EXIT - - shopt -s nullglob - - for i in $(IFS=:; echo $INFOPATH); do - for j in $i/*.info; do - ${texinfo}/bin/install-info --quiet $j $dir/dir - done - done - - INFOPATH=$dir:$INFOPATH ${texinfo}/bin/info "$@" - ''; # */ - -in - -{ - environment.systemPackages = [ infoWrapper texinfo ]; -} diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix index 0d1ec500afc4..cf7ef455eb85 100644 --- a/nixos/modules/programs/ssh.nix +++ b/nixos/modules/programs/ssh.nix @@ -18,6 +18,14 @@ let exec ${askPassword} ''; + knownHosts = map (h: getAttr h cfg.knownHosts) (attrNames cfg.knownHosts); + + knownHostsText = flip (concatMapStringsSep "\n") knownHosts + (h: assert h.hostNames != []; + concatStringsSep "," h.hostNames + " " + + (if h.publicKey != null then h.publicKey else readFile h.publicKeyFile) + ); + in { ###### interface @@ -92,31 +100,93 @@ in ''; }; + knownHosts = mkOption { + default = {}; + type = types.loaOf (types.submodule ({ name, ... }: { + options = { + hostNames = mkOption { + type = types.listOf types.str; + default = []; + description = '' + A list of host names and/or IP numbers used for accessing + the host's ssh service. + ''; + }; + publicKey = mkOption { + default = null; + type = types.nullOr types.str; + example = "ecdsa-sha2-nistp521 AAAAE2VjZHN...UEPg=="; + description = '' + The public key data for the host. You can fetch a public key + from a running SSH server with the <command>ssh-keyscan</command> + command. The public key should not include any host names, only + the key type and the key itself. + ''; + }; + publicKeyFile = mkOption { + default = null; + type = types.nullOr types.path; + description = '' + The path to the public key file for the host. The public + key file is read at build time and saved in the Nix store. + You can fetch a public key file from a running SSH server + with the <command>ssh-keyscan</command> command. The content + of the file should follow the same format as described for + the <literal>publicKey</literal> option. + ''; + }; + }; + config = { + hostNames = mkDefault [ name ]; + }; + })); + description = '' + The set of system-wide known SSH hosts. + ''; + example = [ + { + hostNames = [ "myhost" "myhost.mydomain.com" "10.10.1.4" ]; + publicKeyFile = literalExample "./pubkeys/myhost_ssh_host_dsa_key.pub"; + } + { + hostNames = [ "myhost2" ]; + publicKeyFile = literalExample "./pubkeys/myhost2_ssh_host_dsa_key.pub"; + } + ]; + }; + }; }; config = { - assertions = singleton - { assertion = cfg.forwardX11 -> cfg.setXAuthLocation; - message = "cannot enable X11 forwarding without setting XAuth location"; - }; - - environment.etc = - [ { # SSH configuration. Slight duplication of the sshd_config - # generation in the sshd service. - source = pkgs.writeText "ssh_config" '' - AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"} - ${optionalString cfg.setXAuthLocation '' - XAuthLocation ${pkgs.xorg.xauth}/bin/xauth - ''} - ForwardX11 ${if cfg.forwardX11 then "yes" else "no"} - ${cfg.extraConfig} - ''; - target = "ssh/ssh_config"; + assertions = + [ { assertion = cfg.forwardX11 -> cfg.setXAuthLocation; + message = "cannot enable X11 forwarding without setting XAuth location"; } - ]; + ] ++ flip mapAttrsToList cfg.knownHosts (name: data: { + assertion = (data.publicKey == null && data.publicKeyFile != null) || + (data.publicKey != null && data.publicKeyFile == null); + message = "knownHost ${name} must contain either a publicKey or publicKeyFile"; + }); + + # SSH configuration. Slight duplication of the sshd_config + # generation in the sshd service. + environment.etc."ssh/ssh_config".text = + '' + AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"} + + ${optionalString cfg.setXAuthLocation '' + XAuthLocation ${pkgs.xorg.xauth}/bin/xauth + ''} + + ForwardX11 ${if cfg.forwardX11 then "yes" else "no"} + + ${cfg.extraConfig} + ''; + + environment.etc."ssh/ssh_known_hosts".text = knownHostsText; # FIXME: this should really be socket-activated for über-awesomeness. systemd.user.services.ssh-agent = diff --git a/nixos/modules/programs/xfs_quota.nix b/nixos/modules/programs/xfs_quota.nix new file mode 100644 index 000000000000..d30a85922cff --- /dev/null +++ b/nixos/modules/programs/xfs_quota.nix @@ -0,0 +1,110 @@ +# Configuration for the xfs_quota command + +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.programs.xfs_quota; + + limitOptions = opts: concatStringsSep " " [ + (optionalString (opts.sizeSoftLimit != null) "bsoft=${opts.sizeSoftLimit}") + (optionalString (opts.sizeHardLimit != null) "bhard=${opts.sizeHardLimit}") + ]; + +in + +{ + + ###### interface + + options = { + + programs.xfs_quota = { + projects = mkOption { + default = {}; + type = types.attrsOf (types.submodule { + options = { + id = mkOption { + type = types.int; + description = "Project ID."; + }; + + fileSystem = mkOption { + type = types.string; + description = "XFS filesystem hosting the xfs_quota project."; + default = "/"; + }; + + path = mkOption { + type = types.string; + description = "Project directory."; + }; + + sizeSoftLimit = mkOption { + type = types.nullOr types.string; + default = null; + example = "30g"; + description = "Soft limit of the project size"; + }; + + sizeHardLimit = mkOption { + type = types.nullOr types.string; + default = null; + example = "50g"; + description = "Hard limit of the project size."; + }; + }; + }); + + description = "Setup of xfs_quota projects. Make sure the filesystem is mounted with the pquota option."; + + example = { + "projname" = { + id = 50; + path = "/xfsprojects/projname"; + sizeHardLimit = "50g"; + }; + }; + }; + }; + + }; + + + ###### implementation + + config = mkIf (cfg.projects != {}) { + + environment.etc.projects.source = pkgs.writeText "etc-project" + (concatStringsSep "\n" (mapAttrsToList + (name: opts: "${toString opts.id}:${opts.path}") cfg.projects)); + + environment.etc.projid.source = pkgs.writeText "etc-projid" + (concatStringsSep "\n" (mapAttrsToList + (name: opts: "${name}:${toString opts.id}") cfg.projects)); + + systemd.services = mapAttrs' (name: opts: + nameValuePair "xfs_quota-${name}" { + description = "Setup xfs_quota for project ${name}"; + script = '' + ${pkgs.xfsprogs}/bin/xfs_quota -x -c 'project -s ${name}' ${opts.fileSystem} + ${pkgs.xfsprogs}/bin/xfs_quota -x -c 'limit -p ${limitOptions opts} ${name}' ${opts.fileSystem} + ''; + + wantedBy = [ "multi-user.target" ]; + after = [ ((replaceChars [ "/" ] [ "-" ] opts.fileSystem) + ".mount") ]; + + restartTriggers = [ config.environment.etc.projects.source ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + } + ) cfg.projects; + + }; + +} diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index a928f47f439e..cb378b024490 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -77,6 +77,8 @@ in zipModules ([] ++ obsolete [ "environment" "nix" ] [ "nix" "package" ] ++ obsolete [ "fonts" "enableFontConfig" ] [ "fonts" "fontconfig" "enable" ] ++ obsolete [ "fonts" "extraFonts" ] [ "fonts" "fonts" ] +++ alias [ "users" "extraUsers" ] [ "users" "users" ] +++ alias [ "users" "extraGroups" ] [ "users" "groups" ] ++ obsolete [ "security" "extraSetuidPrograms" ] [ "security" "setuidPrograms" ] ++ obsolete [ "networking" "enableWLAN" ] [ "networking" "wireless" "enable" ] @@ -98,6 +100,9 @@ in zipModules ([] ++ obsolete [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ] ++ obsolete [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ] +# smartd +++ obsolete [ "services" "smartd" "deviceOpts" ] [ "services" "smartd" "defaults" "monitored" ] + # OpenSSH ++ obsolete [ "services" "sshd" "ports" ] [ "services" "openssh" "ports" ] ++ alias [ "services" "sshd" "enable" ] [ "services" "openssh" "enable" ] @@ -107,9 +112,17 @@ in zipModules ([] ++ obsolete [ "services" "sshd" "permitRootLogin" ] [ "services" "openssh" "permitRootLogin" ] ++ obsolete [ "services" "xserver" "startSSHAgent" ] [ "services" "xserver" "startOpenSSHAgent" ] ++ obsolete [ "services" "xserver" "startOpenSSHAgent" ] [ "programs" "ssh" "startAgent" ] +++ alias [ "services" "openssh" "knownHosts" ] [ "programs" "ssh" "knownHosts" ] # VirtualBox -++ obsolete [ "services" "virtualbox" "enable" ] [ "services" "virtualboxGuest" "enable" ] +++ obsolete [ "services" "virtualbox" "enable" ] [ "virtualisation" "virtualbox" "guest" "enable" ] +++ obsolete [ "services" "virtualboxGuest" "enable" ] [ "virtualisation" "virtualbox" "guest" "enable" ] +++ obsolete [ "programs" "virtualbox" "enable" ] [ "virtualisation" "virtualbox" "host" "enable" ] +++ obsolete [ "programs" "virtualbox" "addNetworkInterface" ] [ "virtualisation" "virtualbox" "host" "addNetworkInterface" ] +++ obsolete [ "programs" "virtualbox" "enableHardening" ] [ "virtualisation" "virtualbox" "host" "enableHardening" ] +++ obsolete [ "services" "virtualboxHost" "enable" ] [ "virtualisation" "virtualbox" "host" "enable" ] +++ obsolete [ "services" "virtualboxHost" "addNetworkInterface" ] [ "virtualisation" "virtualbox" "host" "addNetworkInterface" ] +++ obsolete [ "services" "virtualboxHost" "enableHardening" ] [ "virtualisation" "virtualbox" "host" "enableHardening" ] # Tarsnap ++ obsolete [ "services" "tarsnap" "config" ] [ "services" "tarsnap" "archives" ] diff --git a/nixos/modules/security/apparmor.nix b/nixos/modules/security/apparmor.nix index 4fef62cbffd7..202639f98701 100644 --- a/nixos/modules/security/apparmor.nix +++ b/nixos/modules/security/apparmor.nix @@ -37,13 +37,5 @@ in ) cfg.profiles; }; }; - - security.pam.services.apparmor.text = '' - ## AppArmor changes hats according to `order`: first try user, then - ## group, and finally fall back to a hat called "DEFAULT" - ## - ## For now, enable debugging as this is an experimental feature. - session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug - ''; }; } diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 02520fb88cdd..474b93b4984d 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -192,6 +192,16 @@ let description = "Whether to log authentication failures in <filename>/var/log/faillog</filename>."; }; + enableAppArmor = mkOption { + default = false; + type = types.bool; + description = '' + Enable support for attaching AppArmor profiles at the + user/group level, e.g., as part of a role based access + control scheme. + ''; + }; + text = mkOption { type = types.nullOr types.lines; description = "Contents of the PAM service file."; @@ -251,9 +261,9 @@ let ${optionalString (!(config.security.pam.enableEcryptfs || cfg.pamMount)) "auth required pam_deny.so"} # Password management. + password requisite pam_unix.so nullok sha512 ${optionalString config.security.pam.enableEcryptfs "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} - password requisite pam_unix.so nullok sha512 ${optionalString cfg.pamMount "password optional ${pkgs.pam_mount}/lib/security/pam_mount.so"} ${optionalString config.users.ldap.enable @@ -294,6 +304,8 @@ let "session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}"} ${optionalString cfg.pamMount "session optional ${pkgs.pam_mount}/lib/security/pam_mount.so"} + ${optionalString (cfg.enableAppArmor && config.security.apparmor.enable) + "session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug"} ''; }; diff --git a/nixos/modules/services/cluster/kubernetes.nix b/nixos/modules/services/cluster/kubernetes.nix index d00c1aaa1055..ba09f04d502b 100644 --- a/nixos/modules/services/cluster/kubernetes.nix +++ b/nixos/modules/services/cluster/kubernetes.nix @@ -78,12 +78,6 @@ in { type = types.int; }; - readOnlyPort = mkOption { - description = "Kubernets apiserver read-only port."; - default = 7080; - type = types.int; - }; - securePort = mkOption { description = "Kubernetes apiserver secure port."; default = 6443; @@ -102,10 +96,16 @@ in { type = types.str; }; + clientCaFile = mkOption { + description = "Kubernetes apiserver CA file for client auth."; + default = ""; + type = types.str; + }; + tokenAuth = mkOption { description = '' Kubernetes apiserver token authentication file. See - <link xlink:href="https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/authentication.md"/> + <link xlink:href="http://kubernetes.io/v1.0/docs/admin/authentication.html"/> ''; default = {}; example = literalExample '' @@ -120,7 +120,7 @@ in { authorizationMode = mkOption { description = '' Kubernetes apiserver authorization mode (AlwaysAllow/AlwaysDeny/ABAC). See - <link xlink:href="https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/authorization.md"/> + <link xlink:href="http://kubernetes.io/v1.0/docs/admin/authorization.html"/> ''; default = "AlwaysAllow"; type = types.enum ["AlwaysAllow" "AlwaysDeny" "ABAC"]; @@ -129,7 +129,7 @@ in { authorizationPolicy = mkOption { description = '' Kubernetes apiserver authorization policy file. See - <link xlink:href="https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/authorization.md"/> + <link xlink:href="http://kubernetes.io/v1.0/docs/admin/authorization.html"/> ''; default = []; example = literalExample '' @@ -158,6 +158,38 @@ in { type = types.str; }; + runtimeConfig = mkOption { + description = '' + Api runtime configuration. See + <link xlink:href="http://kubernetes.io/v1.0/docs/admin/cluster-management.html"/> + ''; + default = ""; + example = "api/all=false,api/v1=true"; + type = types.str; + }; + + admissionControl = mkOption { + description = '' + Kubernetes admission control plugins to use. See + <link xlink:href="http://kubernetes.io/v1.0/docs/admin/admission-controllers.html"/> + ''; + default = ["AlwaysAdmit"]; + example = [ + "NamespaceLifecycle" "NamespaceExists" "LimitRanger" + "SecurityContextDeny" "ServiceAccount" "ResourceQuota" + ]; + type = types.listOf types.str; + }; + + serviceAccountKey = mkOption { + description = '' + Kubernetes apiserver PEM-encoded x509 RSA private or public key file, + used to verify ServiceAccount tokens. + ''; + default = null; + type = types.nullOr types.path; + }; + extraOpts = mkOption { description = "Kubernetes apiserver extra command line options."; default = ""; @@ -222,14 +254,26 @@ in { type = types.str; }; - machines = mkOption { - description = "Kubernetes controller list of machines to schedule to schedule onto"; - default = []; - type = types.listOf types.str; + serviceAccountPrivateKey = mkOption { + description = '' + Kubernetes controller manager PEM-encoded private RSA key file used to + sign service account tokens + ''; + default = null; + type = types.nullOr types.path; + }; + + rootCaFile = mkOption { + description = '' + Kubernetes controller manager certificate authority file included in + service account's token secret. + ''; + default = null; + type = types.nullOr types.path; }; extraOpts = mkOption { - description = "Kubernetes controller extra command line options."; + description = "Kubernetes controller manager extra command line options."; default = ""; type = types.str; }; @@ -260,6 +304,20 @@ in { type = types.int; }; + healthz = { + bind = mkOption { + description = "Kubernetes kubelet healthz listening address."; + default = "127.0.0.1"; + type = types.str; + }; + + port = mkOption { + description = "Kubernetes kubelet healthz port."; + default = 10248; + type = types.int; + }; + }; + hostname = mkOption { description = "Kubernetes kubelet hostname override"; default = config.networking.hostName; @@ -273,7 +331,10 @@ in { }; apiServers = mkOption { - description = "Kubernetes kubelet list of Kubernetes API servers for publishing events, and reading pods and services."; + description = '' + Kubernetes kubelet list of Kubernetes API servers for publishing events, + and reading pods and services. + ''; default = ["${cfg.apiserver.address}:${toString cfg.apiserver.port}"]; type = types.listOf types.str; }; @@ -374,7 +435,6 @@ in { --etcd-servers=${concatMapStringsSep "," (f: "http://${f}") cfg.etcdServers} \ --insecure-bind-address=${cfg.apiserver.address} \ --insecure-port=${toString cfg.apiserver.port} \ - --read-only-port=${toString cfg.apiserver.readOnlyPort} \ --bind-address=${cfg.apiserver.publicAddress} \ --allow-privileged=${if cfg.apiserver.allowPrivileged then "true" else "false"} \ ${optionalString (cfg.apiserver.tlsCertFile!="") @@ -383,22 +443,24 @@ in { "--tls-private-key-file=${cfg.apiserver.tlsPrivateKeyFile}"} \ ${optionalString (cfg.apiserver.tokenAuth!=[]) "--token-auth-file=${tokenAuthFile}"} \ + ${optionalString (cfg.apiserver.clientCaFile!="") + "--client-ca-file=${cfg.apiserver.clientCaFile}"} \ --authorization-mode=${cfg.apiserver.authorizationMode} \ ${optionalString (cfg.apiserver.authorizationMode == "ABAC") "--authorization-policy-file=${authorizationPolicyFile}"} \ --secure-port=${toString cfg.apiserver.securePort} \ --service-cluster-ip-range=${cfg.apiserver.portalNet} \ + ${optionalString (cfg.apiserver.runtimeConfig!="") + "--runtime-config=${cfg.apiserver.runtimeConfig}"} \ + --admission_control=${concatStringsSep "," cfg.apiserver.admissionControl} \ + ${optionalString (cfg.apiserver.serviceAccountKey!=null) + "--service-account-key-file=${cfg.apiserver.serviceAccountKey}"} \ --logtostderr=true \ ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \ ${cfg.apiserver.extraOpts} ''; User = "kubernetes"; }; - postStart = '' - until ${pkgs.curl}/bin/curl -s -o /dev/null 'http://${cfg.apiserver.address}:${toString cfg.apiserver.port}/'; do - sleep 1; - done - ''; }; }) @@ -431,7 +493,10 @@ in { --address=${cfg.controllerManager.address} \ --port=${toString cfg.controllerManager.port} \ --master=${cfg.controllerManager.master} \ - --machines=${concatStringsSep "," cfg.controllerManager.machines} \ + ${optionalString (cfg.controllerManager.serviceAccountPrivateKey!=null) + "--service-account-private-key-file=${cfg.controllerManager.serviceAccountPrivateKey}"} \ + ${optionalString (cfg.controllerManager.rootCaFile!=null) + "--root-ca-file=${cfg.controllerManager.rootCaFile}"} \ --logtostderr=true \ ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \ ${cfg.controllerManager.extraOpts} @@ -454,6 +519,8 @@ in { --register-node=${if cfg.kubelet.registerNode then "true" else "false"} \ --address=${cfg.kubelet.address} \ --port=${toString cfg.kubelet.port} \ + --healthz-bind-address=${cfg.kubelet.healthz.bind} \ + --healthz-port=${toString cfg.kubelet.healthz.port} \ --hostname-override=${cfg.kubelet.hostname} \ --allow-privileged=${if cfg.kubelet.allowPrivileged then "true" else "false"} \ --root-dir=${cfg.dataDir} \ @@ -483,6 +550,8 @@ in { ${optionalString cfg.verbose "--v=6 --log-flush-frequency=1s"} \ ${cfg.proxy.extraOpts} ''; + Restart = "always"; # Retry connection + RestartSec = "5s"; }; }; }) @@ -504,9 +573,6 @@ in { User = "kubernetes"; }; }; - - services.skydns.enable = mkDefault true; - services.skydns.domain = mkDefault cfg.kubelet.clusterDomain; }) (mkIf (any (el: el == "master") cfg.roles) { @@ -524,6 +590,9 @@ in { (mkIf (any (el: el == "node" || el == "master") cfg.roles) { services.etcd.enable = mkDefault true; + + services.skydns.enable = mkDefault true; + services.skydns.domain = mkDefault cfg.kubelet.clusterDomain; }) (mkIf ( @@ -538,8 +607,10 @@ in { serviceConfig.Type = "oneshot"; script = '' mkdir -p /var/run/kubernetes - chown kubernetes /var/run/kubernetes - ln -fs ${pkgs.writeText "kubernetes-dockercfg" cfg.dockerCfg} /var/run/kubernetes/.dockercfg + chown kubernetes /var/lib/kubernetes + + rm ${cfg.dataDir}/.dockercfg || true + ln -fs ${pkgs.writeText "kubernetes-dockercfg" cfg.dockerCfg} ${cfg.dataDir}/.dockercfg ''; }; diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix index 97927055ce37..bae088c6610e 100644 --- a/nixos/modules/services/databases/postgresql.nix +++ b/nixos/modules/services/databases/postgresql.nix @@ -154,6 +154,12 @@ in config = mkIf config.services.postgresql.enable { + services.postgresql.package = + # Note: when changing the default, make it conditional on + # ‘system.stateVersion’ to maintain compatibility with existing + # systems! + mkDefault pkgs.postgresql94; + services.postgresql.authentication = mkAfter '' # Generated file; do not edit! @@ -207,6 +213,7 @@ in serviceConfig = { ExecStart = "@${postgresql}/bin/postgres postgres ${toString flags}"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; User = "postgres"; Group = "postgres"; PermissionsStartOnly = true; diff --git a/nixos/modules/services/databases/riak.nix b/nixos/modules/services/databases/riak.nix new file mode 100644 index 000000000000..bee768fa42ae --- /dev/null +++ b/nixos/modules/services/databases/riak.nix @@ -0,0 +1,148 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.riak; + +in + +{ + + ###### interface + + options = { + + services.riak = { + + enable = mkEnableOption "riak"; + + package = mkOption { + type = types.package; + example = literalExample "pkgs.riak2"; + description = '' + Riak package to use. + ''; + }; + + nodeName = mkOption { + type = types.string; + default = "riak@127.0.0.1"; + description = '' + Name of the Erlang node. + ''; + }; + + distributedCookie = mkOption { + type = types.string; + default = "riak"; + description = '' + Cookie for distributed node communication. All nodes in the + same cluster should use the same cookie or they will not be able to + communicate. + ''; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/db/riak"; + description = '' + Data directory for Riak. + ''; + }; + + logDir = mkOption { + type = types.path; + default = "/var/log/riak"; + description = '' + Log directory for Riak. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Additional text to be appended to <filename>riak.conf</filename>. + ''; + }; + + }; + + }; + + ###### implementation + + config = mkIf cfg.enable { + + environment.systemPackages = [ cfg.package ]; + environment.etc."riak/riak.conf".text = '' + nodename = ${cfg.nodeName} + distributed_cookie = ${cfg.distributedCookie} + + platform_log_dir = ${cfg.logDir} + platform_etc_dir = /etc/riak + platform_data_dir = ${cfg.dataDir} + + ${cfg.extraConfig} + ''; + + users.extraUsers.riak = { + name = "riak"; + uid = config.ids.uids.riak; + group = "riak"; + description = "Riak server user"; + }; + + users.extraGroups.riak.gid = config.ids.gids.riak; + + systemd.services.riak = { + description = "Riak Server"; + + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + path = [ + pkgs.utillinux # for `logger` + pkgs.bash + ]; + + environment.RIAK_DATA_DIR = "${cfg.dataDir}"; + environment.RIAK_LOG_DIR = "${cfg.logDir}"; + environment.RIAK_ETC_DIR = "/etc/riak"; + + preStart = '' + if ! test -e ${cfg.logDir}; then + mkdir -m 0755 -p ${cfg.logDir} + chown -R riak ${cfg.logDir} + fi + + if ! test -e ${cfg.dataDir}; then + mkdir -m 0700 -p ${cfg.dataDir} + chown -R riak ${cfg.dataDir} + fi + ''; + + serviceConfig = { + ExecStart = "${cfg.package}/bin/riak console"; + ExecStop = "${cfg.package}/bin/riak stop"; + StandardInput = "tty"; + User = "riak"; + Group = "riak"; + PermissionsStartOnly = true; + # Give Riak a decent amount of time to clean up. + TimeoutStopSec = 120; + LimitNOFILE = 65536; + }; + + unitConfig.RequiresMountsFor = [ + "${cfg.dataDir}" + "${cfg.logDir}" + "/etc/riak" + ]; + }; + + }; + +} diff --git a/nixos/modules/services/hardware/freefall.nix b/nixos/modules/services/hardware/freefall.nix index 6e6960bac491..7867956c1ab0 100644 --- a/nixos/modules/services/hardware/freefall.nix +++ b/nixos/modules/services/hardware/freefall.nix @@ -39,11 +39,14 @@ with lib; mkService = dev: assert dev != ""; let dev' = utils.escapeSystemdPath dev; in - nameValuePair "freefall-${dev'}" - { description = "Free-fall protection for ${dev}"; + nameValuePair "freefall-${dev'}" { + description = "Free-fall protection for ${dev}"; after = [ "${dev'}.device" ]; wantedBy = [ "${dev'}.device" ]; path = [ pkgs.freefall ]; + unitConfig = { + DefaultDependencies = false; + }; serviceConfig = { ExecStart = "${pkgs.freefall}/bin/freefall ${dev}"; Restart = "on-failure"; diff --git a/nixos/modules/services/hardware/tcsd.nix b/nixos/modules/services/hardware/tcsd.nix index 220b154bd97a..d957b5063d38 100644 --- a/nixos/modules/services/hardware/tcsd.nix +++ b/nixos/modules/services/hardware/tcsd.nix @@ -17,8 +17,8 @@ let # what is available directly from the PCR registers. firmware_log_file = /sys/kernel/security/tpm0/binary_bios_measurements kernel_log_file = /sys/kernel/security/ima/binary_runtime_measurements - #firmware_pcrs = 0,1,2,3,4,5,6,7 - #kernel_pcrs = 10,11 + firmware_pcrs = ${cfg.firmwarePCRs} + kernel_pcrs = ${cfg.kernelPCRs} platform_cred = ${cfg.platformCred} conformance_cred = ${cfg.conformanceCred} endorsement_cred = ${cfg.endorsementCred} @@ -60,20 +60,32 @@ in }; stateDir = mkOption { - default = "/var/lib/tpm"; + default = "/var/lib/tpm"; type = types.path; - description = '' + description = '' The location of the system persistent storage file. The system persistent storage file holds keys and data across restarts of the TCSD and system reboots. - ''; + ''; + }; + + firmwarePCRs = mkOption { + default = "0,1,2,3,4,5,6,7"; + type = types.string; + description = "PCR indices used in the TPM for firmware measurements."; + }; + + kernelPCRs = mkOption { + default = "8,9,10,11,12"; + type = types.string; + description = "PCR indices used in the TPM for kernel measurements."; }; platformCred = mkOption { default = "${cfg.stateDir}/platform.cert"; type = types.path; description = '' - Path to the platform credential for your TPM. Your TPM + Path to the platform credential for your TPM. Your TPM manufacturer may have provided you with a set of credentials (certificates) that should be used when creating identities using your TPM. When a user of your TPM makes an identity, diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix index fc89de777e8e..513eb27b4069 100644 --- a/nixos/modules/services/hardware/udev.nix +++ b/nixos/modules/services/hardware/udev.nix @@ -171,25 +171,23 @@ in }; hardware.firmware = mkOption { - type = types.listOf types.path; + type = types.listOf types.package; default = []; description = '' - List of directories containing firmware files. Such files + List of packages containing firmware files. Such files will be loaded automatically if the kernel asks for them (i.e., when it has detected specific hardware that requires - firmware to function). If more than one path contains a - firmware file with the same name, the first path in the list - takes precedence. Note that you must rebuild your system if - you add files to any of these directories. For quick testing, + firmware to function). If multiple packages contain firmware + files with the same name, the first package in the list takes + precedence. Note that you must rebuild your system if you add + files to any of these directories. For quick testing, put firmware files in <filename>/root/test-firmware</filename> - and add that directory to the list. Note that you can also - add firmware packages to this list as these are directories in - the nix store. + and add that directory to the list. ''; apply = list: pkgs.buildEnv { name = "firmware"; paths = list; - pathsToLink = [ "/" ]; + pathsToLink = [ "/lib/firmware" ]; ignoreCollisions = true; }; }; @@ -236,7 +234,7 @@ in (isYes "NET") ]; - boot.extraModprobeConfig = "options firmware_class path=${config.hardware.firmware}"; + boot.extraModprobeConfig = "options firmware_class path=${config.hardware.firmware}/lib/firmware"; system.activationScripts.udevd = '' @@ -254,7 +252,7 @@ in # Allow the kernel to find our firmware. if [ -e /sys/module/firmware_class/parameters/path ]; then - echo -n "${config.hardware.firmware}" > /sys/module/firmware_class/parameters/path + echo -n "${config.hardware.firmware}/lib/firmware" > /sys/module/firmware_class/parameters/path fi ''; diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix index 50ff1b38db12..fca0d2a7f616 100644 --- a/nixos/modules/services/mail/dovecot.nix +++ b/nixos/modules/services/mail/dovecot.nix @@ -10,7 +10,7 @@ let '' base_dir = /var/run/dovecot2/ - protocols = ${optionalString cfg.enableImap "imap"} ${optionalString cfg.enablePop3 "pop3"} + protocols = ${optionalString cfg.enableImap "imap"} ${optionalString cfg.enablePop3 "pop3"} ${optionalString cfg.enableLmtp "lmtp"} '' + (if cfg.sslServerCert!="" then '' @@ -70,6 +70,11 @@ in description = "Start the IMAP listener (when Dovecot is enabled)."; }; + enableLmtp = mkOption { + default = false; + description = "Start the LMTP listener (when Dovecot is enabled)."; + }; + user = mkOption { default = "dovecot2"; description = "Dovecot user name."; diff --git a/nixos/modules/services/mail/mlmmj.nix b/nixos/modules/services/mail/mlmmj.nix index db3a266d011f..5843a6745f58 100644 --- a/nixos/modules/services/mail/mlmmj.nix +++ b/nixos/modules/services/mail/mlmmj.nix @@ -11,7 +11,7 @@ let listCtl = domain: list: "${listDir domain list}/control"; transport = domain: list: "${domain}--${list}@local.list.mlmmj mlmmj:${domain}/${list}"; virtual = domain: list: "${list}@${domain} ${domain}--${list}@local.list.mlmmj"; - alias = domain: list: "${list}: \"|${pkgs.mlmmj}/mlmmj-receive -L ${listDir domain list}/\""; + alias = domain: list: "${list}: \"|${pkgs.mlmmj}/bin/mlmmj-receive -L ${listDir domain list}/\""; subjectPrefix = list: "[${list}]"; listAddress = domain: list: "${list}@${domain}"; customHeaders = list: domain: [ "List-Id: ${list}" "Reply-To: ${list}@${domain}" ]; diff --git a/nixos/modules/services/misc/confd.nix b/nixos/modules/services/misc/confd.nix index 98738b6497bf..50532a8a16fb 100644 --- a/nixos/modules/services/misc/confd.nix +++ b/nixos/modules/services/misc/confd.nix @@ -63,7 +63,7 @@ in { package = mkOption { description = "Confd package to use."; - default = pkgs.goPackages.confd; + default = pkgs.confd; type = types.package; }; }; diff --git a/nixos/modules/services/misc/etcd.nix b/nixos/modules/services/misc/etcd.nix index 26d2753879d0..e1839b936f01 100644 --- a/nixos/modules/services/misc/etcd.nix +++ b/nixos/modules/services/misc/etcd.nix @@ -122,14 +122,6 @@ in { mkdir -m 0700 -p ${cfg.dataDir} if [ "$(id -u)" = 0 ]; then chown etcd ${cfg.dataDir}; fi ''; - postStart = '' - until ${pkgs.etcdctl}/bin/etcdctl set /nixos/state 'up'; do - sleep 1; - done - until ${pkgs.etcdctl}/bin/etcdctl get /nixos/state | grep up; do - sleep 1; - done - ''; }; environment.systemPackages = [ pkgs.etcdctl ]; diff --git a/nixos/modules/services/misc/gitit.nix b/nixos/modules/services/misc/gitit.nix index 56e735d7356b..10a706fbd71d 100644 --- a/nixos/modules/services/misc/gitit.nix +++ b/nixos/modules/services/misc/gitit.nix @@ -8,6 +8,8 @@ let homeDir = "/var/lib/gitit"; + toYesNo = b: if b then "yes" else "no"; + gititShared = with cfg.haskellPackages; gitit + "/share/" + pkgs.stdenv.system + "-" + ghc.name + "/" + gitit.pname + "-" + gitit.version; gititWithPkgs = hsPkgs: extras: hsPkgs.ghcWithPackages (self: with self; [ gitit ] ++ (extras self)); @@ -17,9 +19,6 @@ let in writeScript "gitit" '' #!${stdenv.shell} cd $HOME - export PATH="${makeSearchPath "bin" ( - [ git curl ] ++ (if cfg.pdfExport == "yes" then [texLiveFull] else []) - )}:$PATH"; export NIX_GHC="${env}/bin/ghc" export NIX_GHCPKG="${env}/bin/ghc-pkg" export NIX_GHC_DOCDIR="${env}/share/doc/ghc/html" @@ -27,11 +26,7 @@ let ${env}/bin/gitit -f ${configFile} ''; - gititOptions = let - - yesNo = types.enum [ "yes" "no" ]; - - in { + gititOptions = { enable = mkOption { type = types.bool; @@ -40,7 +35,6 @@ let }; haskellPackages = mkOption { - default = pkgs.haskellPackages; defaultText = "pkgs.haskellPackages"; example = literalExample "pkgs.haskell.packages.ghc784"; description = "haskellPackages used to build gitit and plugins."; @@ -143,7 +137,6 @@ let staticDir = mkOption { type = types.path; - default = gititShared + "/data/static"; description = '' Specifies the path of the static directory (containing javascript, css, and images). If it does not exist, gitit will create it and @@ -204,8 +197,8 @@ let }; showLhsBirdTracks = mkOption { - type = yesNo; - default = "no"; + type = types.bool; + default = false; description = '' Specifies whether to show Haskell code blocks in "bird style", with "> " at the beginning of each line. @@ -214,7 +207,6 @@ let templatesDir = mkOption { type = types.path; - default = gititShared + "/data/templates"; description = '' Specifies the path of the directory containing page templates. If it does not exist, gitit will create it with default templates. Users @@ -286,8 +278,8 @@ let }; tableOfContents = mkOption { - type = yesNo; - default = "yes"; + type = types.bool; + default = true; description = '' Specifies whether to print a tables of contents (with links to sections) on each wiki page. @@ -295,23 +287,18 @@ let }; plugins = mkOption { - type = types.path; - default = gititShared + "/plugins/Dot.hs"; + type = with types; listOf str; description = '' - Specifies a list of plugins to load. Plugins may be specified either - by their path or by their module name. If the plugin name starts + Specifies a list of plugins to load. Plugins may be specified either + by their path or by their module name. If the plugin name starts with Gitit.Plugin., gitit will assume that the plugin is an installed module and will not try to find a source file. - Examples: - plugins: plugins/DotPlugin.hs, CapitalizeEmphasisPlugin.hs - plugins: plugins/DotPlugin - plugins: Gitit.Plugin.InterwikiLinks ''; }; useCache = mkOption { - type = yesNo; - default = "no"; + type = types.bool; + default = false; description = '' Specifies whether to cache rendered pages. Note that if use-feed is selected, feeds will be cached regardless of the value of use-cache. @@ -342,14 +329,14 @@ let }; debugMode = mkOption { - type = yesNo; - default = "no"; + type = types.bool; + default = false; description = "Causes debug information to be logged while gitit is running."; }; compressResponses = mkOption { - type = yesNo; - default = "yes"; + type = types.bool; + default = true; description = "Specifies whether HTTP responses should be compressed."; }; @@ -361,16 +348,18 @@ let line of the file should contain two fields, separated by whitespace. The first field is the mime type, the second is a file extension. For example: - video/x-ms-wmx wmx +<programlisting> +video/x-ms-wmx wmx +</programlisting> If the file is not found, some simple defaults will be used. ''; }; useReCaptcha = mkOption { - type = yesNo; - default = "no"; + type = types.bool; + default = false; description = '' - If "yes", causes gitit to use the reCAPTCHA service + If true, causes gitit to use the reCAPTCHA service (http://recaptcha.net) to prevent bots from creating accounts. ''; }; @@ -475,8 +464,8 @@ let }; useFeed = mkOption { - type = yesNo; - default = "no"; + type = types.bool; + default = false; description = '' Specifies whether an ATOM feed should be enabled (for the site and for individual pages). @@ -488,19 +477,19 @@ let default = null; description = '' The base URL of the wiki, to be used in constructing feed IDs and RPX - token_urls. Set this if use-feed is 'yes' or authentication-method + token_urls. Set this if useFeed is false or authentication-method is 'rpx'. ''; }; absoluteUrls = mkOption { - type = yesNo; - default = "no"; + type = types.bool; + default = false; description = '' Make wikilinks absolute with respect to the base-url. So, for example, in a wiki served at the base URL '/wiki', on a page Sub/Page, the wikilink '[Cactus]()' will produce a link to - '/wiki/Cactus' if absolute-urls is 'yes', and a relative link to + '/wiki/Cactus' if absoluteUrls is true, and a relative link to 'Cactus' (referring to '/wiki/Sub/Cactus') if absolute-urls is 'no'. ''; }; @@ -518,10 +507,10 @@ let }; pdfExport = mkOption { - type = yesNo; - default = "no"; + type = types.bool; + default = false; description = '' - If yes, PDF will appear in export options. PDF will be created using + If true, PDF will appear in export options. PDF will be created using pdflatex, which must be installed and in the path. Note that PDF exports create significant additional server load. ''; @@ -541,10 +530,10 @@ let }; xssSanitize = mkOption { - type = yesNo; - default = "yes"; + type = types.bool; + default = true; description = '' - If yes, all HTML (including that produced by pandoc) is filtered + If true, all HTML (including that produced by pandoc) is filtered through xss-sanitize. Set to no only if you trust all of your users. ''; }; @@ -564,7 +553,7 @@ let default-page-type: ${cfg.defaultPageType} math: ${cfg.math} mathjax-script: ${cfg.mathJaxScript} - show-lhs-bird-tracks: ${cfg.showLhsBirdTracks} + show-lhs-bird-tracks: ${toYesNo cfg.showLhsBirdTracks} templates-dir: ${cfg.templatesDir} log-file: ${cfg.logFile} log-level: ${cfg.logLevel} @@ -572,16 +561,16 @@ let no-delete: ${cfg.noDelete} no-edit: ${cfg.noEdit} default-summary: ${cfg.defaultSummary} - table-of-contents: ${cfg.tableOfContents} - plugins: ${cfg.plugins} - use-cache: ${cfg.useCache} + table-of-contents: ${toYesNo cfg.tableOfContents} + plugins: ${concatStringsSep "," cfg.plugins} + use-cache: ${toYesNo cfg.useCache} cache-dir: ${cfg.cacheDir} max-upload-size: ${cfg.maxUploadSize} max-page-size: ${cfg.maxPageSize} - debug-mode: ${cfg.debugMode} - compress-responses: ${cfg.compressResponses} + debug-mode: ${toYesNo cfg.debugMode} + compress-responses: ${toYesNo cfg.compressResponses} mime-types-file: ${cfg.mimeTypesFile} - use-recaptcha: ${cfg.useReCaptcha} + use-recaptcha: ${toYesNo cfg.useReCaptcha} recaptcha-private-key: ${toString cfg.reCaptchaPrivateKey} recaptcha-public-key: ${toString cfg.reCaptchaPublicKey} access-question: ${cfg.accessQuestion} @@ -590,14 +579,14 @@ let rpx-key: ${toString cfg.rpxKey} mail-command: ${cfg.mailCommand} reset-password-message: ${cfg.resetPasswordMessage} - use-feed: ${cfg.useFeed} + use-feed: ${toYesNo cfg.useFeed} base-url: ${toString cfg.baseUrl} - absolute-urls: ${cfg.absoluteUrls} + absolute-urls: ${toYesNo cfg.absoluteUrls} feed-days: ${toString cfg.feedDays} feed-refresh-time: ${toString cfg.feedRefreshTime} - pdf-export: ${cfg.pdfExport} + pdf-export: ${toYesNo cfg.pdfExport} pandoc-user-data: ${toString cfg.pandocUserData} - xss-sanitize: ${cfg.xssSanitize} + xss-sanitize: ${toYesNo cfg.xssSanitize} ''; in @@ -608,6 +597,13 @@ in config = mkIf cfg.enable { + services.gitit = { + haskellPackages = mkDefault pkgs.haskellPackages; + staticDir = gititShared + "/data/static"; + templatesDir = gititShared + "/data/templates"; + plugins = [ ]; + }; + users.extraUsers.gitit = { group = config.users.extraGroups.gitit.name; description = "Gitit user"; @@ -625,8 +621,16 @@ in description = "Git and Pandoc Powered Wiki"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - - preStart = with cfg; '' + path = with pkgs; [ curl ] + ++ optional cfg.pdfExport texLiveFull + ++ optional (cfg.repositoryType == "darcs") darcs + ++ optional (cfg.repositoryType == "mercurial") mercurial + ++ optional (cfg.repositoryType == "git") git; + + preStart = let + gm = "gitit@${config.networking.hostName}"; + in + with cfg; '' chown ${uid}:${gid} -R ${homeDir} for dir in ${repositoryPath} ${staticDir} ${templatesDir} ${cacheDir} do @@ -638,14 +642,35 @@ in fi done cd ${repositoryPath} - if [ ! -d .git ] - then - ${pkgs.git}/bin/git init - ${pkgs.git}/bin/git config user.email "gitit@${config.networking.hostName}" - ${pkgs.git}/bin/git config user.name "gitit" - chown ${uid}:${gid} -R {repositoryPath} - fi - cd - + ${ + if repositoryType == "darcs" then + '' + if [ ! -d _darcs ] + then + ${pkgs.darcs}/bin/darcs initialize + echo "${gm}" > _darcs/prefs/email + '' + else if repositoryType == "mercurial" then + '' + if [ ! -d .hg ] + then + ${pkgs.mercurial}/bin/hg init + cat >> .hg/hgrc <<NAMED +[ui] +username = gitit ${gm} +NAMED + '' + else + '' + if [ ! -d .git ] + then + ${pkgs.git}/bin/git init + ${pkgs.git}/bin/git config user.email "${gm}" + ${pkgs.git}/bin/git config user.name "gitit" + ''} + chown ${uid}:${gid} -R ${repositoryPath} + fi + cd - ''; serviceConfig = { diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix index b5a8a7df9fca..4aed91c34978 100644 --- a/nixos/modules/services/misc/nix-daemon.nix +++ b/nixos/modules/services/misc/nix-daemon.nix @@ -78,8 +78,8 @@ in description = '' This option defines the maximum number of jobs that Nix will try to build in parallel. The default is 1. You should generally - set it to the number of CPUs in your system (e.g., 2 on an Athlon - 64 X2). + set it to the total number of logical cores in your system (e.g., 16 + for two CPUs with 4 cores each and hyper-threading). ''; }; @@ -254,7 +254,7 @@ in requireSignedBinaryCaches = mkOption { type = types.bool; - default = false; + default = true; description = '' If enabled, Nix will only download binaries from binary caches if they are cryptographically signed with any of the @@ -309,6 +309,20 @@ in ''; }; + nixPath = mkOption { + type = types.listOf types.str; + default = + [ "/nix/var/nix/profiles/per-user/root/channels/nixos" + "nixos-config=/etc/nixos/configuration.nix" + "/nix/var/nix/profiles/per-user/root/channels" + ]; + description = '' + The default Nix expression search path, used by the Nix + evaluator to look up paths enclosed in angle brackets + (e.g. <literal><nixpkgs></literal>). + ''; + }; + }; }; @@ -378,7 +392,9 @@ in }; # Set up the environment variables for running Nix. - environment.sessionVariables = cfg.envVars; + environment.sessionVariables = cfg.envVars // + { NIX_PATH = concatStringsSep ":" cfg.nixPath; + }; environment.extraInit = '' diff --git a/nixos/modules/services/misc/nix-gc.nix b/nixos/modules/services/misc/nix-gc.nix index 6a7a7f4cee72..981299352575 100644 --- a/nixos/modules/services/misc/nix-gc.nix +++ b/nixos/modules/services/misc/nix-gc.nix @@ -52,7 +52,7 @@ in systemd.services.nix-gc = { description = "Nix Garbage Collector"; - script = "exec ${config.nix.package}/bin/nix-collect-garbage ${cfg.options}"; + script = "exec ${config.nix.package}/bin/nix-store --gc ${cfg.options}"; startAt = optionalString cfg.automatic cfg.dates; }; diff --git a/nixos/modules/services/misc/rogue.nix b/nixos/modules/services/misc/rogue.nix index ed8da8a518ff..aae02e384c97 100644 --- a/nixos/modules/services/misc/rogue.nix +++ b/nixos/modules/services/misc/rogue.nix @@ -52,6 +52,7 @@ in TTYPath = "/dev/${cfg.tty}"; TTYReset = true; TTYVTDisallocate = true; + WorkingDirectory = "/tmp"; Restart = "always"; }; }; diff --git a/nixos/modules/services/monitoring/dd-agent.nix b/nixos/modules/services/monitoring/dd-agent.nix index 3e90393a662d..8c847af3bfc0 100644 --- a/nixos/modules/services/monitoring/dd-agent.nix +++ b/nixos/modules/services/monitoring/dd-agent.nix @@ -51,12 +51,37 @@ let # ganglia_port: 8651 ''; + diskConfig = pkgs.writeText "disk.yaml" '' + init_config: + + instances: + - use_mount: no + ''; + + networkConfig = pkgs.writeText "network.yaml" '' + init_config: + + instances: + # Network check only supports one configured instance + - collect_connection_state: false + excluded_interfaces: + - lo + - lo0 + ''; + postgresqlConfig = pkgs.writeText "postgres.yaml" cfg.postgresqlConfig; nginxConfig = pkgs.writeText "nginx.yaml" cfg.nginxConfig; - + mongoConfig = pkgs.writeText "mongo.yaml" cfg.mongoConfig; + etcfiles = [ { source = ddConf; target = "dd-agent/datadog.conf"; + } + { source = diskConfig; + target = "dd-agent/conf.d/disk.yaml"; + } + { source = networkConfig; + target = "dd-agent/conf.d/network.yaml"; } ] ++ (optional (cfg.postgresqlConfig != null) { source = postgresqlConfig; @@ -65,6 +90,10 @@ let (optional (cfg.nginxConfig != null) { source = nginxConfig; target = "dd-agent/conf.d/nginx.yaml"; + }) ++ + (optional (cfg.mongoConfig != null) + { source = mongoConfig; + target = "dd-agent/conf.d/mongo.yaml"; }); in { @@ -106,6 +135,12 @@ in { default = null; type = types.uniq (types.nullOr types.string); }; + + mongoConfig = mkOption { + description = "MongoDB integration configuration"; + default = null; + type = types.uniq (types.nullOr types.string); + }; }; config = mkIf cfg.enable { @@ -123,7 +158,7 @@ in { systemd.services.dd-agent = { description = "Datadog agent monitor"; - path = [ pkgs."dd-agent" pkgs.python pkgs.sysstat pkgs.procps]; + path = [ pkgs."dd-agent" pkgs.python pkgs.sysstat pkgs.procps ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { ExecStart = "${pkgs.dd-agent}/bin/dd-agent foreground"; @@ -132,7 +167,7 @@ in { Restart = "always"; RestartSec = 2; }; - restartTriggers = [ pkgs.dd-agent ddConf postgresqlConfig nginxConfig ]; + restartTriggers = [ pkgs.dd-agent ddConf diskConfig networkConfig postgresqlConfig nginxConfig mongoConfig ]; }; systemd.services.dogstatsd = { @@ -149,7 +184,7 @@ in { RestartSec = 2; }; environment.SSL_CERT_FILE = "/etc/ssl/certs/ca-bundle.crt"; - restartTriggers = [ pkgs.dd-agent ddConf postgresqlConfig nginxConfig ]; + restartTriggers = [ pkgs.dd-agent ddConf diskConfig networkConfig postgresqlConfig nginxConfig mongoConfig ]; }; environment.etc = etcfiles; diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix index 6a1799dedc8e..f987c4792e93 100644 --- a/nixos/modules/services/monitoring/grafana.nix +++ b/nixos/modules/services/monitoring/grafana.nix @@ -200,13 +200,13 @@ in { staticRootPath = mkOption { description = "Root path for static assets."; - default = "${cfg.package}/share/go/src/github.com/grafana/grafana/public"; + default = "${cfg.package.out}/share/go/src/github.com/grafana/grafana/public"; type = types.str; }; package = mkOption { description = "Package to use."; - default = pkgs.goPackages.grafana; + default = pkgs.grafana-backend; type = types.package; }; @@ -319,7 +319,7 @@ in { wantedBy = ["multi-user.target"]; after = ["networking.target"]; serviceConfig = { - ExecStart = "${cfg.package}/bin/grafana --config ${cfgFile} web"; + ExecStart = "${cfg.package-backend}/bin/grafana --config ${cfgFile} web"; WorkingDirectory = cfg.dataDir; User = "grafana"; }; diff --git a/nixos/modules/services/monitoring/scollector.nix b/nixos/modules/services/monitoring/scollector.nix index 179c587431ea..8b97daf8881a 100644 --- a/nixos/modules/services/monitoring/scollector.nix +++ b/nixos/modules/services/monitoring/scollector.nix @@ -20,9 +20,11 @@ let cfg.collectors)} ''; - cmdLineOpts = concatStringsSep " " ( - [ "-h=${cfg.bosunHost}" "-c=${collectors}" ] ++ cfg.extraOpts - ); + conf = pkgs.writeText "scollector.toml" '' + Host = "${cfg.bosunHost}" + ColDir = "${collectors}" + ${cfg.extraConfig} + ''; in { @@ -92,6 +94,14 @@ in { ''; }; + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra scollector configuration added to the end of scollector.toml + ''; + }; + }; }; @@ -108,7 +118,7 @@ in { PermissionsStartOnly = true; User = cfg.user; Group = cfg.group; - ExecStart = "${cfg.package}/bin/scollector ${cmdLineOpts}"; + ExecStart = "${cfg.package}/bin/scollector -conf=${conf} ${lib.concatStringsSep " " cfg.extraOpts}"; }; }; diff --git a/nixos/modules/services/monitoring/smartd.nix b/nixos/modules/services/monitoring/smartd.nix index 803bd9e9a65a..61ba16123252 100644 --- a/nixos/modules/services/monitoring/smartd.nix +++ b/nixos/modules/services/monitoring/smartd.nix @@ -4,8 +4,66 @@ with lib; let + host = config.networking.hostName or "unknown" + + optionalString (config.networking.domain != null) ".${config.networking.domain}"; + cfg = config.services.smartd; + nm = cfg.notifications.mail; + nw = cfg.notifications.wall; + nx = cfg.notifications.x11; + + smartdNotify = pkgs.writeScript "smartd-notify.sh" '' + #! ${pkgs.stdenv.shell} + ${optionalString nm.enable '' + { + cat << EOF + From: smartd on ${host} <root> + To: undisclosed-recipients:; + Subject: SMART error on $SMARTD_DEVICESTRING: $SMARTD_FAILTYPE + + $SMARTD_FULLMESSAGE + EOF + + ${pkgs.smartmontools}/sbin/smartctl -a -d "$SMARTD_DEVICETYPE" "$SMARTD_DEVICE" + } | ${nm.mailer} -i "${nm.recipient}" + ''} + ${optionalString nw.enable '' + { + cat << EOF + Problem detected with disk: $SMARTD_DEVICESTRING + Warning message from smartd is: + + $SMARTD_MESSAGE + EOF + } | ${pkgs.utillinux}/bin/wall 2>/dev/null + ''} + ${optionalString nx.enable '' + export DISPLAY=${nx.display} + { + cat << EOF + Problem detected with disk: $SMARTD_DEVICESTRING + Warning message from smartd is: + + $SMARTD_FULLMESSAGE + EOF + } | ${pkgs.xorg.xmessage}/bin/xmessage -file - 2>/dev/null & + ''} + ''; + + notifyOpts = optionalString (nm.enable || nw.enable || nx.enable) + ("-m <nomailer> -M exec ${smartdNotify} " + optionalString cfg.notifications.test "-M test "); + + smartdConf = pkgs.writeText "smartd.conf" '' + # Autogenerated smartd startup config file + DEFAULT ${notifyOpts}${cfg.defaults.monitored} + + ${concatMapStringsSep "\n" (d: "${d.device} ${d.options}") cfg.devices} + + ${optionalString cfg.autodetect + "DEVICESCAN ${notifyOpts}${cfg.defaults.autodetected}"} + ''; + smartdOpts = { name, ... }: { options = { @@ -22,34 +80,11 @@ let type = types.separatedString " "; description = "Options that determine how smartd monitors the device."; }; + }; }; - smartdMail = pkgs.writeScript "smartdmail.sh" '' - #! ${pkgs.stdenv.shell} - TMPNAM=/tmp/smartd-message.$$.tmp - if test -n "$SMARTD_ADDRESS"; then - echo >"$TMPNAM" "From: smartd <root>" - echo >>"$TMPNAM" 'To: undisclosed-recipients:;' - echo >>"$TMPNAM" "Subject: $SMARTD_SUBJECT" - echo >>"$TMPNAM" - echo >>"$TMPNAM" "Failure on $SMARTD_DEVICESTRING: $SMARTD_FAILTYPE" - echo >>"$TMPNAM" - cat >>"$TMPNAM" - ${pkgs.smartmontools}/sbin/smartctl >>"$TMPNAM" -a -d "$SMARTD_DEVICETYPE" "$SMARTD_DEVICE" - /var/setuid-wrappers/sendmail <"$TMPNAM" -f "$SENDER" -i "$SMARTD_ADDRESS" - fi - ''; - - smartdConf = pkgs.writeText "smartd.conf" (concatMapStrings (device: - '' - ${device.device} -a -m root -M exec ${smartdMail} ${device.options} ${cfg.deviceOpts} - '' - ) cfg.devices); - - smartdFlags = if (cfg.devices == []) then "" else "--configfile=${smartdConf}"; - in { @@ -59,26 +94,104 @@ in services.smartd = { - enable = mkOption { - default = false; + enable = mkEnableOption "smartd daemon from <literal>smartmontools</literal> package"; + + autodetect = mkOption { + default = true; type = types.bool; - example = true; description = '' - Run smartd from the smartmontools package. Note that e-mail - notifications will not be enabled unless you configure the list of - devices with <varname>services.smartd.devices</varname> as well. + Whenever smartd should monitor all devices connected to the + machine at the time it's being started (the default). + + Set to false to monitor the devices listed in + <option>services.smartd.devices</option> only. ''; }; - deviceOpts = mkOption { - default = ""; - type = types.string; - example = "-o on -s (S/../.././02|L/../../7/04)"; - description = '' - Additional options for each device that is monitored. The example - turns on SMART Automatic Offline Testing on startup, and schedules short - self-tests daily, and long self-tests weekly. - ''; + notifications = { + + mail = { + enable = mkOption { + default = config.services.mail.sendmailSetuidWrapper != null; + type = types.bool; + description = "Whenever to send e-mail notifications."; + }; + + recipient = mkOption { + default = "root"; + type = types.string; + description = "Recipient of the notification messages."; + }; + + mailer = mkOption { + default = "/var/setuid-wrappers/sendmail"; + type = types.path; + description = '' + Sendmail-compatible binary to be used to send the messages. + + You should probably enable + <option>services.postfix</option> or some other MTA for + this to work. + ''; + }; + }; + + wall = { + enable = mkOption { + default = true; + type = types.bool; + description = "Whenever to send wall notifications to all users."; + }; + }; + + x11 = { + enable = mkOption { + default = config.services.xserver.enable; + type = types.bool; + description = "Whenever to send X11 xmessage notifications."; + }; + + display = mkOption { + default = ":${toString config.services.xserver.display}"; + type = types.string; + description = "DISPLAY to send X11 notifications to."; + }; + }; + + test = mkOption { + default = false; + type = types.bool; + description = "Whenever to send a test notification on startup."; + }; + + }; + + defaults = { + monitored = mkOption { + default = "-a"; + type = types.separatedString " "; + example = "-a -o on -s (S/../.././02|L/../../7/04)"; + description = '' + Common default options for explicitly monitored (listed in + <option>services.smartd.devices</option>) devices. + + The default value turns on monitoring of all the things (see + <literal>man 5 smartd.conf</literal>). + + The example also turns on SMART Automatic Offline Testing on + startup, and schedules short self-tests daily, and long + self-tests weekly. + ''; + }; + + autodetected = mkOption { + default = cfg.defaults.monitored; + type = types.separatedString " "; + description = '' + Like <option>services.smartd.defaults.monitored</option>, but for the + autodetected devices. + ''; + }; }; devices = mkOption { @@ -86,14 +199,9 @@ in example = [ { device = "/dev/sda"; } { device = "/dev/sdb"; options = "-d sat"; } ]; type = types.listOf types.optionSet; options = [ smartdOpts ]; - description = '' - List of devices to monitor. By default -- if this list is empty --, - smartd will monitor all devices connected to the machine at the time - it's being run. Configuring this option has the added benefit of - enabling e-mail notifications to "root" every time smartd detects an - error. - ''; - }; + description = "List of devices to monitor."; + }; + }; }; @@ -103,12 +211,19 @@ in config = mkIf cfg.enable { + assertions = [ { + assertion = cfg.autodetect || cfg.devices != []; + message = "smartd can't run with both disabled autodetect and an empty list of devices to monitor."; + } ]; + systemd.services.smartd = { description = "S.M.A.R.T. Daemon"; wantedBy = [ "multi-user.target" ]; - serviceConfig.ExecStart = "${pkgs.smartmontools}/sbin/smartd --no-fork ${smartdFlags}"; + path = [ pkgs.nettools ]; # for hostname and dnsdomanname calls in smartd + + serviceConfig.ExecStart = "${pkgs.smartmontools}/sbin/smartd --no-fork --configfile=${smartdConf}"; }; }; diff --git a/nixos/modules/services/network-filesystems/nfsd.nix b/nixos/modules/services/network-filesystems/nfsd.nix index 33b7ec3d9f1c..f1838224098b 100644 --- a/nixos/modules/services/network-filesystems/nfsd.nix +++ b/nixos/modules/services/network-filesystems/nfsd.nix @@ -88,10 +88,7 @@ in environment.systemPackages = [ pkgs.nfs-utils ]; - environment.etc = singleton - { source = exports; - target = "exports"; - }; + environment.etc.exports.source = exports; boot.kernelModules = [ "nfsd" ]; diff --git a/nixos/modules/services/networking/copy-com.nix b/nixos/modules/services/networking/copy-com.nix index 36bd29109b8a..69a41ab97963 100644 --- a/nixos/modules/services/networking/copy-com.nix +++ b/nixos/modules/services/networking/copy-com.nix @@ -1,53 +1,53 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - - cfg = config.services.copy-com; - -in - -{ - options = { - - services.copy-com = { - - enable = mkOption { - default = false; - description = " - Enable the copy.com client. - - The first time copy.com is run, it needs to be configured. Before enabling run - copy_console manually. - "; - }; - - user = mkOption { - description = "The user for which copy should run."; - }; - - debug = mkOption { - default = false; - description = "Output more."; - }; - }; - }; - - config = mkIf cfg.enable { - environment.systemPackages = [ pkgs.postfix ]; - - systemd.services."copy-com-${cfg.user}" = { - description = "Copy.com Client"; - after = [ "network.target" "local-fs.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - ExecStart = "${pkgs.copy-com}/bin/copy_console ${if cfg.debug then "-consoleOutput -debugToConsole=dirwatch,path-watch,csm_path,csm -debug -console" else ""}"; - User = "${cfg.user}"; - }; - - }; - }; - -} - +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.copy-com; + +in + +{ + options = { + + services.copy-com = { + + enable = mkOption { + default = false; + description = " + Enable the Copy.com client. + NOTE: before enabling the client for the first time, it must be + configured by first running CopyConsole (command line) or CopyAgent + (graphical) as the appropriate user. + "; + }; + + user = mkOption { + description = "The user for which the Copy.com client should be run."; + }; + + debug = mkOption { + default = false; + description = "Output more (debugging) messages to the console."; + }; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.postfix ]; + + systemd.services."copy-com-${cfg.user}" = { + description = "Copy.com client"; + after = [ "network.target" "local-fs.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkgs.copy-com}/bin/CopyConsole ${if cfg.debug then "-consoleOutput -debugToConsole=dirwatch,path-watch,csm_path,csm -debug -console" else ""}"; + User = "${cfg.user}"; + }; + + }; + }; + +} + diff --git a/nixos/modules/services/networking/dnsmasq.nix b/nixos/modules/services/networking/dnsmasq.nix index 4a812167bb5f..eb3551515723 100644 --- a/nixos/modules/services/networking/dnsmasq.nix +++ b/nixos/modules/services/networking/dnsmasq.nix @@ -98,6 +98,7 @@ in ExecStart = "${dnsmasq}/bin/dnsmasq -k --enable-dbus --user=dnsmasq -C ${dnsmasqConf}"; ExecReload = "${dnsmasq}/bin/kill -HUP $MAINPID"; }; + restartTriggers = [ config.environment.etc.hosts.source ]; }; }; diff --git a/nixos/modules/services/networking/fan.nix b/nixos/modules/services/networking/fan.nix new file mode 100644 index 000000000000..3170567e5b4a --- /dev/null +++ b/nixos/modules/services/networking/fan.nix @@ -0,0 +1,60 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.networking.fan; + modprobe = "${config.system.sbin.modprobe}/sbin/modprobe"; + +in + +{ + + ###### interface + + options = { + + networking.fan = { + + enable = mkEnableOption "FAN Networking"; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.fanctl ]; + + systemd.services.fan = { + description = "FAN Networking"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + before = [ "docker.service" ]; + restartIfChanged = false; + preStart = '' + if [ ! -f /proc/sys/net/fan/version ]; then + ${modprobe} ipip + if [ ! -f /proc/sys/net/fan/version ]; then + echo "The Fan Networking patches have not been applied to this kernel!" 1>&2 + exit 1 + fi + fi + + mkdir -p /var/lib/fan-networking + ''; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${pkgs.fanctl}/bin/fanctl up -a"; + ExecStop = "${pkgs.fanctl}/bin/fanctl down -a"; + }; + }; + + }; + +} diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix index 40681f5b957a..a61f0250ef8b 100644 --- a/nixos/modules/services/networking/firewall.nix +++ b/nixos/modules/services/networking/firewall.nix @@ -420,6 +420,16 @@ in ''; }; + networking.firewall.extraPackages = mkOption { + default = [ ]; + example = [ pkgs.ipset ]; + description = + '' + Additional packages to be included in the environment of the system + as well as the path of networking.firewall.extraCommands. + ''; + }; + networking.firewall.extraStopCommands = mkOption { type = types.lines; default = ""; @@ -443,7 +453,7 @@ in networking.firewall.trustedInterfaces = [ "lo" ]; - environment.systemPackages = [ pkgs.iptables pkgs.ipset ]; + environment.systemPackages = [ pkgs.iptables ] ++ cfg.extraPackages; boot.kernelModules = map (x: "nf_conntrack_${x}") cfg.connectionTrackingModules; boot.extraModprobeConfig = optionalString (!cfg.autoLoadConntrackHelpers) '' @@ -462,7 +472,7 @@ in before = [ "network-pre.target" ]; after = [ "systemd-modules-load.service" ]; - path = [ pkgs.iptables pkgs.ipset ]; + path = [ pkgs.iptables ] ++ cfg.extraPackages; # FIXME: this module may also try to load kernel modules, but # containers don't have CAP_SYS_MODULE. So the host system had diff --git a/nixos/modules/services/networking/gateone.nix b/nixos/modules/services/networking/gateone.nix new file mode 100644 index 000000000000..93273837181e --- /dev/null +++ b/nixos/modules/services/networking/gateone.nix @@ -0,0 +1,61 @@ +{ config, lib, pkgs, ...}: +with lib; +let + cfg = config.services.gateone; +in +{ +options = { + services.gateone = { + enable = mkEnableOption "GateOne server"; + pidDir = mkOption { + default = "/run/gateone"; + type = types.path; + description = ''Path of pid files for GateOne.''; + }; + settingsDir = mkOption { + default = "/var/lib/gateone"; + type = types.path; + description = ''Path of configuration files for GateOne.''; + }; + }; +}; +config = mkIf cfg.enable { + environment.systemPackages = with pkgs.pythonPackages; [ + gateone pkgs.openssh pkgs.procps pkgs.coreutils ]; + + users.extraUsers.gateone = { + description = "GateOne privilege separation user"; + uid = config.ids.uids.gateone; + home = cfg.settingsDir; + }; + users.extraGroups.gateone.gid = config.ids.gids.gateone; + + systemd.services.gateone = with pkgs; { + description = "GateOne web-based terminal"; + path = [ pythonPackages.gateone nix openssh procps coreutils ]; + preStart = '' + if [ ! -d ${cfg.settingsDir} ] ; then + mkdir -m 0750 -p ${cfg.settingsDir} + chown -R gateone.gateone ${cfg.settingsDir} + fi + if [ ! -d ${cfg.pidDir} ] ; then + mkdir -m 0750 -p ${cfg.pidDir} + chown -R gateone.gateone ${cfg.pidDir} + fi + ''; + #unitConfig.RequiresMountsFor = "${cfg.settingsDir}"; + serviceConfig = { + ExecStart = ''${pythonPackages.gateone}/bin/gateone --settings_dir=${cfg.settingsDir} --pid_file=${cfg.pidDir}/gateone.pid --gid=${toString config.ids.gids.gateone} --uid=${toString config.ids.uids.gateone}''; + User = "gateone"; + Group = "gateone"; + WorkingDirectory = cfg.settingsDir; + PermissionsStartOnly = true; + + }; + + wantedBy = [ "multi-user.target" ]; + requires = [ "network.target" ]; + }; +}; +} + diff --git a/nixos/modules/services/networking/heyefi.nix b/nixos/modules/services/networking/heyefi.nix new file mode 100644 index 000000000000..fc2b5a848578 --- /dev/null +++ b/nixos/modules/services/networking/heyefi.nix @@ -0,0 +1,82 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.heyefi; +in + +{ + + ###### interface + + options = { + + services.heyefi = { + + enable = mkEnableOption "heyefi"; + + cardMacaddress = mkOption { + default = ""; + description = '' + An Eye-Fi card MAC address. + ''; + }; + + uploadKey = mkOption { + default = ""; + description = '' + An Eye-Fi card's upload key. + ''; + }; + + uploadDir = mkOption { + example = "/home/username/pictures"; + description = '' + The directory to upload the files to. + ''; + }; + + user = mkOption { + default = "root"; + description = '' + heyefi will be run under this user (user must exist, + this can be your user name). + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + systemd.services.heyefi = + { + description = "heyefi service"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = "${cfg.user}"; + Restart = "always"; + ExecStart = "${pkgs.heyefi}/bin/heyefi"; + }; + + }; + + environment.etc."heyefi/heyefi.config".text = + '' + # /etc/heyefi/heyefi.conf: DO NOT EDIT -- this file has been generated automatically. + cards = [["${config.services.heyefi.cardMacaddress}","${config.services.heyefi.uploadKey}"]] + upload_dir = "${toString config.services.heyefi.uploadDir}" + ''; + + environment.systemPackages = [ pkgs.heyefi ]; + + }; + +} diff --git a/nixos/modules/services/networking/i2p.nix b/nixos/modules/services/networking/i2p.nix index bad22c791388..e6ee5fd1f957 100644 --- a/nixos/modules/services/networking/i2p.nix +++ b/nixos/modules/services/networking/i2p.nix @@ -7,15 +7,7 @@ let homeDir = "/var/lib/i2p"; in { ###### interface - options.services.i2p = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Enables i2p as a running service upon activation. - ''; - }; - }; + options.services.i2p.enable = mkEnableOption "I2P router"; ###### implementation config = mkIf cfg.enable { diff --git a/nixos/modules/services/networking/kippo.nix b/nixos/modules/services/networking/kippo.nix index 68f26eefe27e..7d70a3d05fa7 100644 --- a/nixos/modules/services/networking/kippo.nix +++ b/nixos/modules/services/networking/kippo.nix @@ -86,8 +86,7 @@ rec { wantedBy = [ "multi-user.target" ]; environment.PYTHONPATH = "${pkgs.kippo}/src/:${pkgs.pythonPackages.pycrypto}/lib/python2.7/site-packages/:${pkgs.pythonPackages.pyasn1}/lib/python2.7/site-packages/:${pkgs.pythonPackages.python}/lib/python2.7/site-packages/:${pkgs.pythonPackages.twisted}/lib/python2.7/site-packages/:."; preStart = '' - if [ ! -d ${cfg.varPath}/ ] ; then - mkdir -p ${cfg.pidPath} + if [ ! -d ${cfg.varPath}/ ] ; then mkdir -p ${cfg.logPath}/tty mkdir -p ${cfg.logPath}/dl mkdir -p ${cfg.varPath}/keys @@ -97,12 +96,15 @@ rec { cp ${pkgs.kippo}/src/txtcmds ${cfg.varPath} -r chmod u+rw ${cfg.varPath} -R - chmod u+rw ${cfg.pidPath} chown kippo.kippo ${cfg.varPath} -R - chown kippo.kippo ${cfg.pidPath} chown kippo.kippo ${cfg.logPath} -R chmod u+rw ${cfg.logPath} -R fi + if [ ! -d ${cfg.pidPath}/ ] ; then + mkdir -p ${cfg.pidPath} + chmod u+rw ${cfg.pidPath} + chown kippo.kippo ${cfg.pidPath} + fi ''; serviceConfig.ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd -y ${pkgs.kippo}/src/kippo.tac --syslog --rundir=${cfg.varPath}/ --pidfile=${cfg.pidPath}/kippo.pid --prefix=kippo -n"; diff --git a/nixos/modules/services/networking/quassel.nix b/nixos/modules/services/networking/quassel.nix index 579d62884c78..005eb7bd7614 100644 --- a/nixos/modules/services/networking/quassel.nix +++ b/nixos/modules/services/networking/quassel.nix @@ -3,7 +3,7 @@ with lib; let - quassel = pkgs.kde4.quasselDaemon; + quassel = pkgs.quasselDaemon_qt5; cfg = config.services.quassel; user = if cfg.user != null then cfg.user else "quassel"; in diff --git a/nixos/modules/services/networking/racoon.nix b/nixos/modules/services/networking/racoon.nix index 9428d9112a1b..86e13d1ea0d6 100644 --- a/nixos/modules/services/networking/racoon.nix +++ b/nixos/modules/services/networking/racoon.nix @@ -36,7 +36,10 @@ in { Type = "forking"; Restart = "always"; }; - preStart = "rm /var/run/racoon.pid || true"; + preStart = '' + rm /var/run/racoon.pid || true + mkdir -p /var/racoon + ''; }; }; } diff --git a/nixos/modules/services/networking/shout.nix b/nixos/modules/services/networking/shout.nix new file mode 100644 index 000000000000..f55b87a96140 --- /dev/null +++ b/nixos/modules/services/networking/shout.nix @@ -0,0 +1,80 @@ +{ pkgs, lib, config, options, ... }: + +with lib; + +let + cfg = config.services.shout; + shoutHome = "/var/lib/shout"; + +in { + options.services.shout = { + enable = mkEnableOption "Shout web IRC client"; + + private = mkOption { + type = types.bool; + default = false; + description = '' + Make your shout instance private. You will need to configure user + accounts by adding entries in <filename>${shoutHome}/users</filename>. + ''; + }; + + host = mkOption { + type = types.string; + default = "0.0.0.0"; + description = "IP interface to listen on for http connections."; + }; + + port = mkOption { + type = types.int; + default = 9000; + description = "TCP port to listen on for http connections."; + }; + + configFile = mkOption { + type = types.nullOr types.lines; + default = null; + description = '' + Contents of Shout's <filename>config.js</filename> file. If left empty, + Shout will generate from its defaults at first startup. + + Documentation: http://shout-irc.com/docs/server/configuration.html + ''; + }; + }; + + config = mkIf cfg.enable { + users.extraUsers = singleton { + name = "shout"; + uid = config.ids.uids.shout; + description = "Shout daemon user"; + home = shoutHome; + createHome = true; + }; + + systemd.services.shout = { + description = "Shout web IRC client"; + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + preStart = if isNull cfg.configFile then null + else '' + ln -sf ${pkgs.writeText "config.js" cfg.configFile} \ + ${shoutHome}/config.js + ''; + script = concatStringsSep " " [ + "${pkgs.shout}/bin/shout" + (if cfg.private then "--private" else "--public") + "--port" (toString cfg.port) + "--host" (toString cfg.host) + "--home" shoutHome + ]; + serviceConfig = { + User = "shout"; + ProtectHome = "true"; + ProtectSystem = "full"; + PrivateTmp = "true"; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/skydns.nix b/nixos/modules/services/networking/skydns.nix index 3b9390914891..f5eb452fec62 100644 --- a/nixos/modules/services/networking/skydns.nix +++ b/nixos/modules/services/networking/skydns.nix @@ -79,7 +79,7 @@ in { ETCD_CACERT = cfg.etcd.caCert; SKYDNS_ADDR = cfg.address; SKYDNS_DOMAIN = cfg.domain; - SKYDNS_NAMESERVER = concatStringsSep "," cfg.nameservers; + SKYDNS_NAMESERVERS = concatStringsSep "," cfg.nameservers; }; serviceConfig = { ExecStart = "${cfg.package}/bin/skydns"; diff --git a/nixos/modules/services/networking/softether.nix b/nixos/modules/services/networking/softether.nix new file mode 100644 index 000000000000..49538af7d351 --- /dev/null +++ b/nixos/modules/services/networking/softether.nix @@ -0,0 +1,150 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + pkg = pkgs.softether; + cfg = config.services.softether; + +in +{ + + ###### interface + + options = { + + services.softether = { + + enable = mkEnableOption "SoftEther VPN services"; + + vpnserver.enable = mkEnableOption "SoftEther VPN Server"; + + vpnbridge.enable = mkEnableOption "SoftEther VPN Bridge"; + + vpnclient = { + enable = mkEnableOption "SoftEther VPN Client"; + up = mkOption { + type = types.lines; + default = ""; + description = '' + Shell commands executed when the Virtual Network Adapter(s) is/are starting. + ''; + }; + down = mkOption { + type = types.lines; + default = ""; + description = '' + Shell commands executed when the Virtual Network Adapter(s) is/are shutting down. + ''; + }; + }; + + dataDir = mkOption { + type = types.string; + default = "${pkg.dataDir}"; + description = '' + Data directory for SoftEther VPN. + ''; + }; + + }; + + }; + + ###### implementation + + config = mkIf cfg.enable ( + + mkMerge [{ + environment.systemPackages = [ + (pkgs.lib.overrideDerivation pkg (attrs: { + dataDir = cfg.dataDir; + })) + ]; + jobs.softether = { + description = "SoftEther VPN services initial job"; + startOn = "started network-interfaces"; + preStart = '' + for d in vpnserver vpnbridge vpnclient vpncmd; do + if ! test -e ${cfg.dataDir}/$d; then + ${pkgs.coreutils}/bin/mkdir -m0700 -p ${cfg.dataDir}/$d + install -m0600 ${pkg}${cfg.dataDir}/$d/hamcore.se2 ${cfg.dataDir}/$d/hamcore.se2 + fi + done + rm -rf ${cfg.dataDir}/vpncmd/vpncmd + ln -s ${pkg}${cfg.dataDir}/vpncmd/vpncmd ${cfg.dataDir}/vpncmd/vpncmd + ''; + exec = "true"; + }; + } + + (mkIf (cfg.vpnserver.enable) { + systemd.services.vpnserver = { + description = "SoftEther VPN Server"; + after = [ "network-interfaces.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkg}/bin/vpnserver start"; + ExecStop = "${pkg}/bin/vpnserver stop"; + Type = "forking"; + }; + preStart = '' + rm -rf ${cfg.dataDir}/vpnserver/vpnserver + ln -s ${pkg}${cfg.dataDir}/vpnserver/vpnserver ${cfg.dataDir}/vpnserver/vpnserver + ''; + postStop = '' + rm -rf ${cfg.dataDir}/vpnserver/vpnserver + ''; + }; + }) + + (mkIf (cfg.vpnbridge.enable) { + systemd.services.vpnbridge = { + description = "SoftEther VPN Bridge"; + after = [ "network-interfaces.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkg}/bin/vpnbridge start"; + ExecStop = "${pkg}/bin/vpnbridge stop"; + Type = "forking"; + }; + preStart = '' + rm -rf ${cfg.dataDir}/vpnbridge/vpnbridge + ln -s ${pkg}${cfg.dataDir}/vpnbridge/vpnbridge ${cfg.dataDir}/vpnbridge/vpnbridge + ''; + postStop = '' + rm -rf ${cfg.dataDir}/vpnbridge/vpnbridge + ''; + }; + }) + + (mkIf (cfg.vpnclient.enable) { + systemd.services.vpnclient = { + description = "SoftEther VPN Client"; + after = [ "network-interfaces.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkg}/bin/vpnclient start"; + ExecStop = "${pkg}/bin/vpnclient stop"; + Type = "forking"; + }; + preStart = '' + rm -rf ${cfg.dataDir}/vpnclient/vpnclient + ln -s ${pkg}${cfg.dataDir}/vpnclient/vpnclient ${cfg.dataDir}/vpnclient/vpnclient + ''; + postStart = '' + sleep 1 + ${cfg.vpnclient.up} + ''; + postStop = '' + rm -rf ${cfg.dataDir}/vpnclient/vpnclient + sleep 1 + ${cfg.vpnclient.down} + ''; + }; + boot.kernelModules = [ "tun" ]; + }) + + ]); + +} diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index 4be2b5fe0c0c..5baea4bc6aea 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -9,14 +9,6 @@ let nssModulesPath = config.system.nssModules.path; - knownHosts = map (h: getAttr h cfg.knownHosts) (attrNames cfg.knownHosts); - - knownHostsText = flip (concatMapStringsSep "\n") knownHosts - (h: - concatStringsSep "," h.hostNames + " " - + (if h.publicKey != null then h.publicKey else readFile h.publicKeyFile) - ); - userOptions = { openssh.authorizedKeys = { @@ -48,8 +40,7 @@ let }; authKeysFiles = let - mkAuthKeyFile = u: { - target = "ssh/authorized_keys.d/${u.name}"; + mkAuthKeyFile = u: nameValuePair "ssh/authorized_keys.d/${u.name}" { mode = "0444"; source = pkgs.writeText "${u.name}-authorized_keys" '' ${concatStringsSep "\n" u.openssh.authorizedKeys.keys} @@ -59,7 +50,7 @@ let usersWithKeys = attrValues (flip filterAttrs config.users.extraUsers (n: u: length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0 )); - in map mkAuthKeyFile usersWithKeys; + in listToAttrs (map mkAuthKeyFile usersWithKeys); in @@ -184,16 +175,11 @@ in hostKeys = mkOption { type = types.listOf types.attrs; default = - [ { path = "/etc/ssh/ssh_host_dsa_key"; - type = "dsa"; - } - { path = "/etc/ssh/ssh_host_ecdsa_key"; - type = "ecdsa"; - bits = 521; - } - { path = "/etc/ssh/ssh_host_ed25519_key"; - type = "ed25519"; - } + [ { type = "rsa"; bits = 4096; path = "/etc/ssh/ssh_host_rsa_key"; } + { type = "ed25519"; path = "/etc/ssh/ssh_host_ed25519_key"; } + ] ++ optionals (!versionAtLeast config.system.stateVersion "15.07") + [ { type = "dsa"; path = "/etc/ssh/ssh_host_dsa_key"; } + { type = "ecdsa"; bits = 521; path = "/etc/ssh/ssh_host_ecdsa_key"; } ]; description = '' NixOS can automatically generate SSH host keys. This option @@ -216,57 +202,6 @@ in description = "Verbatim contents of <filename>sshd_config</filename>."; }; - knownHosts = mkOption { - default = {}; - type = types.loaOf types.optionSet; - description = '' - The set of system-wide known SSH hosts. - ''; - example = [ - { - hostNames = [ "myhost" "myhost.mydomain.com" "10.10.1.4" ]; - publicKeyFile = literalExample "./pubkeys/myhost_ssh_host_dsa_key.pub"; - } - { - hostNames = [ "myhost2" ]; - publicKeyFile = literalExample "./pubkeys/myhost2_ssh_host_dsa_key.pub"; - } - ]; - options = { - hostNames = mkOption { - type = types.listOf types.str; - default = []; - description = '' - A list of host names and/or IP numbers used for accessing - the host's ssh service. - ''; - }; - publicKey = mkOption { - default = null; - type = types.nullOr types.str; - example = "ecdsa-sha2-nistp521 AAAAE2VjZHN...UEPg=="; - description = '' - The public key data for the host. You can fetch a public key - from a running SSH server with the <command>ssh-keyscan</command> - command. The public key should not include any host names, only - the key type and the key itself. - ''; - }; - publicKeyFile = mkOption { - default = null; - type = types.nullOr types.path; - description = '' - The path to the public key file for the host. The public - key file is read at build time and saved in the Nix store. - You can fetch a public key file from a running SSH server - with the <command>ssh-keyscan</command> command. The content - of the file should follow the same format as described for - the <literal>publicKey</literal> option. - ''; - }; - }; - }; - moduliFile = mkOption { example = "services.openssh.moduliFile = /etc/my-local-ssh-moduli;"; type = types.path; @@ -279,7 +214,7 @@ in }; - users.extraUsers = mkOption { + users.users = mkOption { options = [ userOptions ]; }; @@ -297,14 +232,8 @@ in services.openssh.moduliFile = mkDefault "${cfgc.package}/etc/ssh/moduli"; - environment.etc = authKeysFiles ++ [ - { source = cfg.moduliFile; - target = "ssh/moduli"; - } - { text = knownHostsText; - target = "ssh/ssh_known_hosts"; - } - ]; + environment.etc = authKeysFiles // + { "ssh/moduli".source = cfg.moduliFile; }; systemd = let @@ -422,11 +351,6 @@ in assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true; message = "cannot enable X11 forwarding without setting xauth location";}] - ++ flip mapAttrsToList cfg.knownHosts (name: data: { - assertion = (data.publicKey == null && data.publicKeyFile != null) || - (data.publicKey != null && data.publicKeyFile == null); - message = "knownHost ${name} must contain either a publicKey or publicKeyFile"; - }) ++ flip map cfg.listenAddresses ({ addr, port, ... }: { assertion = addr != null; message = "addr must be specified in each listenAddresses entry"; diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix index 02572c1e27d2..d5accfef1cb5 100644 --- a/nixos/modules/services/networking/syncthing.nix +++ b/nixos/modules/services/networking/syncthing.nix @@ -36,9 +36,7 @@ in dataDir = mkOption { default = "/var/lib/syncthing"; description = '' - Path where the `.syncthing` (settings and keys) and `Sync` - (your synced files) directories will exist. This can be your home - directory. + Path where the settings and keys will exist. ''; }; @@ -57,18 +55,12 @@ in after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; environment.STNORESTART = "placeholder"; # do not self-restart - environment.HOME = "${cfg.dataDir}"; serviceConfig = { User = "${cfg.user}"; PermissionsStartOnly = true; Restart = "always"; - ExecStart = "${pkgs.syncthing}/bin/syncthing -home=${cfg.dataDir}/.syncthing"; + ExecStart = "${pkgs.syncthing}/bin/syncthing -no-browser -home=${cfg.dataDir}"; }; - preStart = '' - mkdir -p ${cfg.dataDir} - chown ${cfg.user} ${cfg.dataDir} - ''; - }; environment.systemPackages = [ pkgs.syncthing ]; diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix index fd9589883edc..69c76cf97cfd 100644 --- a/nixos/modules/services/printing/cupsd.nix +++ b/nixos/modules/services/printing/cupsd.nix @@ -160,6 +160,17 @@ in ''; }; + snmpConf = mkOption { + type = types.lines; + default = '' + Address @LOCAL + ''; + description = '' + The contents of <filename>/etc/cups/snmp.conf</filename>. See "man + cups-snmp.conf" for a complete description. + ''; + }; + drivers = mkOption { type = types.listOf types.path; example = literalExample "[ pkgs.splix ]"; @@ -199,6 +210,7 @@ in environment.etc."cups/cups-files.conf".text = cfg.cupsFilesConf; environment.etc."cups/cupsd.conf".text = cfg.cupsdConf; environment.etc."cups/cups-browsed.conf".text = cfg.browsedConf; + environment.etc."cups/snmp.conf".text = cfg.snmpConf; services.dbus.packages = [ cups ]; @@ -230,8 +242,8 @@ in ]; }; - systemd.services.cups-browsed = - { description = "Make remote CUPS printers available locally"; + systemd.services.cups-browsed = mkIf config.services.avahi.enable + { description = "CUPS Remote Printer Discovery"; wantedBy = [ "multi-user.target" ]; wants = [ "cups.service" "avahi-daemon.service" ]; diff --git a/nixos/modules/services/scheduling/cron.nix b/nixos/modules/services/scheduling/cron.nix index 1f42086dc1ec..02d80a77da50 100644 --- a/nixos/modules/services/scheduling/cron.nix +++ b/nixos/modules/services/scheduling/cron.nix @@ -4,8 +4,6 @@ with lib; let - inherit (config.services) jobsTags; - # Put all the system cronjobs together. systemCronJobsFile = pkgs.writeText "system-crontab" '' @@ -25,9 +23,9 @@ let sendmailPath = "/var/setuid-wrappers/sendmail"; }; - allFiles = map (f: "\"${f}\"") ( - [ "${systemCronJobsFile}" ] ++ config.services.cron.cronFiles - ); + allFiles = + optional (config.services.cron.systemCronJobs != []) systemCronJobsFile + ++ config.services.cron.cronFiles; in @@ -91,36 +89,49 @@ in ###### implementation - config = mkIf (config.services.cron.enable && allFiles != []) { + config = mkMerge [ - security.setuidPrograms = [ "crontab" ]; + { services.cron.enable = mkDefault (allFiles != []); } - environment.systemPackages = [ cronNixosPkg ]; + (mkIf (config.services.cron.enable) { - systemd.services.cron = - { description = "Cron Daemon"; + security.setuidPrograms = [ "crontab" ]; - wantedBy = [ "multi-user.target" ]; + environment.systemPackages = [ cronNixosPkg ]; - preStart = - '' - rm -f /etc/crontab - cat ${toString allFiles} > /etc/crontab - chmod 0600 /etc/crontab + environment.etc.crontab = + { source = pkgs.runCommand "crontabs" { inherit allFiles; } + '' + touch $out + for i in $allFiles; do + cat "$i" >> $out + done + ''; + mode = "0600"; # Cron requires this. + }; - mkdir -m 710 -p /var/cron + systemd.services.cron = + { description = "Cron Daemon"; - # By default, allow all users to create a crontab. This - # is denoted by the existence of an empty cron.deny file. - if ! test -e /var/cron/cron.allow -o -e /var/cron/cron.deny; then - touch /var/cron/cron.deny - fi - ''; + wantedBy = [ "multi-user.target" ]; - restartTriggers = [ config.environment.etc.localtime.source ]; - serviceConfig.ExecStart = "${cronNixosPkg}/bin/cron -n"; - }; + preStart = + '' + mkdir -m 710 -p /var/cron - }; + # By default, allow all users to create a crontab. This + # is denoted by the existence of an empty cron.deny file. + if ! test -e /var/cron/cron.allow -o -e /var/cron/cron.deny; then + touch /var/cron/cron.deny + fi + ''; + + restartTriggers = [ config.environment.etc.localtime.source ]; + serviceConfig.ExecStart = "${cronNixosPkg}/bin/cron -n"; + }; + + }) + + ]; } diff --git a/nixos/modules/services/security/hologram.nix b/nixos/modules/services/security/hologram.nix index f9abf38942f4..58f308df7a21 100644 --- a/nixos/modules/services/security/hologram.nix +++ b/nixos/modules/services/security/hologram.nix @@ -95,7 +95,7 @@ in { wantedBy = [ "multi-user.target" ]; serviceConfig = { - ExecStart = "${pkgs.goPackages.hologram}/bin/hologram-server --debug --conf ${cfgFile}"; + ExecStart = "${pkgs.hologram}/bin/hologram-server --debug --conf ${cfgFile}"; }; }; }; diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix index 5c20901427cb..77427ce9606e 100644 --- a/nixos/modules/services/system/dbus.nix +++ b/nixos/modules/services/system/dbus.nix @@ -73,6 +73,7 @@ in enable = mkOption { type = types.bool; default = true; + internal = true; description = '' Whether to start the D-Bus message bus daemon, which is required by many other system services and applications. diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index fe50c182bfe5..b16f701a0c9f 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -11,7 +11,9 @@ let ${cfg.config} ${optionalString (cfg.httpConfig != "") '' http { - ${cfg.httpConfig} + ${cfg.httpConfig} + ${cfg.httpServers} + ${cfg.httpDefaultServer} } ''} ${cfg.appendConfig} @@ -60,7 +62,32 @@ in httpConfig = mkOption { type = types.lines; default = ""; - description = "Configuration lines to be appended inside of the http {} block."; + description = '' + Configuration lines to be placed at the top inside of + the http {} block. The option is intended to be used for + the default configuration of the servers. + ''; + }; + + httpServers = mkOption { + type = types.lines; + default = ""; + description = '' + Configuration lines to be placed inside of the http {} + block. The option is intended to be used for defining + individual servers. + ''; + }; + + httpDefaultServer = mkOption { + type = types.lines; + default = ""; + description = '' + Configuration lines to be placed at the bottom inside of + the http {} block. The option is intended to be used for + setting up the default servers. The default server is used + if no previously specified server matches a request. + ''; }; stateDir = mkOption { diff --git a/nixos/modules/services/web-servers/nginx/reverse_proxy.nix b/nixos/modules/services/web-servers/nginx/reverse_proxy.nix new file mode 100644 index 000000000000..c21406dff29a --- /dev/null +++ b/nixos/modules/services/web-servers/nginx/reverse_proxy.nix @@ -0,0 +1,233 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.nginx; + + defaultSSL = cfg.httpDefaultKey != null || cfg.httpDefaultCertificate != null; + + validSSL = key: cert: cert != null && key != null || cert == null && key == null; + +in + +{ + options = { + + services.nginx = { + + reverseProxies = mkOption { + type = types.attrsOf (types.submodule ( + { + options = { + proxy = mkOption { + type = types.str; + default = []; + description = '' + Exclude files and directories matching these patterns. + ''; + }; + + key = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Exclude files and directories matching these patterns. + ''; + }; + + certificate = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Exclude files and directories matching these patterns. + ''; + }; + }; + } + )); + + default = {}; + + example = literalExample '' + { + "hydra.yourdomain.org" = + { proxy = "localhost:3000"; + key = "/etc/nixos/certs/hydra_key.key"; + certificate = "/etc/nixos/certs/hydra_cert.crt"; + }; + } + ''; + + description = '' + A reverse proxy server configuration is created for every attribute. + The attribute name corresponds to the name the server is listening to, + and the proxy option defines the target to forward the requests to. + If a key and certificate are given, then the server is secured through + a SSL connection. Non-SSL requests on port 80 are automatically + re-directed to the SSL server on port 443. + ''; + }; + + httpDefaultKey = mkOption { + type = types.nullOr types.path; + default = null; + example = "/etc/nixos/certs/defaut_key.key"; + description = '' + Key of SSL certificate for default server. + The default certificate is presented by the default server during + the SSL handshake when no specialized server configuration matches + a request. + A default SSL certificate is also helpful if browsers do not + support the TLS Server Name Indication extension (SNI, RFC 6066). + ''; + }; + + httpDefaultCertificate = mkOption { + type = types.nullOr types.path; + default = null; + example = "/etc/nixos/certs/defaut_key.crt"; + description = '' + SSL certificate for default server. + The default certificate is presented by the default server during + the SSL handshake when no specialized server configuration matches + a request. + A default SSL certificate is also helpful if browsers do not + support the TLS Server Name Indication extension (SNI, RFC 6066). + ''; + }; + + }; + + }; + + + config = mkIf (cfg.reverseProxies != {}) { + + assertions = [ + { assertion = all id (mapAttrsToList (n: v: validSSL v.certificate v.key) cfg.reverseProxies); + message = '' + One (or more) reverse proxy configurations specify only either + the key option or the certificate option. Both certificate + with associated key have to be configured to enable SSL for a + server configuration. + + services.nginx.reverseProxies: ${toString cfg.reverseProxies} + ''; + } + { assertion = validSSL cfg.httpDefaultCertificate cfg.httpDefaultKey; + message = '' + The default server configuration specifies only either the key + option or the certificate option. Both httpDefaultCertificate + with associated httpDefaultKey have to be configured to enable + SSL for the default server configuration. + + services.nginx.httpDefaultCertificate: ${toString cfg.httpDefaultCertificate} + + services.nginx.httpDefaultKey : ${toString cfg.httpDefaultKey} + ''; + } + ]; + + services.nginx.config = mkBefore '' + worker_processes 1; + error_log logs/error.log debug; + pid logs/nginx.pid; + events { + worker_connections 1024; + } + ''; + + services.nginx.httpConfig = mkBefore '' + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + access_log logs/access.log main; + sendfile on; + tcp_nopush on; + keepalive_timeout 10; + gzip on; + + ${lib.optionalString defaultSSL '' + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_certificate ${cfg.httpDefaultCertificate}; + ssl_certificate_key ${cfg.httpDefaultKey}; + ''} + ''; + + services.nginx.httpDefaultServer = mkBefore '' + # reject as default policy + server { + listen 80 default_server; + listen [::]:80 default_server; + ${lib.optionalString defaultSSL "listen 443 default_server ssl;"} + return 444; + } + ''; + + services.nginx.httpServers = + let + useSSL = certificate: key: certificate != null && key != null; + + server = servername: proxy: certificate: key: useSSL: '' + server { + server_name ${servername}; + keepalive_timeout 70; + + ${if !useSSL then '' + listen 80; + listen [::]:80; + '' else '' + listen 443 ssl; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + ssl_certificate ${certificate}; + ssl_certificate_key ${key}; + ''} + + location / { + proxy_pass ${proxy}; + + ### force timeouts if one of backend is dead ## + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + + ### Set headers #### + proxy_set_header Accept-Encoding ""; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + ${lib.optionalString useSSL '' + ### Most PHP, Python, Rails, Java App can use this header ### + #proxy_set_header X-Forwarded-Proto https;## + #This is better## + proxy_set_header X-Forwarded-Proto $scheme; + add_header Front-End-Https on; + ''} + + ### By default we don't want to redirect it #### + proxy_redirect off; + proxy_buffering off; + } + } + + ${lib.optionalString useSSL '' + # redirect http to https + server { + listen 80; + listen [::]:80; + server_name ${servername}; + return 301 https://$server_name$request_uri; + } + ''} + ''; + in + concatStrings (mapAttrsToList (n: v: server n v.proxy v.certificate v.key (useSSL v.proxy v.certificate)) cfg.reverseProxies); + + }; + +} diff --git a/nixos/modules/services/x11/desktop-managers/e19.nix b/nixos/modules/services/x11/desktop-managers/e19.nix index 2d5c7b192bc6..74065c862ef7 100644 --- a/nixos/modules/services/x11/desktop-managers/e19.nix +++ b/nixos/modules/services/x11/desktop-managers/e19.nix @@ -62,6 +62,7 @@ in waitPID=$! ''; }]; + services.xserver.displayManager.desktopManagerHandlesLidAndPower = true; security.setuidPrograms = [ "e19_freqset" ]; diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix index cf6d2cab3492..507c2d2da139 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -25,6 +25,24 @@ let ''; }; + nixos-gsettings-desktop-schemas = pkgs.stdenv.mkDerivation { + name = "nixos-gsettings-desktop-schemas"; + buildInputs = [ pkgs.nixos-artwork ]; + buildCommand = '' + mkdir -p $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas + cp -rf ${gnome3.gsettings_desktop_schemas}/share/gsettings-schemas/gsettings-desktop-schemas*/glib-2.0 $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas/ + chmod -R a+w $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas + cat - > $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas/glib-2.0/schemas/nixos-defaults.gschema.override <<- EOF + [org.gnome.desktop.background] + picture-uri='${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png' + + [org.gnome.desktop.screensaver] + picture-uri='${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png' + EOF + ${pkgs.glib}/bin/glib-compile-schemas $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas/glib-2.0/schemas/ + ''; + }; + in { options = { @@ -40,7 +58,7 @@ in { example = literalExample "[ pkgs.gnome3.gpaste ]"; description = "Additional list of packages to be added to the session search path. Useful for gnome shell extensions or gsettings-conditionated autostart."; - apply = list: list ++ [ gnome3.gnome_shell ]; + apply = list: list ++ [ gnome3.gnome_shell gnome3.gnome-shell-extensions ]; }; environment.gnome3.packageSet = mkOption { @@ -81,6 +99,7 @@ in { networking.networkmanager.enable = mkDefault true; services.upower.enable = config.powerManagement.enable; hardware.bluetooth.enable = mkDefault true; + services.xserver.displayManager.desktopManagerHandlesLidAndPower = false; # true doesn't make sense here, GNOME just doesn't handle it anymore fonts.fonts = [ pkgs.dejavu_fonts pkgs.cantarell_fonts ]; @@ -109,6 +128,9 @@ in { # Override default mimeapps 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/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas''${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS + # 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/kde4.nix b/nixos/modules/services/x11/desktop-managers/kde4.nix index 21b6243ba188..7830e984219a 100644 --- a/nixos/modules/services/x11/desktop-managers/kde4.nix +++ b/nixos/modules/services/x11/desktop-managers/kde4.nix @@ -111,6 +111,7 @@ in exec ${kde_workspace}/bin/startkde ''; }; + services.xserver.displayManager.desktopManagerHandlesLidAndPower = true; security.setuidOwners = singleton { program = "kcheckpass"; diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix index 5061d59b7c7f..01a8704fea71 100644 --- a/nixos/modules/services/x11/desktop-managers/kde5.nix +++ b/nixos/modules/services/x11/desktop-managers/kde5.nix @@ -78,6 +78,7 @@ in bgSupport = true; start = ''exec ${plasma5.plasma-workspace}/bin/startkde;''; }; + services.xserver.displayManager.desktopManagerHandlesLidAndPower = true; security.setuidOwners = singleton { program = "kcheckpass"; diff --git a/nixos/modules/services/x11/desktop-managers/kodi.nix b/nixos/modules/services/x11/desktop-managers/kodi.nix index 1e30308a5139..e6d6efaf3a61 100644 --- a/nixos/modules/services/x11/desktop-managers/kodi.nix +++ b/nixos/modules/services/x11/desktop-managers/kodi.nix @@ -25,7 +25,8 @@ in waitPID=$! ''; }]; + services.xserver.displayManager.desktopManagerHandlesLidAndPower = true; environment.systemPackages = [ pkgs.kodi ]; }; -} \ No newline at end of file +} diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix index fce5bf11f053..746f810a11ff 100644 --- a/nixos/modules/services/x11/desktop-managers/xfce.nix +++ b/nixos/modules/services/x11/desktop-managers/xfce.nix @@ -37,6 +37,7 @@ in exec ${pkgs.stdenv.shell} ${pkgs.xfce.xinitrc} ''; }; + services.xserver.displayManager.desktopManagerHandlesLidAndPower = true; environment.systemPackages = [ pkgs.gtk # To get GTK+'s themes. @@ -62,7 +63,7 @@ in pkgs.xfce.xfwm4 # This supplies some "abstract" icons such as # "utilities-terminal" and "accessories-text-editor". - pkgs.gnome.gnomeicontheme + pkgs.gnome3.defaultIconTheme pkgs.desktop_file_utils pkgs.xfce.libxfce4ui pkgs.xfce.garcon diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix index 7e05cd84be64..fc0803f2acaf 100644 --- a/nixos/modules/services/x11/display-managers/default.nix +++ b/nixos/modules/services/x11/display-managers/default.nix @@ -62,7 +62,7 @@ let if [ -z "$_INHIBITION_LOCK_TAKEN" ]; then export _INHIBITION_LOCK_TAKEN=1 if ! ${config.systemd.package}/bin/loginctl show-session $XDG_SESSION_ID | grep -q '^RemoteHost='; then - exec ${config.systemd.package}/bin/systemd-inhibit --what=handle-lid-switch:handle-power-key --why="See NixOS configuration option 'services.xserver.displayManager.desktopManagerHandlesLidAndPower' for more information." "$0" "$sessionType" + exec ${config.systemd.package}/bin/systemd-inhibit --what=handle-lid-switch:handle-power-key --why="Desktop environment handles power events" "$0" "$sessionType" fi fi @@ -161,7 +161,11 @@ let exit 0 ''; - mkDesktops = names: pkgs.runCommand "desktops" {} + mkDesktops = names: pkgs.runCommand "desktops" + { # trivial derivation + preferLocalBuild = true; + allowSubstitutes = false; + } '' mkdir -p $out ${concatMapStrings (n: '' @@ -225,7 +229,7 @@ in desktopManagerHandlesLidAndPower = mkOption { type = types.bool; - default = true; + default = false; description = '' Whether the display manager should prevent systemd from handling lid and power events. This is normally handled by the desktop diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix index 6c3c52730863..55af2ecbb764 100644 --- a/nixos/modules/services/x11/display-managers/gdm.nix +++ b/nixos/modules/services/x11/display-managers/gdm.nix @@ -18,14 +18,45 @@ in services.xserver.displayManager.gdm = { - enable = mkOption { - type = types.bool; - default = false; - example = true; + enable = mkEnableOption '' + GDM as the display manager. + <emphasis>GDM is very experimental and may render system unusable.</emphasis> + ''; + + autoLogin = mkOption { + default = {}; description = '' - Whether to enable GDM as the display manager. - <emphasis>GDM is very experimental and may render system unusable.</emphasis> + Auto login configuration attrset. ''; + + type = types.submodule { + options = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Automatically log in as the sepecified <option>autoLogin.user</option>. + ''; + }; + + user = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + User to be used for the autologin. + ''; + }; + + delay = mkOption { + type = types.int; + default = 0; + description = '' + Seconds of inactivity after which the autologin will be performed. + ''; + }; + + }; + }; }; }; @@ -37,6 +68,13 @@ in config = mkIf cfg.gdm.enable { + assertions = [ + { assertion = let autoLogin = cfg.gdm.autoLogin; in + if autoLogin.enable then autoLogin.user != null else true; + message = "GDM auto-login requires services.xserver.displayManager.gdm.autoLogin.user to be set"; + } + ]; + services.xserver.displayManager.slim.enable = false; users.extraUsers.gdm = @@ -50,7 +88,7 @@ in users.extraGroups.gdm.gid = config.ids.gids.gdm; services.xserver.displayManager.job = - { + { environment = { GDM_X_SERVER = "${cfg.xserverBin} ${cfg.xserverArgs}"; GDM_SESSIONS_DIR = "${cfg.session.desktops}"; @@ -71,6 +109,25 @@ in programs.dconf.profiles.gdm = "${gdm}/share/dconf/profile/gdm"; + environment.etc."gdm/custom.conf".text = '' + [daemon] + ${optionalString cfg.gdm.autoLogin.enable '' + TimedLoginEnable=true + TimedLogin=${cfg.gdm.autoLogin.user} + TimedLoginDelay=${toString cfg.gdm.autoLogin.delay} + ''} + + [security] + + [xdmcp] + + [greeter] + + [chooser] + + [debug] + ''; + # GDM LFS PAM modules, adapted somehow to NixOS security.pam.services = { gdm-launch-environment.text = '' @@ -89,7 +146,7 @@ in session optional pam_permit.so ''; - gdm.text = '' + gdm.text = '' auth requisite pam_nologin.so auth required pam_env.so @@ -130,7 +187,7 @@ in "auth required pam_deny.so"} account sufficient pam_unix.so - + password requisite pam_unix.so nullok sha512 ${optionalString config.security.pam.enableEcryptfs "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} diff --git a/nixos/modules/services/x11/redshift.nix b/nixos/modules/services/x11/redshift.nix index 99d19f6ab151..4f39e05f0f8d 100644 --- a/nixos/modules/services/x11/redshift.nix +++ b/nixos/modules/services/x11/redshift.nix @@ -47,6 +47,13 @@ in { type = types.str; }; }; + + services.redshift.extraOptions = mkOption { + type = types.listOf types.str; + default = []; + example = [ "-v" "-m randr" ]; + description = "Additional command-line arguments to pass to the redshift(1) command"; + }; }; config = mkIf cfg.enable { @@ -59,7 +66,8 @@ in { ${pkgs.redshift}/bin/redshift \ -l ${cfg.latitude}:${cfg.longitude} \ -t ${toString cfg.temperature.day}:${toString cfg.temperature.night} \ - -b ${toString cfg.brightness.day}:${toString cfg.brightness.night} + -b ${toString cfg.brightness.day}:${toString cfg.brightness.night} \ + ${lib.strings.concatStringsSep " " cfg.extraOptions} ''; environment = { DISPLAY = ":0"; }; serviceConfig.Restart = "always"; diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix index a8b1044ad365..4751de07a15d 100644 --- a/nixos/modules/services/x11/window-managers/default.nix +++ b/nixos/modules/services/x11/window-managers/default.nix @@ -25,6 +25,7 @@ in ./windowmaker.nix ./wmii.nix ./xmonad.nix + ./qtile.nix ./none.nix ]; options = { diff --git a/nixos/modules/services/x11/window-managers/icewm.nix b/nixos/modules/services/x11/window-managers/icewm.nix index 36028da453a5..9a3e80221890 100644 --- a/nixos/modules/services/x11/window-managers/icewm.nix +++ b/nixos/modules/services/x11/window-managers/icewm.nix @@ -3,29 +3,16 @@ with lib; let - cfg = config.services.xserver.windowManager.icewm; - in - { - ###### interface - options = { - - services.xserver.windowManager.icewm.enable = mkOption { - default = false; - description = "Enable the IceWM window manager."; - }; - + services.xserver.windowManager.icewm.enable = mkEnableOption "oroborus"; }; - ###### implementation - config = mkIf cfg.enable { - services.xserver.windowManager.session = singleton { name = "icewm"; start = @@ -36,7 +23,5 @@ in }; environment.systemPackages = [ pkgs.icewm ]; - }; - } diff --git a/nixos/modules/services/x11/window-managers/oroborus.nix b/nixos/modules/services/x11/window-managers/oroborus.nix new file mode 100644 index 000000000000..bd7e3396864b --- /dev/null +++ b/nixos/modules/services/x11/window-managers/oroborus.nix @@ -0,0 +1,25 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.xserver.windowManager.oroborus; +in +{ + ###### interface + options = { + services.xserver.windowManager.oroborus.enable = mkEnableOption "oroborus"; + }; + + ###### implementation + config = mkIf cfg.enable { + services.xserver.windowManager.session = singleton { + name = "oroborus"; + start = '' + ${pkgs.oroborus}/bin/oroborus & + waitPID=$! + ''; + }; + environment.systemPackages = [ pkgs.oroborus ]; + }; +} diff --git a/nixos/modules/services/x11/window-managers/qtile.nix b/nixos/modules/services/x11/window-managers/qtile.nix new file mode 100644 index 000000000000..37f84f0903c3 --- /dev/null +++ b/nixos/modules/services/x11/window-managers/qtile.nix @@ -0,0 +1,25 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.xserver.windowManager.qtile; +in + +{ + options = { + services.xserver.windowManager.qtile.enable = mkEnableOption "qtile"; + }; + + config = mkIf cfg.enable { + services.xserver.windowManager.session = [{ + name = "qtile"; + start = '' + ${pkgs.qtile}/bin/qtile + waitPID=$! + ''; + }]; + + environment.systemPackages = [ pkgs.qtile ]; + }; +} diff --git a/nixos/modules/services/x11/window-managers/wmii.nix b/nixos/modules/services/x11/window-managers/wmii.nix index 75f6fdfe3bc4..e6f534a1be66 100644 --- a/nixos/modules/services/x11/window-managers/wmii.nix +++ b/nixos/modules/services/x11/window-managers/wmii.nix @@ -1,47 +1,43 @@ -{ config, lib, pkgs, ... }: - -with lib; +{ config, lib, pkgs, options, modulesPath }: let - + inherit (lib) mkOption mkIf singleton; cfg = config.services.xserver.windowManager.wmii; - + wmii = pkgs.wmii_hg; in - { options = { - services.xserver.windowManager.wmii.enable = mkOption { default = false; example = true; description = "Enable the wmii window manager."; }; - }; config = mkIf cfg.enable { - services.xserver.windowManager.session = singleton # stop wmii by # $wmiir xwrite /ctl quit # this will cause wmii exiting with exit code 0 + # (or "mod+a quit", which is bound to do the same thing in wmiirc + # by default) # # why this loop? # wmii crashes once a month here. That doesn't matter that much - # wmii can recover very well. However without loop the x session terminates and then your workspace setup is - # lost and all applications running on X will terminate. + # wmii can recover very well. However without loop the X session + # terminates and then your workspace setup is lost and all + # applications running on X will terminate. # Another use case is kill -9 wmii; after rotating screen. - # Note: we don't like kill for that purpose. But it works (-> subject "wmii and xrandr" on mailinglist) + # Note: we don't like kill for that purpose. But it works (-> + # subject "wmii and xrandr" on mailinglist) { name = "wmii"; start = '' while :; do - ${pkgs.wmiiSnap}/bin/wmii && break + ${wmii}/bin/wmii && break done ''; }; - environment.systemPackages = [ pkgs.wmiiSnap ]; - + environment.systemPackages = [ wmii ]; }; - } diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl index 4289740322ad..655fbab2a843 100644 --- a/nixos/modules/system/activation/switch-to-configuration.pl +++ b/nixos/modules/system/activation/switch-to-configuration.pl @@ -97,7 +97,7 @@ sub parseFstab { sub parseUnit { my ($filename) = @_; my $info = {}; - parseKeyValues($info, read_file($filename)); + parseKeyValues($info, read_file($filename)) if -f $filename; parseKeyValues($info, read_file("${filename}.d/overrides.conf")) if -f "${filename}.d/overrides.conf"; return $info; } @@ -157,7 +157,8 @@ while (my ($unit, $state) = each %{$activePrev}) { if (-e $prevUnitFile && ($state->{state} eq "active" || $state->{state} eq "activating")) { if (! -e $newUnitFile || abs_path($newUnitFile) eq "/dev/null") { - $unitsToStop{$unit} = 1; + my $unitInfo = parseUnit($prevUnitFile); + $unitsToStop{$unit} = 1 if boolIsTrue($unitInfo->{'X-StopOnRemoval'} // "yes"); } elsif ($unit =~ /\.target$/) { diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix index 839300798167..a977ddb7bb4d 100644 --- a/nixos/modules/system/activation/top-level.nix +++ b/nixos/modules/system/activation/top-level.nix @@ -50,7 +50,7 @@ let ln -s ${config.system.build.initialRamdisk}/initrd $out/initrd - ln -s ${config.hardware.firmware} $out/firmware + ln -s ${config.hardware.firmware}/lib/firmware $out/firmware ''} echo "$activationScript" > $out/activate diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix index 63a095be6311..ac40e8a49acf 100644 --- a/nixos/modules/system/boot/kernel.nix +++ b/nixos/modules/system/boot/kernel.nix @@ -49,9 +49,8 @@ in type = types.int; default = 4; description = '' - The kernel console log level. Only log messages with a - priority numerically less than this will appear on the - console. + The kernel console log level. Log messages with a priority + numerically less than this will not appear on the console. ''; }; @@ -217,7 +216,7 @@ in ]; # The Linux kernel >= 2.6.27 provides firmware. - hardware.firmware = [ "${kernel}/lib/firmware" ]; + hardware.firmware = [ kernel ]; # Create /etc/modules-load.d/nixos.conf, which is read by # systemd-modules-load.service to load required kernel modules. diff --git a/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix index 261192c6d24e..c5c250c14cea 100644 --- a/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix +++ b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.nix @@ -3,6 +3,7 @@ pkgs.substituteAll { src = ./extlinux-conf-builder.sh; isExecutable = true; - inherit (pkgs) bash; path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep]; + inherit (pkgs) bash; + kernelDTB = pkgs.stdenv.platform.kernelDTB or false; } diff --git a/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh index 8f2a496de8b6..b9a42b2a196d 100644 --- a/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh +++ b/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh @@ -75,8 +75,10 @@ addEntry() { copyToKernelsDir "$path/kernel"; kernel=$result copyToKernelsDir "$path/initrd"; initrd=$result - # XXX UGLY: maybe the system config should have a top-level "dtbs" entry? - copyToKernelsDir $(readlink -m "$path/kernel/../dtbs"); dtbs=$result + if [ -n "@kernelDTB@" ]; then + # XXX UGLY: maybe the system config should have a top-level "dtbs" entry? + copyToKernelsDir $(readlink -m "$path/kernel/../dtbs"); dtbs=$result + fi timestampEpoch=$(stat -L -c '%Z' $path) @@ -93,7 +95,9 @@ addEntry() { fi echo " LINUX ../nixos/$(basename $kernel)" echo " INITRD ../nixos/$(basename $initrd)" - echo " FDTDIR ../nixos/$(basename $dtbs)" + if [ -n "@kernelDTB@" ]; then + echo " FDTDIR ../nixos/$(basename $dtbs)" + fi echo " APPEND systemConfig=$path init=$path/init $extraParams" } @@ -105,20 +109,24 @@ cat > $tmpFile <<EOF # Change this to e.g. nixos-42 to temporarily boot to an older configuration. DEFAULT nixos-default +MENU TITLE ------------------------------------------------------------ TIMEOUT $timeout -$(addEntry $default default) EOF -# Add up to $numGenerations generations of the system profile to the menu, -# in reverse (most recent to least recent) order. -for generation in $( - (cd /nix/var/nix/profiles && ls -d system-*-link) \ - | sed 's/system-\([0-9]\+\)-link/\1/' \ - | sort -n -r \ - | head -n $numGenerations); do - link=/nix/var/nix/profiles/system-$generation-link - addEntry $link $generation -done >> $tmpFile +addEntry $default default >> $tmpFile + +if [ "$numGenerations" -gt 0 ]; then + # Add up to $numGenerations generations of the system profile to the menu, + # in reverse (most recent to least recent) order. + for generation in $( + (cd /nix/var/nix/profiles && ls -d system-*-link) \ + | sed 's/system-\([0-9]\+\)-link/\1/' \ + | sort -n -r \ + | head -n $numGenerations); do + link=/nix/var/nix/profiles/system-$generation-link + addEntry $link $generation + done >> $tmpFile +fi mv -f $tmpFile $target/extlinux/extlinux.conf diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix index c7cf712e3c2b..0b349749244f 100644 --- a/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixos/modules/system/boot/loader/grub/grub.nix @@ -10,7 +10,7 @@ let realGrub = if cfg.version == 1 then pkgs.grub else if cfg.zfsSupport then pkgs.grub2.override { zfsSupport = true; } - else if cfg.enableTrustedboot then pkgs.trustedGrub + else if cfg.enableTrustedBoot then pkgs.trustedGrub else pkgs.grub2; grub = @@ -112,7 +112,7 @@ in description = '' The devices on which the boot loader, GRUB, will be installed. Can be used instead of <literal>device</literal> to - install grub into multiple devices (e.g., if as softraid arrays holding /boot). + install GRUB onto multiple devices. ''; }; @@ -135,8 +135,8 @@ in example = "/boot1"; type = types.str; description = '' - The path to the boot directory where grub will be written. Generally - this boot parth should double as an efi path. + The path to the boot directory where GRUB will be written. Generally + this boot path should double as an EFI path. ''; }; @@ -166,7 +166,7 @@ in example = [ "/dev/sda" "/dev/sdb" ]; type = types.listOf types.str; description = '' - The path to the devices which will have the grub mbr written. + The path to the devices which will have the GRUB MBR written. Note these are typically device paths and not paths to partitions. ''; }; @@ -197,7 +197,7 @@ in type = types.lines; description = '' Additional bash commands to be run at the script that - prepares the grub menu entries. + prepares the GRUB menu entries. ''; }; @@ -276,7 +276,7 @@ in example = "1024x768"; type = types.str; description = '' - The gfxmode to pass to grub when loading a graphical boot interface under efi. + The gfxmode to pass to GRUB when loading a graphical boot interface under EFI. ''; }; @@ -285,7 +285,7 @@ in example = "auto"; type = types.str; description = '' - The gfxmode to pass to grub when loading a graphical boot interface under bios. + The gfxmode to pass to GRUB when loading a graphical boot interface under BIOS. ''; }; @@ -330,10 +330,10 @@ in type = types.addCheck types.str (type: type == "uuid" || type == "label" || type == "provided"); description = '' - Determines how grub will identify devices when generating the + Determines how GRUB will identify devices when generating the configuration file. A value of uuid / label signifies that grub will always resolve the uuid or label of the device before using - it in the configuration. A value of provided means that grub will + it in the configuration. A value of provided means that GRUB will use the device name as show in <command>df</command> or <command>mount</command>. Note, zfs zpools / datasets are ignored and will always be mounted using their labels. @@ -344,7 +344,7 @@ in default = false; type = types.bool; description = '' - Whether grub should be build against libzfs. + Whether GRUB should be build against libzfs. ZFS support is only available for GRUB v2. This option is ignored for GRUB v1. ''; @@ -354,7 +354,7 @@ in default = false; type = types.bool; description = '' - Whether grub should be build with EFI support. + Whether GRUB should be build with EFI support. EFI support is only available for GRUB v2. This option is ignored for GRUB v1. ''; @@ -364,16 +364,16 @@ in default = false; type = types.bool; description = '' - Enable support for encrypted partitions. Grub should automatically + Enable support for encrypted partitions. GRUB should automatically unlock the correct encrypted partition and look for filesystems. ''; }; - enableTrustedboot = mkOption { + enableTrustedBoot = mkOption { default = false; type = types.bool; description = '' - Enable trusted boot. Grub will measure all critical components during + Enable trusted boot. GRUB will measure all critical components during the boot process to offer TCG (TPM) support. ''; }; @@ -429,7 +429,7 @@ in assertions = [ { assertion = !cfg.zfsSupport || cfg.version == 2; - message = "Only grub version 2 provides zfs support"; + message = "Only GRUB version 2 provides ZFS support"; } { assertion = cfg.mirroredBoots != [ ]; @@ -441,19 +441,19 @@ in message = "You cannot have duplicated devices in mirroredBoots"; } { - assertion = !cfg.enableTrustedboot || cfg.version == 2; + assertion = !cfg.enableTrustedBoot || cfg.version == 2; message = "Trusted GRUB is only available for GRUB 2"; } { - assertion = !cfg.efiSupport || !cfg.enableTrustedboot; + assertion = !cfg.efiSupport || !cfg.enableTrustedBoot; message = "Trusted GRUB does not have EFI support"; } { - assertion = !cfg.zfsSupport || !cfg.enableTrustedboot; + assertion = !cfg.zfsSupport || !cfg.enableTrustedBoot; message = "Trusted GRUB does not have ZFS support"; } { - assertion = !cfg.enableTrustedboot; + assertion = !cfg.enableTrustedBoot; message = "Trusted GRUB can break your system. Remove assertion if you want to test trustedGRUB nevertheless."; } ] ++ flip concatMap cfg.mirroredBoots (args: [ @@ -471,7 +471,7 @@ in } ] ++ flip map args.devices (device: { assertion = device == "nodev" || hasPrefix "/" device; - message = "Grub devices must be absolute paths, not ${dev} in ${args.path}"; + message = "GRUB devices must be absolute paths, not ${dev} in ${args.path}"; })); }) diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl index 34bff727b73a..af39e50ff72d 100644 --- a/nixos/modules/system/boot/loader/grub/install-grub.pl +++ b/nixos/modules/system/boot/loader/grub/install-grub.pl @@ -237,6 +237,7 @@ else { $conf .= " " . $grubStore->search; } + # FIXME: should use grub-mkconfig. $conf .= " " . $grubBoot->search . " if [ -s \$prefix/grubenv ]; then @@ -245,14 +246,12 @@ else { # ‘grub-reboot’ sets a one-time saved entry, which we process here and # then delete. - if [ \"\${saved_entry}\" ]; then - # The next line *has* to look exactly like this, otherwise KDM's - # reboot feature won't work properly with GRUB 2. + if [ \"\${next_entry}\" ]; then + # FIXME: KDM expects the next line to be present. set default=\"\${saved_entry}\" - set saved_entry= - set prev_saved_entry= - save_env saved_entry - save_env prev_saved_entry + set default=\"\${next_entry}\" + set next_entry= + save_env next_entry set timeout=1 else set default=$defaultEntry diff --git a/nixos/modules/system/boot/modprobe.nix b/nixos/modules/system/boot/modprobe.nix index a3b616ff3eff..c49380899664 100644 --- a/nixos/modules/system/boot/modprobe.nix +++ b/nixos/modules/system/boot/modprobe.nix @@ -35,6 +35,7 @@ with lib; fi ''; + meta.priority = 4; }; description = '' Wrapper around modprobe that sets the path to the modules diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index c4c84784feac..366bec7187ba 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -642,6 +642,10 @@ in if ! [ -e /etc/machine-id ]; then ${systemd}/bin/systemd-machine-id-setup fi + + # Keep a persistent journal. Note that systemd-tmpfiles will + # set proper ownership/permissions. + mkdir -m 0700 -p /var/log/journal ''; users.extraUsers.systemd-network.uid = config.ids.uids.systemd-network; @@ -712,6 +716,14 @@ in }) (filterAttrs (name: service: service.startAt != "") cfg.services); + # Generate timer units for all services that have a ‘startAt’ value. + systemd.user.timers = + mapAttrs (name: service: + { wantedBy = [ "timers.target" ]; + timerConfig.OnCalendar = service.startAt; + }) + (filterAttrs (name: service: service.startAt != "") cfg.user.services); + systemd.sockets.systemd-journal-gatewayd.wantedBy = optional config.services.journald.enableHttpGateway "sockets.target"; diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index 6361ed2cc431..a967fc77e686 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -708,11 +708,14 @@ in pkgs.iproute pkgs.iputils pkgs.nettools - pkgs.wirelesstools + pkgs.openresolv + ] + ++ optionals (!config.boot.isContainer) [ + pkgs.wirelesstools # FIXME: obsolete? pkgs.iw pkgs.rfkill - pkgs.openresolv - ] ++ bridgeStp; + ] + ++ bridgeStp; systemd.targets."network-interfaces" = { description = "All Network Interfaces"; diff --git a/nixos/modules/virtualisation/brightbox-config.nix b/nixos/modules/virtualisation/brightbox-config.nix new file mode 100644 index 000000000000..528ffecc0bf2 --- /dev/null +++ b/nixos/modules/virtualisation/brightbox-config.nix @@ -0,0 +1,5 @@ +{ config, pkgs, modulesPath, ... }: + +{ + imports = [ "${modulesPath}/virtualisation/brightbox-image.nix" ]; +} diff --git a/nixos/modules/virtualisation/brightbox-image.nix b/nixos/modules/virtualisation/brightbox-image.nix new file mode 100644 index 000000000000..3a956caca0c3 --- /dev/null +++ b/nixos/modules/virtualisation/brightbox-image.nix @@ -0,0 +1,166 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + diskSize = "20G"; +in +{ + imports = [ ../profiles/headless.nix ../profiles/qemu-guest.nix ]; + + system.build.brightboxImage = + pkgs.vmTools.runInLinuxVM ( + pkgs.runCommand "brightbox-image" + { preVM = + '' + mkdir $out + diskImage=$out/$diskImageBase + truncate $diskImage --size ${diskSize} + mv closure xchg/ + ''; + + postVM = + '' + PATH=$PATH:${pkgs.gnutar}/bin:${pkgs.gzip}/bin + pushd $out + ${pkgs.qemu_kvm}/bin/qemu-img convert -c -O qcow2 $diskImageBase nixos.qcow2 + rm $diskImageBase + popd + ''; + diskImageBase = "nixos-${config.system.nixosVersion}-${pkgs.stdenv.system}.raw"; + buildInputs = [ pkgs.utillinux pkgs.perl ]; + exportReferencesGraph = + [ "closure" config.system.build.toplevel ]; + } + '' + # Create partition table + ${pkgs.parted}/sbin/parted /dev/vda mklabel msdos + ${pkgs.parted}/sbin/parted /dev/vda mkpart primary ext4 1 ${diskSize} + ${pkgs.parted}/sbin/parted /dev/vda print + . /sys/class/block/vda1/uevent + mknod /dev/vda1 b $MAJOR $MINOR + + # Create an empty filesystem and mount it. + ${pkgs.e2fsprogs}/sbin/mkfs.ext4 -L nixos /dev/vda1 + ${pkgs.e2fsprogs}/sbin/tune2fs -c 0 -i 0 /dev/vda1 + + mkdir /mnt + mount /dev/vda1 /mnt + + # The initrd expects these directories to exist. + mkdir /mnt/dev /mnt/proc /mnt/sys + + mount --bind /proc /mnt/proc + mount --bind /dev /mnt/dev + mount --bind /sys /mnt/sys + + # Copy all paths in the closure to the filesystem. + storePaths=$(perl ${pkgs.pathsFromGraph} /tmp/xchg/closure) + + mkdir -p /mnt/nix/store + echo "copying everything (will take a while)..." + cp -prd $storePaths /mnt/nix/store/ + + # Register the paths in the Nix database. + printRegistration=1 perl ${pkgs.pathsFromGraph} /tmp/xchg/closure | \ + chroot /mnt ${config.nix.package}/bin/nix-store --load-db --option build-users-group "" + + # Create the system profile to allow nixos-rebuild to work. + chroot /mnt ${config.nix.package}/bin/nix-env \ + -p /nix/var/nix/profiles/system --set ${config.system.build.toplevel} \ + --option build-users-group "" + + # `nixos-rebuild' requires an /etc/NIXOS. + mkdir -p /mnt/etc + touch /mnt/etc/NIXOS + + # `switch-to-configuration' requires a /bin/sh + mkdir -p /mnt/bin + ln -s ${config.system.build.binsh}/bin/sh /mnt/bin/sh + + # Install a configuration.nix. + mkdir -p /mnt/etc/nixos /mnt/boot/grub + cp ${./brightbox-config.nix} /mnt/etc/nixos/configuration.nix + + # Generate the GRUB menu. + ln -s vda /dev/sda + chroot /mnt ${config.system.build.toplevel}/bin/switch-to-configuration boot + + umount /mnt/proc /mnt/dev /mnt/sys + umount /mnt + '' + ); + + fileSystems."/".label = "nixos"; + + # Generate a GRUB menu. Amazon's pv-grub uses this to boot our kernel/initrd. + boot.loader.grub.device = "/dev/vda"; + boot.loader.grub.timeout = 0; + + # Don't put old configurations in the GRUB menu. The user has no + # way to select them anyway. + boot.loader.grub.configurationLimit = 0; + + # Allow root logins only using the SSH key that the user specified + # at instance creation time. + services.openssh.enable = true; + services.openssh.permitRootLogin = "without-password"; + + # Force getting the hostname from Google Compute. + networking.hostName = mkDefault ""; + + # Always include cryptsetup so that NixOps can use it. + environment.systemPackages = [ pkgs.cryptsetup ]; + + systemd.services."fetch-ec2-data" = + { description = "Fetch EC2 Data"; + + wantedBy = [ "multi-user.target" "sshd.service" ]; + before = [ "sshd.service" ]; + wants = [ "ip-up.target" ]; + after = [ "ip-up.target" ]; + + path = [ pkgs.wget pkgs.iproute ]; + + script = + '' + wget="wget -q --retry-connrefused -O -" + + ${optionalString (config.networking.hostName == "") '' + echo "setting host name..." + ${pkgs.nettools}/bin/hostname $($wget http://169.254.169.254/latest/meta-data/hostname) + ''} + + # Don't download the SSH key if it has already been injected + # into the image (a Nova feature). + if ! [ -e /root/.ssh/authorized_keys ]; then + echo "obtaining SSH key..." + mkdir -m 0700 -p /root/.ssh + $wget http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > /root/key.pub + if [ $? -eq 0 -a -e /root/key.pub ]; then + if ! grep -q -f /root/key.pub /root/.ssh/authorized_keys; then + cat /root/key.pub >> /root/.ssh/authorized_keys + echo "new key added to authorized_keys" + fi + chmod 600 /root/.ssh/authorized_keys + rm -f /root/key.pub + fi + fi + + # Extract the intended SSH host key for this machine from + # the supplied user data, if available. Otherwise sshd will + # generate one normally. + $wget http://169.254.169.254/2011-01-01/user-data > /root/user-data || true + key="$(sed 's/|/\n/g; s/SSH_HOST_DSA_KEY://; t; d' /root/user-data)" + key_pub="$(sed 's/SSH_HOST_DSA_KEY_PUB://; t; d' /root/user-data)" + if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_dsa_key ]; then + mkdir -m 0755 -p /etc/ssh + (umask 077; echo "$key" > /etc/ssh/ssh_host_dsa_key) + echo "$key_pub" > /etc/ssh/ssh_host_dsa_key.pub + fi + ''; + + serviceConfig.Type = "oneshot"; + serviceConfig.RemainAfterExit = true; + }; + +} diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix index da39dda85353..59f486ff78b7 100644 --- a/nixos/modules/virtualisation/containers.nix +++ b/nixos/modules/virtualisation/containers.nix @@ -120,6 +120,15 @@ in ''; }; + interfaces = mkOption { + type = types.listOf types.string; + default = []; + example = [ "eth1" "eth2" ]; + description = '' + The list of interfaces to be moved into the container. + ''; + }; + autoStart = mkOption { type = types.bool; default = false; @@ -218,6 +227,10 @@ in extraFlags+=" --network-veth" fi + for iface in $INTERFACES; do + extraFlags+=" --network-interface=$iface" + done + for iface in $MACVLANS; do extraFlags+=" --network-macvlan=$iface" done @@ -331,6 +344,7 @@ in LOCAL_ADDRESS=${cfg.localAddress} ''} ''} + INTERFACES="${toString cfg.interfaces}" ${optionalString cfg.autoStart '' AUTO_START=1 ''} diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix index ef9cc2280db7..ba078cc0a11f 100644 --- a/nixos/modules/virtualisation/docker.nix +++ b/nixos/modules/virtualisation/docker.nix @@ -43,6 +43,17 @@ in in future. So set this option explicitly to false if you wish. ''; }; + storageDriver = + mkOption { + type = types.enum ["aufs" "btrfs" "devicemapper" "overlay" "zfs"]; + description = + '' + This option determines which Docker storage driver to use. + It is required but lacks a default value as its most + suitable value will depend the filesystems available on the + host. + ''; + }; extraOptions = mkOption { type = types.separatedString " "; @@ -54,6 +65,21 @@ in ''; }; + postStart = + mkOption { + type = types.string; + default = '' + while ! [ -e /var/run/docker.sock ]; do + sleep 0.1 + done + ''; + description = '' + The postStart phase of the systemd service. You may need to + override this if you are passing in flags to docker which + don't cause the socket file to be created. + ''; + }; + }; @@ -70,7 +96,7 @@ in after = [ "network.target" "docker.socket" ]; requires = [ "docker.socket" ]; serviceConfig = { - ExecStart = "${pkgs.docker}/bin/docker --daemon=true --host=fd:// --group=docker ${cfg.extraOptions}"; + ExecStart = "${pkgs.docker}/bin/docker daemon --host=fd:// --group=docker --storage-driver=${cfg.storageDriver} ${cfg.extraOptions}"; # I'm not sure if that limits aren't too high, but it's what # goes in config bundled with docker itself LimitNOFILE = 1048576; @@ -96,7 +122,7 @@ in wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; serviceConfig = { - ExecStart = "${pkgs.docker}/bin/docker --daemon=true --group=docker ${cfg.extraOptions}"; + ExecStart = "${pkgs.docker}/bin/docker daemon --group=docker --storage-driver=${cfg.storageDriver} ${cfg.extraOptions}"; # I'm not sure if that limits aren't too high, but it's what # goes in config bundled with docker itself LimitNOFILE = 1048576; @@ -106,11 +132,7 @@ in path = [ pkgs.kmod ]; environment.MODULE_DIR = "/run/current-system/kernel-modules/lib/modules"; - postStart = '' - while ! [ -e /var/run/docker.sock ]; do - sleep 0.1 - done - ''; + postStart = cfg.postStart; # Presumably some containers are running we don't want to interrupt restartIfChanged = false; diff --git a/nixos/modules/virtualisation/openvswitch.nix b/nixos/modules/virtualisation/openvswitch.nix index 69ca13a71479..b5155246fdad 100644 --- a/nixos/modules/virtualisation/openvswitch.nix +++ b/nixos/modules/virtualisation/openvswitch.nix @@ -67,7 +67,6 @@ in { description = "Open_vSwitch Database Server"; wantedBy = [ "multi-user.target" ]; after = [ "systemd-udev-settle.service" ]; - wants = [ "vswitchd.service" ]; path = [ cfg.package ]; restartTriggers = [ db cfg.package ]; # Create the config database @@ -108,6 +107,7 @@ in { systemd.services.vswitchd = { description = "Open_vSwitch Daemon"; + wantedBy = [ "multi-user.target" ]; bindsTo = [ "ovsdb.service" ]; after = [ "ovsdb.service" ]; path = [ cfg.package ]; @@ -135,8 +135,8 @@ in { systemd.services.ovs-monitor-ipsec = { description = "Open_vSwitch Ipsec Daemon"; wantedBy = [ "multi-user.target" ]; - requires = [ "racoon.service" ]; - after = [ "vswitchd.service" ]; + requires = [ "ovsdb.service" ]; + before = [ "vswitchd.service" "racoon.service" ]; environment.UNIXCTLPATH = "/tmp/ovsdb.ctl.sock"; serviceConfig = { ExecStart = '' diff --git a/nixos/modules/virtualisation/virtualbox-guest.nix b/nixos/modules/virtualisation/virtualbox-guest.nix index a0e4bd558e05..642ea3154b1b 100644 --- a/nixos/modules/virtualisation/virtualbox-guest.nix +++ b/nixos/modules/virtualisation/virtualbox-guest.nix @@ -6,7 +6,7 @@ with lib; let - cfg = config.services.virtualboxGuest; + cfg = config.virtualisation.virtualbox.guest; kernel = config.boot.kernelPackages; in @@ -15,20 +15,11 @@ in ###### interface - options = { - - services.virtualboxGuest = { - - enable = mkOption { - default = false; - description = "Whether to enable the VirtualBox service and other guest additions."; - }; - - }; - + options.virtualisation.virtualbox.guest.enable = mkOption { + default = false; + description = "Whether to enable the VirtualBox service and other guest additions."; }; - ###### implementation config = mkIf cfg.enable { @@ -54,7 +45,7 @@ in unitConfig.ConditionVirtualization = "oracle"; - serviceConfig.ExecStart = "@${kernel.virtualboxGuestAdditions}/sbin/VBoxService VBoxService --foreground"; + serviceConfig.ExecStart = "@${kernel.virtualboxGuestAdditions}/bin/VBoxService VBoxService --foreground"; }; services.xserver.videoDrivers = mkOverride 50 [ "virtualbox" ]; diff --git a/nixos/modules/programs/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix index fc113a08a356..00486df5c4ba 100644 --- a/nixos/modules/programs/virtualbox-host.nix +++ b/nixos/modules/virtualisation/virtualbox-host.nix @@ -3,7 +3,7 @@ with lib; let - cfg = config.services.virtualboxHost; + cfg = config.virtualisation.virtualbox.host; virtualbox = config.boot.kernelPackages.virtualbox.override { inherit (cfg) enableHardening; }; @@ -11,12 +11,12 @@ let in { - options.services.virtualboxHost = { + options.virtualisation.virtualbox.host = { enable = mkOption { type = types.bool; default = false; description = '' - Whether to enable host-side support for VirtualBox. + Whether to enable VirtualBox. <note><para> In order to pass USB devices from the host to the guests, the user diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix index 8232f6e50dfc..c1538feb9df5 100644 --- a/nixos/modules/virtualisation/virtualbox-image.nix +++ b/nixos/modules/virtualisation/virtualbox-image.nix @@ -128,6 +128,6 @@ in { boot.loader.grub.version = 2; boot.loader.grub.device = "/dev/sda"; - services.virtualboxGuest.enable = true; + virtualisation.virtualbox.guest.enable = true; }; } diff --git a/nixos/modules/virtualisation/xen-dom0.nix b/nixos/modules/virtualisation/xen-dom0.nix index c750286a3970..a0b2d5363eb2 100644 --- a/nixos/modules/virtualisation/xen-dom0.nix +++ b/nixos/modules/virtualisation/xen-dom0.nix @@ -121,6 +121,10 @@ in "xenfs" ]; + # The xenfs module is needed in system.activationScripts.xen, but + # the modprobe command there fails silently. Include xenfs in the + # initrd as a work around. + boot.initrd.kernelModules = [ "xenfs" ]; # The radeonfb kernel module causes the screen to go black as soon # as it's loaded, so don't load it. @@ -182,6 +186,9 @@ in { source = "${pkgs.xen}/etc/xen/scripts"; target = "xen/scripts"; } + { source = "${pkgs.xen}/etc/default/xendomains"; + target = "default/xendomains"; + } ]; # Xen provides udev rules. @@ -199,7 +206,8 @@ in rm -f "$XENSTORED_ROOTDIR"/tdb* &>/dev/null mkdir -p /var/run - ${optionalString cfg.trace "mkdir -p /var/log/xen"} + mkdir -p /var/log/xen # Running xl requires /var/log/xen and /var/lib/xen, + mkdir -p /var/lib/xen # so we create them here unconditionally. grep -q control_d /proc/xen/capabilities ''; serviceConfig.ExecStart = '' |