diff options
Diffstat (limited to 'nixos')
144 files changed, 3768 insertions, 1239 deletions
diff --git a/nixos/doc/manual/administration/declarative-containers.xml b/nixos/doc/manual/administration/declarative-containers.xml index 177ebdd8db17..228c45b0c1fe 100644 --- a/nixos/doc/manual/administration/declarative-containers.xml +++ b/nixos/doc/manual/administration/declarative-containers.xml @@ -49,4 +49,8 @@ on container networking.)</para> switch</literal>. Note that this will not delete the root directory of the container in <literal>/var/lib/containers</literal>.</para> -</section> \ No newline at end of file +<para>Declarative containers can be started and stopped using the +corresponding systemd service, e.g. <literal>systemctl start +container@database</literal>.</para> + +</section> diff --git a/nixos/doc/manual/configuration/config-file.xml b/nixos/doc/manual/configuration/config-file.xml index 2a58ff25941c..b613c7f06cc8 100644 --- a/nixos/doc/manual/configuration/config-file.xml +++ b/nixos/doc/manual/configuration/config-file.xml @@ -68,7 +68,7 @@ instance, if you try to define an option that doesn’t exist (that is, doesn’t have a corresponding <emphasis>option declaration</emphasis>), <command>nixos-rebuild</command> will give an error like: <screen> -The option `services.httpd.enabl' defined in `/etc/nixos/configuration.nix' does not exist. +The option `services.httpd.enable' defined in `/etc/nixos/configuration.nix' does not exist. </screen> Likewise, values in option definitions must have a correct type. For instance, <option>services.httpd.enable</option> must be a Boolean diff --git a/nixos/doc/manual/configuration/network-manager.xml b/nixos/doc/manual/configuration/network-manager.xml index ceac40b7a1f6..b7e47b8729f3 100644 --- a/nixos/doc/manual/configuration/network-manager.xml +++ b/nixos/doc/manual/configuration/network-manager.xml @@ -10,7 +10,7 @@ use NetworkManager. You can enable NetworkManager by setting: <programlisting> -services.networkmanager.enable = true; +networking.networkmanager.enable = true; </programlisting> some desktop managers (e.g., GNOME) enable NetworkManager @@ -19,8 +19,8 @@ automatically for you.</para> <para>All users that should have permission to change network settings must belong to the <code>networkmanager</code> group.</para> -<note><para><code>services.networkmanager</code> and -<code>services.wireless</code> can not be enabled at the same time: +<note><para><code>networking.networkmanager</code> and +<code>networking.wireless</code> can not be enabled at the same time: you can still connect to the wireless networks using NetworkManager.</para></note> diff --git a/nixos/doc/manual/man-nixos-install.xml b/nixos/doc/manual/man-nixos-install.xml index 06e7b4a98470..7ad1be1ec105 100644 --- a/nixos/doc/manual/man-nixos-install.xml +++ b/nixos/doc/manual/man-nixos-install.xml @@ -26,6 +26,22 @@ <replaceable>root</replaceable> </arg> <arg> + <group choice='req'> + <arg choice='plain'><option>--max-jobs</option></arg> + <arg choice='plain'><option>-j</option></arg> + </group> + <replaceable>number</replaceable> + </arg> + <arg> + <option>--cores</option> + <replaceable>number</replaceable> + </arg> + <arg> + <option>--option</option> + <replaceable>name</replaceable> + <replaceable>value</replaceable> + </arg> + <arg> <arg choice='plain'><option>--show-trace</option></arg> </arg> <arg> @@ -96,6 +112,37 @@ it.</para> </listitem> </varlistentry> + <varlistentry><term><option>--max-jobs</option></term> + <term><option>-j</option></term> + + <listitem><para>Sets the maximum number of build jobs that Nix will + perform in parallel to the specified number. The default is <literal>1</literal>. + A higher value is useful on SMP systems or to exploit I/O latency.</para></listitem> + + </varlistentry> + + + <varlistentry><term><option>--cores</option></term> + + <listitem><para>Sets the value of the <envar>NIX_BUILD_CORES</envar> + environment variable in the invocation of builders. Builders can + use this variable at their discretion to control the maximum amount + of parallelism. For instance, in Nixpkgs, if the derivation + attribute <varname>enableParallelBuilding</varname> is set to + <literal>true</literal>, the builder passes the + <option>-j<replaceable>N</replaceable></option> flag to GNU Make. + The value <literal>0</literal> means that the builder should use all + available CPU cores in the system.</para></listitem> + + </varlistentry> + + <varlistentry><term><option>--option</option> <replaceable>name</replaceable> <replaceable>value</replaceable></term> + + <listitem><para>Set the Nix configuration option + <replaceable>name</replaceable> to <replaceable>value</replaceable>.</para></listitem> + + </varlistentry> + <varlistentry> <term><option>--show-trace</option></term> <listitem> diff --git a/nixos/doc/manual/man-nixos-rebuild.xml b/nixos/doc/manual/man-nixos-rebuild.xml index afc159dbd5d7..c529737c3bf3 100644 --- a/nixos/doc/manual/man-nixos-rebuild.xml +++ b/nixos/doc/manual/man-nixos-rebuild.xml @@ -1,7 +1,7 @@ <refentry xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude"> - + <refmeta> <refentrytitle><command>nixos-rebuild</command></refentrytitle> <manvolnum>8</manvolnum> @@ -22,7 +22,8 @@ <arg choice='plain'><option>boot</option></arg> <arg choice='plain'><option>test</option></arg> <arg choice='plain'><option>build</option></arg> - <arg choice='plain'><option>dry-run</option></arg> + <arg choice='plain'><option>dry-build</option></arg> + <arg choice='plain'><option>dry-activate</option></arg> <arg choice='plain'><option>build-vm</option></arg> <arg choice='plain'><option>build-vm-with-bootloader</option></arg> </group> @@ -114,10 +115,22 @@ $ nix-build /path/to/nixpkgs/nixos -A system </varlistentry> <varlistentry> - <term><option>dry-run</option></term> + <term><option>dry-build</option></term> + <listitem> + <para>Show what store paths would be built or downloaded by any + of the operations above, but otherwise do nothing.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><option>dry-activate</option></term> <listitem> - <para>Simply show what store paths would be built or downloaded - by any of the operations above.</para> + <para>Build the new configuration, but instead of activating it, + show what changes would be performed by the activation (i.e. by + <command>nixos-rebuild test</command>). For + instance, this command will print which systemd units would be + restarted. The list of changes is not guaranteed to be + complete.</para> </listitem> </varlistentry> diff --git a/nixos/lib/eval-config.nix b/nixos/lib/eval-config.nix index 08adcf3a0078..adacbd0863e3 100644 --- a/nixos/lib/eval-config.nix +++ b/nixos/lib/eval-config.nix @@ -2,27 +2,51 @@ # configuration object (`config') from which we can retrieve option # values. -{ system ? builtins.currentSystem -, pkgs ? null -, baseModules ? import ../modules/module-list.nix -, extraArgs ? {} +# !!! Please think twice before adding to this argument list! +# Ideally eval-config.nix would be an extremely thin wrapper +# around lib.evalModules, so that modular systems that have nixos configs +# as subcomponents (e.g. the container feature, or nixops if network +# expressions are ever made modular at the top level) can just use +# types.submodule instead of using eval-config.nix +{ # !!! system can be set modularly, would be nice to remove + system ? builtins.currentSystem +, # !!! is this argument needed any more? The pkgs argument can + # be set modularly anyway. + pkgs ? null +, # !!! what do we gain by making this configurable? + baseModules ? import ../modules/module-list.nix +, # !!! See comment about args in lib/modules.nix + extraArgs ? {} , modules -, check ? true +, # !!! See comment about check in lib/modules.nix + check ? true , prefix ? [] +, lib ? import ../../lib }: let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system; extraModules = let e = builtins.getEnv "NIXOS_EXTRA_MODULE_PATH"; in if e == "" then [] else [(import (builtins.toPath e))]; +in + +let + pkgsModule = rec { + _file = ./eval-config.nix; + key = _file; + config = { + nixpkgs.system = lib.mkDefault system_; + _module.args.pkgs = lib.mkIf (pkgs_ != null) (lib.mkForce pkgs_); + }; + }; + in rec { # Merge the option definitions in all modules, forming the full # system configuration. - inherit (pkgs.lib.evalModules { - inherit prefix; - modules = modules ++ extraModules ++ baseModules; + inherit (lib.evalModules { + inherit prefix check; + modules = modules ++ extraModules ++ baseModules ++ [ pkgsModule ]; args = extraArgs; - check = check && options.environment.checkConfigurationOptions.value; }) config options; # These are the extra arguments passed to every module. In @@ -33,40 +57,8 @@ in rec { # the 64-bit package anyway. However, it would be cleaner to respect # nixpkgs.config here. extraArgs = extraArgs_ // { - inherit pkgs modules baseModules; - modulesPath = ../modules; - pkgs_i686 = import ./nixpkgs.nix { system = "i686-linux"; config.allowUnfree = true; }; - utils = import ./utils.nix pkgs; + inherit modules baseModules; }; - # Import Nixpkgs, allowing the NixOS option nixpkgs.config to - # specify the Nixpkgs configuration (e.g., to set package options - # such as firefox.enableGeckoMediaPlayer, or to apply global - # overrides such as changing GCC throughout the system), and the - # option nixpkgs.system to override the platform type. This is - # tricky, because we have to prevent an infinite recursion: "pkgs" - # is passed as an argument to NixOS modules, but the value of "pkgs" - # depends on config.nixpkgs.config, which we get from the modules. - # So we call ourselves here with "pkgs" explicitly set to an - # instance that doesn't depend on nixpkgs.config. - pkgs = - if pkgs_ != null - then pkgs_ - else import ./nixpkgs.nix ( - let - system = if nixpkgsOptions.system != "" then nixpkgsOptions.system else system_; - nixpkgsOptions = (import ./eval-config.nix { - inherit system extraArgs modules prefix; - # For efficiency, leave out most NixOS modules; they don't - # define nixpkgs.config, so it's pointless to evaluate them. - baseModules = [ ../modules/misc/nixpkgs.nix ../modules/config/no-x-libs.nix ]; - pkgs = import ./nixpkgs.nix { system = system_; config = {}; }; - check = false; - }).config.nixpkgs; - in - { - inherit system; - inherit (nixpkgsOptions) config; - }); - + inherit (config._module.args) pkgs; } diff --git a/nixos/lib/make-iso9660-image.nix b/nixos/lib/make-iso9660-image.nix index 5ad546e9534d..b2409c6006bc 100644 --- a/nixos/lib/make-iso9660-image.nix +++ b/nixos/lib/make-iso9660-image.nix @@ -1,4 +1,4 @@ -{ stdenv, perl, cdrkit, pathsFromGraph +{ stdenv, perl, pathsFromGraph, xorriso, syslinux , # The file name of the resulting ISO image. isoName ? "cd.iso" @@ -22,12 +22,18 @@ , # Whether this should be an efi-bootable El-Torito CD. efiBootable ? false +, # Wheter this should be an hybrid CD (bootable from USB as well as CD). + usbBootable ? false + , # The path (in the ISO file system) of the boot image. bootImage ? "" , # The path (in the ISO file system) of the efi boot image. efiBootImage ? "" +, # The path (outside the ISO file system) of the isohybrid-mbr image. + isohybridMbrImage ? "" + , # Whether to compress the resulting ISO image with bzip2. compressImage ? false @@ -38,13 +44,14 @@ assert bootable -> bootImage != ""; assert efiBootable -> efiBootImage != ""; +assert usbBootable -> isohybridMbrImage != ""; stdenv.mkDerivation { name = "iso9660-image"; builder = ./make-iso9660-image.sh; - buildInputs = [perl cdrkit]; + buildInputs = [perl xorriso syslinux]; - inherit isoName bootable bootImage compressImage volumeID pathsFromGraph efiBootImage efiBootable; + inherit isoName bootable bootImage compressImage volumeID pathsFromGraph efiBootImage efiBootable isohybridMbrImage usbBootable; # !!! should use XML. sources = map (x: x.source) contents; diff --git a/nixos/lib/make-iso9660-image.sh b/nixos/lib/make-iso9660-image.sh index 675b5bb35148..c9a373794692 100644 --- a/nixos/lib/make-iso9660-image.sh +++ b/nixos/lib/make-iso9660-image.sh @@ -13,6 +13,20 @@ stripSlash() { if test "${res:0:1}" = /; then res=${res:1}; fi } +# Escape potential equal signs (=) with backslash (\=) +escapeEquals() { + echo "$1" | sed -e 's/\\/\\\\/g' -e 's/=/\\=/g' +} + +# Queues an file/directory to be placed on the ISO. +# An entry consists of a local source path (2) and +# a destination path on the ISO (1). +addPath() { + target="$1" + source="$2" + echo "$(escapeEquals "$target")=$(escapeEquals "$source")" >> pathlist +} + stripSlash "$bootImage"; bootImage="$res" @@ -31,11 +45,20 @@ if test -n "$bootable"; then fi done - bootFlags="-b $bootImage -c .boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table" + isoBootFlags="-eltorito-boot ${bootImage} + -eltorito-catalog .boot.cat + -no-emul-boot -boot-load-size 4 -boot-info-table" +fi + +if test -n "$usbBootable"; then + usbBootFlags="-isohybrid-mbr ${isohybridMbrImage}" fi if test -n "$efiBootable"; then - bootFlags="$bootFlags -eltorito-alt-boot -e $efiBootImage -no-emul-boot" + efiBootFlags="-eltorito-alt-boot + -e $efiBootImage + -no-emul-boot + -isohybrid-gpt-basdat" fi touch pathlist @@ -44,14 +67,14 @@ touch pathlist # Add the individual files. for ((i = 0; i < ${#targets_[@]}; i++)); do stripSlash "${targets_[$i]}" - echo "$res=${sources_[$i]}" >> pathlist + addPath "$res" "${sources_[$i]}" done # Add the closures of the top-level store objects. storePaths=$(perl $pathsFromGraph closure-*) for i in $storePaths; do - echo "${i:1}=$i" >> pathlist + addPath "${i:1}" "$i" done @@ -59,7 +82,7 @@ done # nix-store --load-db. if [ -n "$object" ]; then printRegistration=1 perl $pathsFromGraph closure-* > nix-path-registration - echo "nix-path-registration=nix-path-registration" >> pathlist + addPath "nix-path-registration" "nix-path-registration" fi @@ -70,22 +93,39 @@ for ((n = 0; n < ${#objects[*]}; n++)); do if test "$symlink" != "none"; then mkdir -p $(dirname ./$symlink) ln -s $object ./$symlink - echo "$symlink=./$symlink" >> pathlist + addPath "$symlink" "./$symlink" fi done -# !!! what does this do? -cat pathlist | sed -e 's/=\(.*\)=\(.*\)=/\\=\1=\2\\=/' | tee pathlist.safer - - mkdir -p $out/iso -genCommand="genisoimage -iso-level 4 -r -J $bootFlags -hide-rr-moved -graft-points -path-list pathlist.safer ${volumeID:+-V $volumeID}" -if test -z "$compressImage"; then - $genCommand -o $out/iso/$isoName -else - $genCommand | bzip2 > $out/iso/$isoName.bz2 + +xorriso="xorriso + -as mkisofs + -iso-level 3 + -volid ${volumeID} + -appid nixos + -publisher nixos + -graft-points + -full-iso9660-filenames + ${isoBootFlags} + ${usbBootFlags} + ${efiBootFlags} + -r + -path-list pathlist + --sort-weight 0 / + --sort-weight 1 /isolinux" # Make sure isolinux is near the beginning of the ISO + +$xorriso -output $out/iso/$isoName + +if test -n "$usbBootable"; then + echo "Making image hybrid..." + isohybrid --uefi $out/iso/$isoName fi +if test -n "$compressImage"; then + echo "Compressing image..." + bzip2 $out/iso/$isoName +fi mkdir -p $out/nix-support echo $system > $out/nix-support/system diff --git a/nixos/lib/test-driver/Machine.pm b/nixos/lib/test-driver/Machine.pm index 85c2bfa88e1a..e0791692d3ef 100644 --- a/nixos/lib/test-driver/Machine.pm +++ b/nixos/lib/test-driver/Machine.pm @@ -37,6 +37,10 @@ sub new { if defined $args->{hda}; $startCommand .= "-cdrom $args->{cdrom} " if defined $args->{cdrom}; + $startCommand .= "-device piix3-usb-uhci -drive id=usbdisk,file=$args->{usb},if=none,readonly -device usb-storage,drive=usbdisk " + if defined $args->{usb}; + $startCommand .= "-bios $args->{bios} " + if defined $args->{bios}; $startCommand .= $args->{qemuFlags} || ""; } else { $startCommand = Cwd::abs_path $startCommand; diff --git a/nixos/maintainers/scripts/ec2/amazon-hvm-install-config.nix b/nixos/maintainers/scripts/ec2/amazon-hvm-install-config.nix index 530769cec5b7..c0ec38bf489a 100644 --- a/nixos/maintainers/scripts/ec2/amazon-hvm-install-config.nix +++ b/nixos/maintainers/scripts/ec2/amazon-hvm-install-config.nix @@ -23,9 +23,9 @@ in boot.kernelParams = [ "console=ttyS0" ]; boot.initrd.extraUtilsCommands = '' - cp -v ${pkgs.gawk}/bin/gawk $out/bin/gawk - cp -v ${pkgs.gnused}/bin/sed $out/bin/gnused - cp -v ${pkgs.utillinux}/sbin/sfdisk $out/bin/sfdisk + copy_bin_and_libs ${pkgs.gawk}/bin/gawk + copy_bin_and_libs ${pkgs.gnused}/bin/sed + copy_bin_and_libs ${pkgs.utillinux}/sbin/sfdisk cp -v ${growpart} $out/bin/growpart ''; boot.initrd.postDeviceCommands = '' diff --git a/nixos/modules/config/fonts/fontconfig-ultimate.nix b/nixos/modules/config/fonts/fontconfig-ultimate.nix index 853f253ff9bc..02568f9de51e 100644 --- a/nixos/modules/config/fonts/fontconfig-ultimate.nix +++ b/nixos/modules/config/fonts/fontconfig-ultimate.nix @@ -1,6 +1,6 @@ -{ config, pkgs, ... }: +{ config, pkgs, lib, ... }: -with pkgs.lib; +with lib; let fcBool = x: if x then "<bool>true</bool>" else "<bool>false</bool>"; in diff --git a/nixos/modules/config/no-x-libs.nix b/nixos/modules/config/no-x-libs.nix index 47393c9d3f5c..13477337bda5 100644 --- a/nixos/modules/config/no-x-libs.nix +++ b/nixos/modules/config/no-x-libs.nix @@ -27,6 +27,6 @@ with lib; fonts.fontconfig.enable = false; nixpkgs.config.packageOverrides = pkgs: - { dbus = pkgs.dbus.override { useX11 = false; }; }; + { dbus = pkgs.dbus.override { x11Support = false; }; }; }; } diff --git a/nixos/modules/config/nsswitch.nix b/nixos/modules/config/nsswitch.nix index 549e731f3b08..a39c2895bf84 100644 --- a/nixos/modules/config/nsswitch.nix +++ b/nixos/modules/config/nsswitch.nix @@ -8,6 +8,7 @@ let inherit (config.services.avahi) nssmdns; inherit (config.services.samba) nsswins; + ldap = config.users.ldap.enable; in @@ -40,9 +41,9 @@ in # should define an option used by this module. environment.etc."nsswitch.conf".text = '' - passwd: files ldap - group: files ldap - shadow: files ldap + passwd: files ${optionalString ldap "ldap"} + group: files ${optionalString ldap "ldap"} + shadow: files ${optionalString ldap "ldap"} hosts: files ${optionalString nssmdns "mdns_minimal [NOTFOUND=return]"} dns ${optionalString nssmdns "mdns"} ${optionalString nsswins "wins"} myhostname mymachines networks: files dns ethers: files diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix index 8b38489a8c19..c41e4ea604d5 100644 --- a/nixos/modules/config/pulseaudio.nix +++ b/nixos/modules/config/pulseaudio.nix @@ -124,9 +124,7 @@ in { } (mkIf cfg.enable { - environment.systemPackages = [ - cfg.package - ] ++ lib.optionals enable32BitAlsaPlugins [ pkgs_i686.pulseaudio ]; + environment.systemPackages = [ cfg.package ]; environment.etc = singleton { target = "asound.conf"; diff --git a/nixos/modules/config/sysctl.nix b/nixos/modules/config/sysctl.nix index 3b6ccd380c75..e83562a8356e 100644 --- a/nixos/modules/config/sysctl.nix +++ b/nixos/modules/config/sysctl.nix @@ -64,6 +64,6 @@ in # # Removed under grsecurity. boot.kernel.sysctl."kernel.kptr_restrict" = - if config.security.grsecurity.enable then null else 1; + if (config.boot.kernelPackages.kernel.features.grsecurity or false) then null else 1; }; } diff --git a/nixos/modules/config/update-users-groups.pl b/nixos/modules/config/update-users-groups.pl index d35ecb754bdb..de73de91629b 100644 --- a/nixos/modules/config/update-users-groups.pl +++ b/nixos/modules/config/update-users-groups.pl @@ -174,12 +174,12 @@ foreach my $u (@{$spec->{users}}) { } elsif (defined $u->{initialHashedPassword}) { $u->{hashedPassword} = $u->{initialHashedPassword}; } + } - # Create a home directory. - if ($u->{createHome}) { - make_path($u->{home}, { mode => 0700 }) if ! -e $u->{home}; - chown $u->{uid}, $u->{gid}, $u->{home}; - } + # Create a home directory. + if ($u->{createHome} && ! -e $u->{home}) { + make_path($u->{home}, { mode => 0700 }) if ! -e $u->{home}; + chown $u->{uid}, $u->{gid}, $u->{home}; } if (defined $u->{passwordFile}) { diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index f585a2774799..9d48edf2f26c 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -110,7 +110,7 @@ let shell = mkOption { type = types.str; - default = "/run/current-system/sw/sbin/nologin"; + default = "/run/current-system/sw/bin/nologin"; description = "The path to the user's shell."; }; @@ -489,6 +489,7 @@ in { utmp.gid = ids.gids.utmp; adm.gid = ids.gids.adm; grsecurity.gid = ids.gids.grsecurity; + input.gid = ids.gids.input; }; system.activationScripts.users = stringAfter [ "etc" ] diff --git a/nixos/modules/hardware/cpu/amd-microcode.nix b/nixos/modules/hardware/cpu/amd-microcode.nix index 86a3df5da21d..d44f01a49590 100644 --- a/nixos/modules/hardware/cpu/amd-microcode.nix +++ b/nixos/modules/hardware/cpu/amd-microcode.nix @@ -22,8 +22,7 @@ with lib; ###### implementation config = mkIf config.hardware.cpu.amd.updateMicrocode { - hardware.firmware = [ "${pkgs.amdUcode}/lib/firmware" ]; - boot.kernelModules = [ "microcode" ]; + boot.initrd.prepend = [ "${pkgs.microcodeAmd}/amd-ucode.img" ]; }; } diff --git a/nixos/modules/hardware/cpu/intel-microcode.nix b/nixos/modules/hardware/cpu/intel-microcode.nix index 800c391b293a..89ae4f45806c 100644 --- a/nixos/modules/hardware/cpu/intel-microcode.nix +++ b/nixos/modules/hardware/cpu/intel-microcode.nix @@ -22,8 +22,7 @@ with lib; ###### implementation config = mkIf config.hardware.cpu.intel.updateMicrocode { - hardware.firmware = [ "${pkgs.microcodeIntel}/lib/firmware" ]; - boot.kernelModules = [ "microcode" ]; + boot.initrd.prepend = [ "${pkgs.microcodeIntel}/intel-ucode.img" ]; }; } diff --git a/nixos/modules/hardware/ksm.nix b/nixos/modules/hardware/ksm.nix new file mode 100644 index 000000000000..d6ac69b5d65e --- /dev/null +++ b/nixos/modules/hardware/ksm.nix @@ -0,0 +1,18 @@ +{ config, lib, ... }: + +{ + options.hardware.enableKSM = lib.mkEnableOption "Kernel Same-Page Merging"; + + config = lib.mkIf config.hardware.enableKSM { + systemd.services.enable-ksm = { + description = "Enable Kernel Same-Page Merging"; + wantedBy = [ "multi-user.target" ]; + after = [ "systemd-udev-settle.service" ]; + script = '' + if [ -e /sys/kernel/mm/ksm ]; then + echo 1 > /sys/kernel/mm/ksm/run + fi + ''; + }; + }; +} diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix index 2b20dc7395af..711576982ec3 100644 --- a/nixos/modules/hardware/video/nvidia.nix +++ b/nixos/modules/hardware/video/nvidia.nix @@ -13,7 +13,7 @@ let # driver. nvidiaForKernel = kernelPackages: if elem "nvidia" drivers then - kernelPackages.nvidia_x11 + kernelPackages.nvidia_x11 else if elem "nvidiaLegacy173" drivers then kernelPackages.nvidia_x11_legacy173 else if elem "nvidiaLegacy304" drivers then @@ -47,6 +47,15 @@ in boot.extraModulePackages = [ nvidia_x11 ]; + # nvidia-uvm is required by CUDA applications. + boot.kernelModules = [ "nvidia-uvm" ]; + + # Create /dev/nvidia-uvm when the nvidia-uvm module is loaded. + services.udev.extraRules = + '' + KERNEL=="nvidia_uvm", RUN+="${pkgs.stdenv.shell} -c 'mknod -m 666 /dev/nvidia-uvm c $(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 0'" + ''; + boot.blacklistedKernelModules = [ "nouveau" "nvidiafb" ]; services.acpid.enable = true; diff --git a/nixos/modules/installer/cd-dvd/installation-cd-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-base.nix index b723a91e4f35..4896eee29084 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-base.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-base.nix @@ -36,6 +36,9 @@ with lib; # EFI booting isoImage.makeEfiBootable = true; + # USB booting + isoImage.makeUsbBootable = true; + # Add Memtest86+ to the CD. boot.loader.grub.memtest86.enable = true; diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index 39db7d9b8f72..d9d7254aba25 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -7,66 +7,89 @@ with lib; let - - # The Grub image. - grubImage = pkgs.runCommand "grub_eltorito" {} + # Timeout in syslinux is in units of 1/10 of a second. + # 0 is used to disable timeouts. + syslinuxTimeout = if config.boot.loader.timeout == null then + 0 + else + max (config.boot.loader.timeout * 10) 1; + + + max = x: y: if x > y then x else y; + + # The configuration file for syslinux. + + # Notes on syslinux configuration and UNetbootin compatiblity: + # * Do not use '/syslinux/syslinux.cfg' as the path for this + # configuration. UNetbootin will not parse the file and use it as-is. + # This results in a broken configuration if the partition label does + # not match the specified config.isoImage.volumeID. For this reason + # we're using '/isolinux/isolinux.cfg'. + # * Use APPEND instead of adding command-line arguments directly after + # the LINUX entries. + # * COM32 entries (chainload, reboot, poweroff) are not recognized. They + # result in incorrect boot entries. + + baseIsolinuxCfg = '' - ${pkgs.grub2}/bin/grub-mkimage -p /boot/grub -O i386-pc -o tmp biosdisk iso9660 help linux linux16 chain png jpeg echo gfxmenu reboot - cat ${pkgs.grub2}/lib/grub/*/cdboot.img tmp > $out - ''; # */ - - - # The configuration file for Grub. - grubCfg = - '' - set default=${builtins.toString config.boot.loader.grub.default} - set timeout=${builtins.toString config.boot.loader.grub.timeout} - - if loadfont /boot/grub/unicode.pf2; then - set gfxmode=640x480 - insmod gfxterm - insmod vbe - terminal_output gfxterm - - insmod png - if background_image /boot/grub/splash.png; then - set color_normal=white/black - set color_highlight=black/white - else - set menu_color_normal=cyan/blue - set menu_color_highlight=white/blue - fi - - fi - - ${config.boot.loader.grub.extraEntries} + SERIAL 0 38400 + TIMEOUT ${builtins.toString syslinuxTimeout} + UI vesamenu.c32 + MENU TITLE NixOS + MENU BACKGROUND /isolinux/background.png + DEFAULT boot + + LABEL boot + MENU LABEL NixOS ${config.system.nixosVersion} Installer + LINUX /boot/bzImage + APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} + INITRD /boot/initrd ''; + isolinuxMemtest86Entry = '' + LABEL memtest + MENU LABEL Memtest86+ + LINUX /boot/memtest.bin + APPEND ${toString config.boot.loader.grub.memtest86.params} + ''; + + isolinuxCfg = baseIsolinuxCfg + (optionalString config.boot.loader.grub.memtest86.enable isolinuxMemtest86Entry); # 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/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 "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 echo "default nixos-livecd" > $out/loader/loader.conf - echo "timeout 5" >> $out/loader/loader.conf + echo "timeout ${builtins.toString config.boot.loader.gummiboot.timeout}" >> $out/loader/loader.conf ''; - efiImg = pkgs.runCommand "efi-image_eltorito" { buildInputs = [ pkgs.mtools ]; } + efiImg = pkgs.runCommand "efi-image_eltorito" { buildInputs = [ pkgs.mtools pkgs.libfaketime ]; } + # Be careful about determinism: du --apparent-size, + # dates (cp -p, touch, mcopy -m, faketime for label), IDs (mkfs.vfat -i) '' - #Let's hope 15M is enough - dd bs=2048 count=7680 if=/dev/zero of="$out" - ${pkgs.dosfstools}/sbin/mkfs.vfat "$out" - mcopy -svi "$out" ${efiDir}/* :: - mmd -i "$out" boot - mcopy -v -i "$out" \ - ${config.boot.kernelPackages.kernel}/bzImage ::boot/bzImage - mcopy -v -i "$out" \ - ${config.system.build.initialRamdisk}/initrd ::boot/initrd + mkdir ./contents && cd ./contents + cp -rp "${efiDir}"/* . + mkdir ./boot + cp -p "${config.boot.kernelPackages.kernel}/bzImage" \ + "${config.system.build.initialRamdisk}/initrd" ./boot/ + touch --date=@0 ./* + + usage_size=$(du -sb --apparent-size . | tr -cd '[:digit:]') + # Make the image 110% as big as the files need to make up for FAT overhead + image_size=$(( ($usage_size * 110) / 100 )) + # Make the image fit blocks of 1M + block_size=$((1024*1024)) + image_size=$(( ($image_size / $block_size + 1) * $block_size )) + echo "Usage size: $usage_size" + echo "Image size: $image_size" + truncate --size=$image_size "$out" + ${pkgs.libfaketime}/bin/faketime "2000-01-01 00:00:00" ${pkgs.dosfstools}/sbin/mkfs.vfat -i 12345678 -n EFIBOOT "$out" + mcopy -bpsvm -i "$out" ./* :: ''; # */ targetArch = if pkgs.stdenv.isi686 then @@ -152,9 +175,24 @@ in ''; }; + isoImage.makeUsbBootable = mkOption { + default = false; + description = '' + Whether the ISO image should be bootable from CD as well as USB. + ''; + }; - }; + isoImage.splashImage = mkOption { + default = pkgs.fetchurl { + url = https://raw.githubusercontent.com/NixOS/nixos-artwork/5729ab16c6a5793c10a2913b5a1b3f59b91c36ee/ideas/grub-splash/grub-nixos-1.png; + sha256 = "43fd8ad5decf6c23c87e9026170a13588c2eba249d9013cb9f888da5e2002217"; + }; + description = '' + The splash image to use in the bootloader. + ''; + }; + }; config = { @@ -166,7 +204,7 @@ in # !!! Hack - attributes expected by other modules. system.boot.loader.kernelFile = "bzImage"; - environment.systemPackages = [ pkgs.grub2 ]; + environment.systemPackages = [ pkgs.grub2 pkgs.syslinux ]; # 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 @@ -216,7 +254,7 @@ in options = "allow_other,cow,nonempty,chroot=/mnt-root,max_files=32768,hide_meta_files,dirs=/nix/.rw-store=rw:/nix/.ro-store=ro"; }; - boot.initrd.availableKernelModules = [ "squashfs" "iso9660" ]; + boot.initrd.availableKernelModules = [ "squashfs" "iso9660" "usb-storage" ]; boot.initrd.kernelModules = [ "loop" ]; @@ -236,15 +274,12 @@ in # Individual files to be included on the CD, outside of the Nix # store on the CD. isoImage.contents = - [ { source = grubImage; - target = "/boot/grub/grub_eltorito"; - } - { source = pkgs.substituteAll { - name = "grub.cfg"; - src = pkgs.writeText "grub.cfg-in" grubCfg; + [ { source = pkgs.substituteAll { + name = "isolinux.cfg"; + src = pkgs.writeText "isolinux.cfg-in" isolinuxCfg; bootRoot = "/boot"; }; - target = "/boot/grub/grub.cfg"; + target = "/isolinux/isolinux.cfg"; } { source = config.boot.kernelPackages.kernel + "/bzImage"; target = "/boot/bzImage"; @@ -252,51 +287,44 @@ in { source = config.system.build.initialRamdisk + "/initrd"; target = "/boot/initrd"; } - { source = "${pkgs.grub2}/share/grub/unicode.pf2"; - target = "/boot/grub/unicode.pf2"; - } - { source = config.boot.loader.grub.splashImage; - target = "/boot/grub/splash.png"; - } { source = config.system.build.squashfsStore; target = "/nix-store.squashfs"; } + { source = "${pkgs.syslinux}/share/syslinux"; + target = "/isolinux"; + } + { source = config.isoImage.splashImage; + target = "/isolinux/background.png"; + } ] ++ optionals config.isoImage.makeEfiBootable [ { source = efiImg; target = "/boot/efi.img"; } - { source = "${efiDir}/efi"; - target = "/efi"; + { source = "${efiDir}/EFI"; + target = "/EFI"; } { source = "${efiDir}/loader"; target = "/loader"; } - ] ++ mapAttrsToList (n: v: { source = v; target = "/boot/${n}"; }) config.boot.loader.grub.extraFiles; - - # The Grub menu. - boot.loader.grub.extraEntries = - '' - menuentry "NixOS ${config.system.nixosVersion} Installer" { - linux /boot/bzImage init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} - initrd /boot/initrd - } - - menuentry "Boot from hard disk" { - set root=(hd0) - chainloader +1 + ] ++ optionals config.boot.loader.grub.memtest86.enable [ + { source = "${pkgs.memtest86plus}/memtest.bin"; + target = "/boot/memtest.bin"; } - ''; + ]; - boot.loader.grub.timeout = 10; + boot.loader.timeout = 10; # Create the ISO image. system.build.isoImage = import ../../../lib/make-iso9660-image.nix ({ - inherit (pkgs) stdenv perl cdrkit pathsFromGraph; + inherit (pkgs) stdenv perl pathsFromGraph xorriso syslinux; inherit (config.isoImage) isoName compressImage volumeID contents; bootable = true; - bootImage = "/boot/grub/grub_eltorito"; + bootImage = "/isolinux/isolinux.bin"; + } // optionalAttrs config.isoImage.makeUsbBootable { + usbBootable = true; + isohybridMbrImage = "${pkgs.syslinux}/share/syslinux/isohdpfx.bin"; } // optionalAttrs config.isoImage.makeEfiBootable { efiBootable = true; efiBootImage = "boot/efi.img"; diff --git a/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix b/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix index 4ce7582c166a..46dc1c705022 100644 --- a/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix +++ b/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix @@ -98,7 +98,7 @@ in boot.initrd.extraUtilsCommands = '' - cp ${pkgs.utillinux}/sbin/hwclock $out/bin + copy_bin_and_libs ${pkgs.utillinux}/sbin/hwclock ''; boot.initrd.postDeviceCommands = diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl index 43a83e0206de..eadaae6715b4 100644 --- a/nixos/modules/installer/tools/nixos-generate-config.pl +++ b/nixos/modules/installer/tools/nixos-generate-config.pl @@ -148,7 +148,7 @@ sub pciCheck { $device eq "0x4331" || $device eq "0x43a0" || $device eq "0x43b1" ) ) { - push @modulePackages, "config.boot.kernelPackages.broadcom_sta"; + push @modulePackages, "\${config.boot.kernelPackages.broadcom_sta}"; push @kernelModules, "wl"; } diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh index bfb42d40b06e..14ae3daace0b 100644 --- a/nixos/modules/installer/tools/nixos-install.sh +++ b/nixos/modules/installer/tools/nixos-install.sh @@ -28,9 +28,14 @@ chrootCommand=(/run/current-system/sw/bin/bash) while [ "$#" -gt 0 ]; do i="$1"; shift 1 case "$i" in - -I) - given_path="$1"; shift 1 - extraBuildFlags+=("$i" "$given_path") + --max-jobs|-j|--cores|-I) + j="$1"; shift 1 + extraBuildFlags+=("$i" "$j") + ;; + --option) + j="$1"; shift 1 + k="$1"; shift 1 + extraBuildFlags+=("$i" "$j" "$k") ;; --root) mountPoint="$1"; shift 1 diff --git a/nixos/modules/installer/tools/nixos-rebuild.sh b/nixos/modules/installer/tools/nixos-rebuild.sh index 8157f8fc7da5..1d6df8cb3f71 100644 --- a/nixos/modules/installer/tools/nixos-rebuild.sh +++ b/nixos/modules/installer/tools/nixos-rebuild.sh @@ -26,7 +26,8 @@ while [ "$#" -gt 0 ]; do --help) showSyntax ;; - switch|boot|test|build|dry-run|build-vm|build-vm-with-bootloader) + switch|boot|test|build|dry-build|dry-run|dry-activate|build-vm|build-vm-with-bootloader) + if [ "$i" = dry-run ]; then i=dry-build; fi action="$i" ;; --install-grub) @@ -137,7 +138,7 @@ fi # First build Nix, since NixOS may require a newer version than the # current one. -if [ -n "$rollback" -o "$action" = dry-run ]; then +if [ -n "$rollback" -o "$action" = dry-build ]; then buildNix= fi @@ -180,7 +181,7 @@ if [ -n "$canRun" ]; then fi -if [ "$action" = dry-run ]; then +if [ "$action" = dry-build ]; then extraBuildFlags+=(--dry-run) fi @@ -193,7 +194,7 @@ if [ -z "$rollback" ]; then if [ "$action" = switch -o "$action" = boot ]; then nix-env "${extraBuildFlags[@]}" -p "$profile" -f '<nixpkgs/nixos>' --set -A system pathToConfig="$profile" - elif [ "$action" = test -o "$action" = build -o "$action" = dry-run ]; then + elif [ "$action" = test -o "$action" = build -o "$action" = dry-build -o "$action" = dry-activate ]; then nix-build '<nixpkgs/nixos>' -A system -k "${extraBuildFlags[@]}" > /dev/null pathToConfig=./result elif [ "$action" = build-vm ]; then @@ -224,7 +225,7 @@ fi # If we're not just building, then make the new configuration the boot # default and/or activate it now. -if [ "$action" = switch -o "$action" = boot -o "$action" = test ]; then +if [ "$action" = switch -o "$action" = boot -o "$action" = test -o "$action" = dry-activate ]; then if ! $pathToConfig/bin/switch-to-configuration "$action"; then echo "warning: error(s) occured while switching to the new configuration" >&2 exit 1 diff --git a/nixos/modules/misc/check-config.nix b/nixos/modules/misc/check-config.nix deleted file mode 100644 index e9803de21961..000000000000 --- a/nixos/modules/misc/check-config.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ lib, ... }: - -with lib; - -{ - options = { - environment.checkConfigurationOptions = mkOption { - type = types.bool; - default = true; - description = '' - Whether to check the validity of the entire configuration. - ''; - }; - }; -} diff --git a/nixos/modules/misc/extra-arguments.nix b/nixos/modules/misc/extra-arguments.nix new file mode 100644 index 000000000000..c2c8903546d5 --- /dev/null +++ b/nixos/modules/misc/extra-arguments.nix @@ -0,0 +1,14 @@ +{ lib, pkgs, config, ... }: + +{ + _module.args = { + modulesPath = ../.; + + pkgs_i686 = import ../../lib/nixpkgs.nix { + system = "i686-linux"; + config.allowUnfree = true; + }; + + utils = import ../../lib/utils.nix pkgs; + }; +} diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 0c863ec8de1c..c2523a3cc329 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -27,28 +27,38 @@ ids.uids = { root = 0; - nscd = 1; - sshd = 2; - ntp = 3; + #wheel = 1; # unused + #kmem = 2; # unused + #tty = 3; # unused messagebus = 4; # D-Bus haldaemon = 5; - nagios = 6; + #disk = 6; # unused vsftpd = 7; ftp = 8; bitlbee = 9; avahi = 10; + nagios = 11; atd = 12; - zabbix = 13; - postfix = 14; + postfix = 13; + #postdrop = 14; # unused dovecot = 15; tomcat = 16; + #audio = 17; # unused + #floppy = 18; # unused + #uucp = 19; # unused + #lp = 20; # unused pulseaudio = 22; # must match `pulseaudio' GID gpsd = 23; + #cdrom = 24; # unused + #tape = 25; # unused + #video = 26; # unused + #dialout = 27; # unused polkituser = 28; - uptimed = 29; + #utmp = 29; # unused ddclient = 30; davfs2 = 31; privoxy = 32; + #disnix = 33; # unused osgi = 34; tor = 35; cups = 36; @@ -70,18 +80,25 @@ fprot = 52; bind = 53; wwwrun = 54; + #adm = 55; # unused spamd = 56; + #networkmanager = 57; # unused nslcd = 58; + #scanner = 59; # unused nginx = 60; chrony = 61; + #systemd-journal = 62; # unused smtpd = 63; smtpq = 64; supybot = 65; iodined = 66; + #libvirtd = 67; # unused graphite = 68; statsd = 69; transmission = 70; postgres = 71; + #vboxusers = 72; # unused + #vboxsf = 73; # unused smbguest = 74; # unused varnish = 75; datadog = 76; @@ -102,13 +119,13 @@ minidlna = 91; elasticsearch = 92; tcpcryptd = 93; # tcpcryptd uses a hard-coded uid. We patch it in Nixpkgs to match this choice. - zope2 = 94; + #connman = 94; # unused firebird = 95; - redis = 96; + #keys = 96; # unused haproxy = 97; mongodb = 98; openldap = 99; - memcached = 100; + #users = 100; # unused cgminer = 101; munin = 102; logcheck = 103; @@ -129,6 +146,7 @@ foundationdb = 118; newrelic = 119; starbound = 120; + #grsecurity = 121; # unused hydra = 122; spiped = 123; teamspeak = 124; @@ -138,7 +156,7 @@ znc = 128; polipo = 129; mopidy = 130; - unifi = 131; + #docker = 131; # unused gdm = 132; dhcpd = 133; siproxd = 134; @@ -180,6 +198,22 @@ panamax = 170; marathon = 171; exim = 172; + #fleet = 173; # unused + #input = 174; # unused + sddm = 175; + tss = 176; + memcached = 177; + nscd = 178; + ntp = 179; + zabbix = 180; + redis = 181; + sshd = 182; + unifi = 183; + uptimed = 184; + zope2 = 185; + ripple-data-api = 186; + mediatomb = 187; + rdnssd = 188; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -199,15 +233,16 @@ ftp = 8; bitlbee = 9; avahi = 10; + #nagios = 11; # unused atd = 12; postfix = 13; postdrop = 14; dovecot = 15; + tomcat = 16; audio = 17; floppy = 18; uucp = 19; lp = 20; - tomcat = 21; pulseaudio = 22; # must match `pulseaudio' UID gpsd = 23; cdrom = 24; @@ -216,21 +251,30 @@ dialout = 27; #polkituser = 28; # currently unused, polkitd doesn't need a group utmp = 29; + #ddclient = 30; # unused davfs2 = 31; privoxy = 32; disnix = 33; osgi = 34; tor = 35; - ghostOne = 40; + #cups = 36; # unused + #foldingathome = 37; # unused + #sabnzd = 38; # unused + #kdm = 39; # unused + ghostone = 40; git = 41; fourstore = 42; - fourstorehttpd = 43; + fourstorehttp = 43; virtuoso = 44; + #rtkit = 45; # unused dovecot2 = 46; + #dovenull = 47; # unused + #unbound = 48; # unused prayer = 49; mpd = 50; clamav = 51; fprot = 52; + #bind = 53; # unused wwwrun = 54; adm = 55; spamd = 56; @@ -238,6 +282,7 @@ nslcd = 58; scanner = 59; nginx = 60; + #chrony = 61; # unused systemd-journal = 62; smtpd = 63; smtpq = 64; @@ -245,6 +290,7 @@ iodined = 66; libvirtd = 67; graphite = 68; + #statsd = 69; # unused transmission = 70; postgres = 71; vboxusers = 72; @@ -267,11 +313,17 @@ quassel = 89; amule = 90; minidlna = 91; - haproxy = 92; - openldap = 93; + #elasticsearch = 92; # unused + #tcpcryptd = 93; # unused connman = 94; - munin = 95; + firebird = 95; keys = 96; + haproxy = 97; + #mongodb = 98; # unused + openldap = 99; + munin = 102; + #logcheck = 103; # unused + #nix-ssh = 104; # unused dictd = 105; couchdb = 106; searx = 107; @@ -279,8 +331,12 @@ jenkins = 109; systemd-journal-gateway = 110; notbit = 111; + #ngircd = 112; # unused btsync = 113; + #minecraft = 114; # unused monetdb = 115; + #ripped = 116; # unused + #murmur = 117; # unused foundationdb = 118; newrelic = 119; starbound = 120; @@ -290,37 +346,65 @@ teamspeak = 124; influxdb = 125; nsd = 126; - firebird = 127; + #gitolite = 127; # unused znc = 128; polipo = 129; mopidy = 130; docker = 131; gdm = 132; - tss = 133; + #dhcpcd = 133; # unused siproxd = 134; mlmmj = 135; + #neo4j = 136; # unused riemann = 137; riemanndash = 138; - hbase = 139; - opentsdb = 140; + #radvd = 139; # unused + #zookeeper = 140; # unused + #dnsmasq = 141; # unused uhub = 142; + #yandexdisk = 143; # unused + #collectd = 144; # unused + #consul = 145; # unused mailpile = 146; redmine = 147; seeks = 148; prosody = 149; i2pd = 150; + #dnscrypt-proxy = 151; # unused systemd-network = 152; systemd-resolve = 153; systemd-timesync = 154; liquidsoap = 155; - fleet = 159; + #etcd = 156; # unused + #docker-registry = 157; # unused + hbase = 158; + opentsdb = 159; scollector = 160; bosun = 161; kubernetes = 162; + #peerflix = 163; # unused + #chronos = 164; # unused gitlab = 165; - nylon = 166; + nylon = 168; panamax = 170; + #marathon = 171; # unused exim = 172; + fleet = 173; + input = 174; + sddm = 175; + tss = 176; + #memcached = 177; # unused + #nscd = 178; # unused + #ntp = 179; # unused + #zabbix = 180; # unused + #redis = 181; # unused + #sshd = 182; # unused + #unifi = 183; # unused + #uptimed = 184; # unused + #zope2 = 185; # unused + #ripple-data-api = 186; #unused + mediatomb = 187; + #rdnssd = 188; # unused # 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/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix index f41c8817ba4a..114feb2562db 100644 --- a/nixos/modules/misc/nixpkgs.nix +++ b/nixos/modules/misc/nixpkgs.nix @@ -59,7 +59,8 @@ in }; nixpkgs.system = mkOption { - type = types.str; + type = types.uniq types.str; + example = "i686-linux"; description = '' Specifies the Nix platform type for which NixOS should be built. If unset, it defaults to the platform type of your host system. @@ -71,6 +72,10 @@ in }; config = { - nixpkgs.system = mkDefault pkgs.stdenv.system; + _module.args.pkgs = import ../../lib/nixpkgs.nix { + system = config.nixpkgs.system; + + inherit (config.nixpkgs) config; + }; }; } diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index c41ae69c1ace..17717c5988dc 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -29,6 +29,7 @@ ./hardware/all-firmware.nix ./hardware/cpu/amd-microcode.nix ./hardware/cpu/intel-microcode.nix + ./hardware/ksm.nix ./hardware/network/b43.nix ./hardware/network/intel-2100bg.nix ./hardware/network/intel-2200bg.nix @@ -43,8 +44,8 @@ ./installer/tools/nixos-checkout.nix ./installer/tools/tools.nix ./misc/assertions.nix - ./misc/check-config.nix ./misc/crashdump.nix + ./misc/extra-arguments.nix ./misc/ids.nix ./misc/lib.nix ./misc/locate.nix @@ -60,6 +61,7 @@ ./programs/dconf.nix ./programs/environment.nix ./programs/info.nix + ./programs/ibus.nix ./programs/light.nix ./programs/nano.nix ./programs/screen.nix @@ -90,8 +92,9 @@ ./services/amqp/activemq/default.nix ./services/amqp/rabbitmq.nix ./services/audio/alsa.nix - # Disabled as fuppes it does no longer builds. + # Disabled as fuppes no longer builds. # ./services/audio/fuppes.nix + ./services/audio/icecast.nix ./services/audio/liquidsoap.nix ./services/audio/mpd.nix ./services/audio/mopidy.nix @@ -108,6 +111,7 @@ ./services/cluster/panamax.nix ./services/computing/torque/server.nix ./services/computing/torque/mom.nix + ./services/computing/slurm/slurm.nix ./services/continuous-integration/jenkins/default.nix ./services/continuous-integration/jenkins/slave.nix ./services/databases/4store-endpoint.nix @@ -143,6 +147,7 @@ ./services/desktops/telepathy.nix ./services/games/ghost-one.nix ./services/games/minecraft-server.nix + ./services/games/minetest-server.nix ./services/hardware/acpid.nix ./services/hardware/amd-hybrid-graphics.nix ./services/hardware/bluetooth.nix @@ -158,6 +163,7 @@ ./services/hardware/udisks2.nix ./services/hardware/upower.nix ./services/hardware/thermald.nix + ./services/logging/fluentd.nix ./services/logging/klogd.nix ./services/logging/logcheck.nix ./services/logging/logrotate.nix @@ -187,6 +193,7 @@ ./services/misc/gitlab.nix ./services/misc/gitolite.nix ./services/misc/gpsd.nix + ./services/misc/mediatomb.nix ./services/misc/mesos-master.nix ./services/misc/mesos-slave.nix ./services/misc/nix-daemon.nix @@ -197,6 +204,7 @@ ./services/misc/phd.nix ./services/misc/redmine.nix ./services/misc/rippled.nix + ./services/misc/ripple-data-api.nix ./services/misc/rogue.nix ./services/misc/siproxd.nix ./services/misc/svnserve.nix @@ -218,6 +226,7 @@ ./services/monitoring/smartd.nix ./services/monitoring/statsd.nix ./services/monitoring/systemhealth.nix + ./services/monitoring/teamviewer.nix ./services/monitoring/ups.nix ./services/monitoring/uptime.nix ./services/monitoring/zabbix-agent.nix @@ -228,7 +237,9 @@ ./services/network-filesystems/rsyncd.nix ./services/network-filesystems/samba.nix ./services/network-filesystems/diod.nix + ./services/network-filesystems/u9fs.nix ./services/network-filesystems/yandex-disk.nix + ./services/networking/aiccu.nix ./services/networking/amuled.nix ./services/networking/atftpd.nix ./services/networking/avahi-daemon.nix @@ -325,6 +336,7 @@ ./services/security/fprot.nix ./services/security/frandom.nix ./services/security/haveged.nix + ./services/security/munge.nix ./services/security/torify.nix ./services/security/tor.nix ./services/security/torsocks.nix @@ -352,12 +364,14 @@ ./services/web-servers/varnish/default.nix ./services/web-servers/winstone.nix ./services/web-servers/zope2.nix + ./services/x11/unclutter.nix ./services/x11/desktop-managers/default.nix ./services/x11/display-managers/auto.nix ./services/x11/display-managers/default.nix ./services/x11/display-managers/gdm.nix ./services/x11/display-managers/kdm.nix ./services/x11/display-managers/lightdm.nix + ./services/x11/display-managers/sddm.nix ./services/x11/display-managers/slim.nix ./services/x11/hardware/multitouch.nix ./services/x11/hardware/synaptics.nix @@ -432,5 +446,5 @@ ./virtualisation/openvswitch.nix ./virtualisation/parallels-guest.nix ./virtualisation/virtualbox-guest.nix - #./virtualisation/xen-dom0.nix + ./virtualisation/xen-dom0.nix ] diff --git a/nixos/modules/programs/ibus.nix b/nixos/modules/programs/ibus.nix new file mode 100644 index 000000000000..b8702a743d8a --- /dev/null +++ b/nixos/modules/programs/ibus.nix @@ -0,0 +1,51 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.programs.ibus; +in +{ + options = { + + programs.ibus = { + enable = mkOption { + type = types.bool; + default = false; + example = true; + description = "Enable IBus input method"; + }; + plugins = mkOption { + type = lib.types.listOf lib.types.path; + default = []; + description = '' + IBus plugin packages + ''; + }; + }; + + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.ibus ]; + + gtkPlugins = [ pkgs.ibus ]; + qtPlugins = [ pkgs.ibus-qt ]; + + environment.variables = + let + env = pkgs.buildEnv { + name = "ibus-env"; + paths = [ pkgs.ibus ] ++ cfg.plugins; + }; + in { + GTK_IM_MODULE = "ibus"; + QT_IM_MODULE = "ibus"; + XMODIFIERS = "@im=ibus"; + + IBUS_COMPONENT_PATH = "${env}/share/ibus/component"; + }; + + services.xserver.displayManager.sessionCommands = "${pkgs.ibus}/bin/ibus-daemon --daemonize --xim --cache=none"; + }; +} diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix index 5c2ea07c5549..895ecb122cb6 100644 --- a/nixos/modules/programs/shadow.nix +++ b/nixos/modules/programs/shadow.nix @@ -100,7 +100,7 @@ in chgpasswd = { rootOK = true; }; }; - security.setuidPrograms = [ "passwd" "chfn" "su" "newgrp" + security.setuidPrograms = [ "passwd" "chfn" "su" "sg" "newgrp" "newuidmap" "newgidmap" # new in shadow 4.2.x ]; diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix index 796740ea636a..6ca73eea5f6f 100644 --- a/nixos/modules/programs/ssh.nix +++ b/nixos/modules/programs/ssh.nix @@ -4,8 +4,19 @@ with lib; -let cfg = config.programs.ssh; - cfgd = config.services.openssh; +let + + cfg = config.programs.ssh; + cfgd = config.services.openssh; + + askPassword = cfg.askPassword; + + askPasswordWrapper = pkgs.writeScript "ssh-askpass-wrapper" + '' + #! ${pkgs.stdenv.shell} -e + export DISPLAY="$(systemctl --user show-environment | ${pkgs.gnused}/bin/sed 's/^DISPLAY=\(.*\)/\1/; t; d')" + exec ${askPassword} + ''; in { @@ -15,6 +26,12 @@ in programs.ssh = { + askPassword = mkOption { + type = types.string; + default = "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass"; + description = ''Program used by SSH to ask for passwords.''; + }; + forwardX11 = mkOption { type = types.bool; default = false; @@ -117,6 +134,11 @@ in Restart = "on-failure"; SuccessExitStatus = "0 2"; }; + # Allow ssh-agent to ask for confirmation. This requires the + # unit to know about the user's $DISPLAY (via ‘systemctl + # import-environment’). + environment.SSH_ASKPASS = optionalString config.services.xserver.enable askPasswordWrapper; + environment.DISPLAY = "fake"; # required to make ssh-agent start $SSH_ASKPASS }; environment.extraInit = optionalString cfg.startAgent @@ -126,5 +148,10 @@ in fi ''; + environment.interactiveShellInit = optionalString config.services.xserver.enable + '' + export SSH_ASKPASS=${askPassword} + ''; + }; } diff --git a/nixos/modules/programs/uim.nix b/nixos/modules/programs/uim.nix index fc25ba6f9694..4bf2f9a17571 100644 --- a/nixos/modules/programs/uim.nix +++ b/nixos/modules/programs/uim.nix @@ -7,14 +7,16 @@ let in { options = { + uim = { enable = mkOption { type = types.bool; default = false; example = true; - description = "enable UIM input method"; + description = "Enable UIM input method"; }; }; + }; config = mkIf cfg.enable { diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 1efc278aeb22..d90cffbd967f 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -107,11 +107,13 @@ in zipModules ([] ++ obsolete [ "services" "sshd" "permitRootLogin" ] [ "services" "openssh" "permitRootLogin" ] ++ obsolete [ "services" "xserver" "startSSHAgent" ] [ "services" "xserver" "startOpenSSHAgent" ] ++ obsolete [ "services" "xserver" "startOpenSSHAgent" ] [ "programs" "ssh" "startAgent" ] -++ obsolete [ "services" "xserver" "windowManager" "xbmc" ] [ "services" "xserver" "desktopManager" "xbmc" ] # VirtualBox ++ obsolete [ "services" "virtualbox" "enable" ] [ "services" "virtualboxGuest" "enable" ] +# Tarsnap +++ obsolete [ "services" "tarsnap" "config" ] [ "services" "tarsnap" "archives" ] + # proxy ++ obsolete [ "nix" "proxy" ] [ "networking" "proxy" "default" ] @@ -133,6 +135,12 @@ in zipModules ([] ++ obsolete [ "services" "mysql55" ] [ "services" "mysql" ] +++ obsolete [ "environment" "checkConfigurationOptions" ] [ "_module" "check" ] + +# XBMC +++ obsolete [ "services" "xserver" "windowManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ] +++ obsolete [ "services" "xserver" "desktopManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ] + # Options that are obsolete and have no replacement. ++ obsolete' [ "boot" "loader" "grub" "bootDevice" ] ++ obsolete' [ "boot" "initrd" "luks" "enable" ] diff --git a/nixos/modules/security/apparmor.nix b/nixos/modules/security/apparmor.nix index f29e7a5ad818..4fef62cbffd7 100644 --- a/nixos/modules/security/apparmor.nix +++ b/nixos/modules/security/apparmor.nix @@ -1,43 +1,49 @@ { config, lib, pkgs, ... }: -with lib; - let + inherit (lib) mkIf mkOption types concatMapStrings; cfg = config.security.apparmor; in + { - options = { - security.apparmor = { - enable = mkOption { - type = types.bool; - default = false; - description = "Enable the AppArmor Mandatory Access Control system."; - }; + options = { + security.apparmor = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable the AppArmor Mandatory Access Control system."; + }; + profiles = mkOption { + type = types.listOf types.path; + default = []; + description = "List of files containing AppArmor profiles."; + }; + }; + }; - profiles = mkOption { - type = types.listOf types.path; - default = []; - description = "List of files containing AppArmor profiles."; - }; - }; - }; + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.apparmor-utils ]; - config = mkIf cfg.enable { - environment.systemPackages = [ pkgs.apparmor ]; - systemd.services.apparmor = { - wantedBy = [ "local-fs.target" ]; - path = [ pkgs.apparmor ]; + systemd.services.apparmor = { + wantedBy = [ "local-fs.target" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = "yes"; + ExecStart = concatMapStrings (p: + ''${pkgs.apparmor-parser}/bin/apparmor_parser -rKv -I ${pkgs.apparmor-profiles}/etc/apparmor.d "${p}" ; '' + ) cfg.profiles; + ExecStop = concatMapStrings (p: + ''${pkgs.apparmor-parser}/bin/apparmor_parser -Rv "${p}" ; '' + ) cfg.profiles; + }; + }; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = "yes"; - ExecStart = concatMapStrings (profile: - ''${pkgs.apparmor}/sbin/apparmor_parser -rKv -I ${pkgs.apparmor}/etc/apparmor.d/ "${profile}" ; '' - ) cfg.profiles; - ExecStop = concatMapStrings (profile: - ''${pkgs.apparmor}/sbin/apparmor_parser -Rv -I ${pkgs.apparmor}/etc/apparmor.d/ "${profile}" ; '' - ) 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/grsecurity.nix b/nixos/modules/security/grsecurity.nix index d0c7fa6ec288..35974f6890e6 100644 --- a/nixos/modules/security/grsecurity.nix +++ b/nixos/modules/security/grsecurity.nix @@ -38,59 +38,47 @@ in type = types.bool; default = false; description = '' - Enable the testing grsecurity patch, based on Linux 3.18. + Enable the testing grsecurity patch, based on Linux 3.19. ''; }; config = { mode = mkOption { - type = types.str; + type = types.enum [ "auto" "custom" ]; default = "auto"; - example = "custom"; description = '' grsecurity configuration mode. This specifies whether grsecurity is auto-configured or otherwise completely - manually configured. Can either be - <literal>custom</literal> or <literal>auto</literal>. - - <literal>auto</literal> is recommended. + manually configured. ''; }; priority = mkOption { - type = types.str; + type = types.enum [ "security" "performance" ]; default = "security"; - example = "performance"; description = '' grsecurity configuration priority. This specifies whether the kernel configuration should emphasize speed or - security. Can either be <literal>security</literal> or - <literal>performance</literal>. + security. ''; }; system = mkOption { - type = types.str; - default = ""; - example = "desktop"; + type = types.enum [ "desktop" "server" ]; + default = "desktop"; description = '' - grsecurity system configuration. This specifies whether - the kernel configuration should be suitable for a Desktop - or a Server. Can either be <literal>server</literal> or - <literal>desktop</literal>. + grsecurity system configuration. ''; }; virtualisationConfig = mkOption { - type = types.str; - default = "none"; - example = "host"; + type = types.nullOr (types.enum [ "host" "guest" ]); + default = null; description = '' grsecurity virtualisation configuration. This specifies the virtualisation role of the machine - that is, whether it will be a virtual machine guest, a virtual machine - host, or neither. Can be one of <literal>none</literal>, - <literal>host</literal>, or <literal>guest</literal>. + host, or neither. ''; }; @@ -106,17 +94,10 @@ in }; virtualisationSoftware = mkOption { - type = types.str; - default = ""; - example = "kvm"; + type = types.nullOr (types.enum [ "kvm" "xen" "vmware" "virtualbox" ]); + default = null; description = '' - grsecurity virtualisation software. Set this to the - specified virtual machine technology if the machine is - running as a guest, or a host. - - Can be one of <literal>kvm</literal>, - <literal>xen</literal>, <literal>vmware</literal> or - <literal>virtualbox</literal>. + Configure grsecurity for use with this virtualisation software. ''; }; @@ -245,7 +226,7 @@ in message = '' If grsecurity is enabled, you must select either the stable patch (with kernel 3.14), or the testing patch (with - kernel 3.18) to continue. + kernel 3.19) to continue. ''; } { assertion = (cfg.stable -> !cfg.testing) || (cfg.testing -> !cfg.stable); @@ -262,34 +243,23 @@ in && config.boot.kernelPackages.kernel.features.grsecurity; message = "grsecurity enabled, but kernel doesn't have grsec support"; } - { assertion = elem cfg.config.mode [ "auto" "custom" ]; - message = "grsecurity mode must either be 'auto' or 'custom'."; - } - { assertion = cfg.config.mode == "auto" -> elem cfg.config.system [ "desktop" "server" ]; - message = "when using auto grsec mode, system must be either 'desktop' or 'server'"; - } - { assertion = cfg.config.mode == "auto" -> elem cfg.config.priority [ "performance" "security" ]; - message = "when using auto grsec mode, priority must be 'performance' or 'security'."; - } - { assertion = cfg.config.mode == "auto" -> elem cfg.config.virtualisationConfig [ "host" "guest" "none" ]; - message = "when using auto grsec mode, 'virt' must be 'host', 'guest' or 'none'."; - } - { assertion = (cfg.config.mode == "auto" && (elem cfg.config.virtualisationConfig [ "host" "guest" ])) -> + { assertion = (cfg.config.mode == "auto" && (cfg.config.virtualisationConfig != null)) -> cfg.config.hardwareVirtualisation != null; message = "when using auto grsec mode with virtualisation, you must specify if your hardware has virtualisation extensions"; } - { assertion = (cfg.config.mode == "auto" && (elem cfg.config.virtualisationConfig [ "host" "guest" ])) -> - elem cfg.config.virtualisationSoftware [ "kvm" "xen" "virtualbox" "vmware" ]; - message = "virtualisation software must be 'kvm', 'xen', 'vmware' or 'virtualbox'"; + { assertion = (cfg.config.mode == "auto" && (cfg.config.virtualisationConfig != null)) -> + cfg.config.virtualisationSoftware != null; + message = "grsecurity configured for virtualisation but no virtualisation software specified"; } ]; systemd.services.grsec-lock = mkIf cfg.config.sysctl { description = "grsecurity sysctl-lock Service"; - requires = [ "sysctl.service" ]; + requires = [ "systemd-sysctl.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = "yes"; + unitConfig.ConditionPathIsReadWrite = "/proc/sys/kernel/grsecurity/grsec_lock"; script = '' locked=`cat /proc/sys/kernel/grsecurity/grsec_lock` if [ "$locked" == "0" ]; then diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index dcb2d5494754..631e8317cb4c 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -6,8 +6,9 @@ with lib; let + parentConfig = config; - pamOpts = args: { + pamOpts = { config, name, ... }: let cfg = config; in let config = parentConfig; in { options = { @@ -180,8 +181,8 @@ let }; - config = let cfg = args.config; in { - name = mkDefault args.name; + config = { + name = mkDefault name; setLoginUid = mkDefault cfg.startSession; limits = mkDefault config.security.pam.loginLimits; @@ -211,11 +212,13 @@ let ${optionalString cfg.usbAuth "auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so"} ${optionalString cfg.unixAuth - "auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth"} + "auth ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth"} + ${optionalString config.security.pam.enableEcryptfs + "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"} ${optionalString cfg.otpwAuth "auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so"} ${optionalString cfg.oathAuth - "auth sufficient ${pkgs.oathToolkit}/lib/security/pam_oath.so"} window=5 usersfile=/etc/users.oath + "auth sufficient ${pkgs.oathToolkit}/lib/security/pam_oath.so window=5 usersfile=/etc/users.oath"} ${optionalString config.users.ldap.enable "auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass"} ${optionalString config.krb5.enable '' @@ -223,9 +226,11 @@ let auth [default=die success=done] ${pam_ccreds}/lib/security/pam_ccreds.so action=validate use_first_pass auth sufficient ${pam_ccreds}/lib/security/pam_ccreds.so action=store use_first_pass ''} - auth required pam_deny.so + ${optionalString (! config.security.pam.enableEcryptfs) "auth required pam_deny.so"} # Password management. + ${optionalString config.security.pam.enableEcryptfs + "password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} password requisite pam_unix.so nullok sha512 ${optionalString config.users.ldap.enable "password sufficient ${pam_ldap}/lib/security/pam_ldap.so"} @@ -245,6 +250,8 @@ let "session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=/etc/skel umask=0022"} ${optionalString cfg.updateWtmp "session required ${pkgs.pam}/lib/security/pam_lastlog.so silent"} + ${optionalString config.security.pam.enableEcryptfs + "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} ${optionalString config.users.ldap.enable "session optional ${pam_ldap}/lib/security/pam_ldap.so"} ${optionalString config.krb5.enable @@ -252,7 +259,7 @@ let ${optionalString cfg.otpwAuth "session optional ${pkgs.otpw}/lib/security/pam_otpw.so"} ${optionalString cfg.oathAuth - "session optional ${pkgs.oathToolkit}/lib/security/pam_oath.so"} window=5 usersfile=/etc/users.oath + "session optional ${pkgs.oathToolkit}/lib/security/pam_oath.so window=5 usersfile=/etc/users.oath"} ${optionalString cfg.startSession "session optional ${pkgs.systemd}/lib/security/pam_systemd.so"} ${optionalString cfg.forwardXAuth @@ -357,6 +364,13 @@ in ''; }; + security.pam.enableEcryptfs = mkOption { + default = false; + description = '' + Enable eCryptfs PAM module (mounting ecryptfs home directory on login). + ''; + }; + users.motd = mkOption { default = null; example = "Today is Sweetmorn, the 4th day of The Aftermath in the YOLD 3178."; @@ -377,7 +391,11 @@ in ++ optional config.users.ldap.enable pam_ldap ++ optionals config.krb5.enable [pam_krb5 pam_ccreds] ++ optionals config.security.pam.enableOTPW [ pkgs.otpw ] - ++ optionals config.security.pam.enableOATH [ pkgs.oathToolkit ]; + ++ optionals config.security.pam.enableOATH [ pkgs.oathToolkit ] + ++ optionals config.security.pam.enableEcryptfs [ pkgs.ecryptfs ]; + + security.setuidPrograms = + optionals config.security.pam.enableEcryptfs [ "mount.ecryptfs_private" "umount.ecryptfs_private" ]; environment.etc = mapAttrsToList (n: v: makePAMService v) config.security.pam.services; diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix index d42a8c7f7d29..bced2a6ed757 100644 --- a/nixos/modules/security/sudo.nix +++ b/nixos/modules/security/sudo.nix @@ -77,7 +77,7 @@ in root ALL=(ALL) SETENV: ALL # Users in the "wheel" group can do anything. - %wheel ALL=(ALL) ${if cfg.wheelNeedsPassword then "" else "NOPASSWD: ALL, "}SETENV: ALL + %wheel ALL=(ALL:ALL) ${if cfg.wheelNeedsPassword then "" else "NOPASSWD: ALL, "}SETENV: ALL ${cfg.extraConfig} ''; diff --git a/nixos/modules/services/audio/icecast.nix b/nixos/modules/services/audio/icecast.nix new file mode 100644 index 000000000000..6a8a0f9975b3 --- /dev/null +++ b/nixos/modules/services/audio/icecast.nix @@ -0,0 +1,130 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.icecast; + configFile = pkgs.writeText "icecast.xml" '' + <icecast> + <hostname>${cfg.hostname}</hostname> + + <authentication> + <admin-user>${cfg.admin.user}</admin-user> + <admin-password>${cfg.admin.password}</admin-password> + </authentication> + + <paths> + <logdir>${cfg.logDir}</logdir> + <adminroot>${pkgs.icecast}/share/icecast/admin</adminroot> + <webroot>${pkgs.icecast}/share/icecast/web</webroot> + <alias source="/" dest="/status.xsl"/> + </paths> + + <listen-socket> + <port>${toString cfg.listen.port}</port> + <bind-address>${cfg.listen.address}</bind-address> + </listen-socket> + + <security> + <chroot>0</chroot> + <changeowner> + <user>${cfg.user}</user> + <group>${cfg.group}</group> + </changeowner> + </security> + + ${cfg.extraConf} + </icecast> + ''; +in { + + ###### interface + + options = { + + services.icecast = { + + enable = mkEnableOption "Icecast server"; + + hostname = mkOption { + type = types.str; + description = "DNS name or IP address that will be used for the stream directory lookups or possibily the playlist generation if a Host header is not provided."; + default = config.networking.domain; + }; + + admin = { + user = mkOption { + type = types.str; + description = "Username used for all administration functions."; + default = "admin"; + }; + + password = mkOption { + type = types.str; + description = "Password used for all administration functions."; + }; + }; + + logDir = mkOption { + type = types.path; + description = "Base directory used for logging."; + default = "/var/log/icecast"; + }; + + listen = { + port = mkOption { + type = types.int; + description = "TCP port that will be used to accept client connections."; + default = 8000; + }; + + address = mkOption { + type = types.str; + description = "Address Icecast will listen on."; + default = "::"; + }; + }; + + user = mkOption { + type = types.str; + description = "User privileges for the server."; + default = "nobody"; + }; + + group = mkOption { + type = types.str; + description = "Group privileges for the server."; + default = "nogroup"; + }; + + extraConf = mkOption { + type = types.lines; + description = "icecast.xml content."; + default = ""; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + systemd.services.icecast = { + after = [ "network.target" ]; + description = "Icecast Network Audio Streaming Server"; + wantedBy = [ "multi-user.target" ]; + + preStart = "mkdir -p ${cfg.logDir} && chown ${cfg.user}:${cfg.group} ${cfg.logDir}"; + serviceConfig = { + Type = "simple"; + ExecStart = "${pkgs.icecast}/bin/icecast -c ${configFile}"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + }; + }; + + }; + +} diff --git a/nixos/modules/services/audio/mpd.nix b/nixos/modules/services/audio/mpd.nix index b79052337597..d9b5bf7b5e6f 100644 --- a/nixos/modules/services/audio/mpd.nix +++ b/nixos/modules/services/audio/mpd.nix @@ -15,10 +15,12 @@ let state_file "${cfg.dataDir}/state" sticker_file "${cfg.dataDir}/sticker.sql" log_file "syslog" - ${if cfg.network.host != "any" then - "bind_to_address ${cfg.network.host}" else ""} - ${if cfg.network.port != 6600 then - "port ${toString cfg.network.port}" else ""} + user "${cfg.user}" + group "${cfg.group}" + + ${optionalString (cfg.network.host != "any") ''bind_to_address "${cfg.network.host}"''} + ${optionalString (cfg.network.port != 6600) ''port "${toString cfg.network.port}"''} + ${cfg.extraConfig} ''; @@ -40,8 +42,7 @@ in { musicDirectory = mkOption { default = "${cfg.dataDir}/music"; description = '' - Extra configuration added to the end of MPD's - configuration file, mpd.conf. + The directory where mpd reads music from. ''; }; @@ -62,6 +63,16 @@ in { ''; }; + user = mkOption { + default = "mpd"; + description = "User account under which MPD runs."; + }; + + group = mkOption { + default = "mpd"; + description = "Group account under which MPD runs."; + }; + network = { host = mkOption { @@ -96,7 +107,7 @@ in { description = "Music Player Daemon"; wantedBy = [ "multi-user.target" ]; path = [ pkgs.mpd ]; - preStart = "mkdir -p ${cfg.dataDir} && chown -R mpd:mpd ${cfg.dataDir}"; + preStart = "mkdir -p ${cfg.dataDir} && chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir}"; script = "exec mpd --no-daemon ${mpdConf}"; serviceConfig = { User = "mpd"; @@ -104,16 +115,19 @@ in { }; }; - users.extraUsers.mpd = { + users.extraUsers = optionalAttrs (cfg.user == "mpd") (singleton { inherit uid; - group = "mpd"; + name = "mpd"; + group = cfg.group; extraGroups = [ "audio" ]; description = "Music Player Daemon user"; home = "${cfg.dataDir}"; - }; - - users.extraGroups.mpd.gid = gid; + }); + users.extraGroups = optionalAttrs (cfg.group == "mpd") (singleton { + name = "mpd"; + gid = gid; + }); }; } diff --git a/nixos/modules/services/backup/tarsnap.nix b/nixos/modules/services/backup/tarsnap.nix index 1b0bcadca151..155161945cd9 100644 --- a/nixos/modules/services/backup/tarsnap.nix +++ b/nixos/modules/services/backup/tarsnap.nix @@ -12,6 +12,7 @@ let keyfile ${config.services.tarsnap.keyfile} ${optionalString cfg.nodump "nodump"} ${optionalString cfg.printStats "print-stats"} + ${optionalString cfg.printStats "humanize-numbers"} ${optionalNullStr cfg.checkpointBytes "checkpoint-bytes "+cfg.checkpointBytes} ${optionalString cfg.aggressiveNetworking "aggressive-networking"} ${concatStringsSep "\n" (map (v: "exclude "+v) cfg.excludes)} @@ -27,46 +28,39 @@ in type = types.bool; default = false; description = '' - If enabled, NixOS will periodically create backups of the - specified directories using the <literal>tarsnap</literal> - backup service. This installs a <literal>systemd</literal> - service called <literal>tarsnap-backup</literal> which is - periodically run by cron, or you may run it on-demand. - - See the Tarsnap <link - xlink:href='http://www.tarsnap.com/gettingstarted.html'>Getting - Started</link> page. + Enable periodic tarsnap backups. ''; }; keyfile = mkOption { - type = types.path; + type = types.str; default = "/root/tarsnap.key"; description = '' - Path to the keyfile which identifies the machine - associated with your Tarsnap account. This file can - be created using the - <literal>tarsnap-keygen</literal> utility, and - providing your Tarsnap login credentials. + The keyfile which associates this machine with your tarsnap + account. + Create the keyfile with <command>tarsnap-keygen</command>. + + The keyfile name should be given as a string and not a path, to + avoid the key being copied into the Nix store. ''; }; cachedir = mkOption { - type = types.path; + type = types.nullOr types.path; default = "/var/cache/tarsnap"; description = '' - Tarsnap operations use a "cache directory" which - allows Tarsnap to identify which blocks of data have - been previously stored; this directory is specified - via the <literal>cachedir</literal> option. If the - cache directory is lost or out of date, tarsnap - creation/deletion operations will exit with an error - message instructing you to run <literal>tarsnap - --fsck</literal> to regenerate the cache directory. + The cache allows tarsnap to identify previously stored data + blocks, reducing archival time and bandwidth usage. + + Should the cache become desynchronized or corrupted, tarsnap + will refuse to run until you manually rebuild the cache with + <command>tarsnap --fsck</command>. + + Set to <literal>null</literal> to disable caching. ''; }; - config = mkOption { + archives = mkOption { type = types.attrsOf (types.submodule ( { options = { @@ -74,41 +68,44 @@ in type = types.bool; default = true; description = '' - If set to <literal>true</literal>, then don't - archive files which have the - <literal>nodump</literal> flag set. + Exclude files with the <literal>nodump</literal> flag. ''; }; printStats = mkOption { type = types.bool; default = true; - description = "Print statistics when creating archives."; + description = '' + Print global archive statistics upon completion. + The output is available via + <command>systemctl status tarsnap@archive-name</command>. + ''; }; checkpointBytes = mkOption { type = types.nullOr types.str; - default = "1G"; + default = "1GB"; description = '' - Create a checkpoint per a particular amount of - uploaded data. By default, Tarsnap will create - checkpoints once per GB of data uploaded. At - minimum, <literal>checkpointBytes</literal> must be - 1GB. - - Can also be set to <literal>null</literal> to - disable checkpointing. + Create a checkpoint every <literal>checkpointBytes</literal> + of uploaded data (optionally specified using an SI prefix). + + 1GB is the minimum value. A higher value is recommended, + as checkpointing is expensive. + + Set to <literal>null</literal> to disable checkpointing. ''; }; period = mkOption { type = types.str; - default = "15 01 * * *"; + default = "01:15"; + example = "hourly"; description = '' - This option defines (in the format used by cron) - when tarsnap is run for backups. The default is to - backup the specified paths at 01:15 at night every - day. + Create archive at this interval. + + The format is described in + <citerefentry><refentrytitle>systemd.time</refentrytitle> + <manvolnum>7</manvolnum></citerefentry>. ''; }; @@ -116,11 +113,11 @@ in type = types.bool; default = false; description = '' - Aggressive network behaviour: Use multiple TCP - connections when writing archives. Use of this - option is recommended only in cases where TCP - congestion control is known to be the limiting - factor in upload performance. + Upload data over multiple TCP connections, potentially + increasing tarsnap's bandwidth utilisation at the cost + of slowing down all other network traffic. Not + recommended unless TCP congestion is the dominant + limiting factor. ''; }; @@ -134,8 +131,7 @@ in type = types.listOf types.str; default = []; description = '' - Exclude files and directories matching the specified - patterns. + Exclude files and directories matching these patterns. ''; }; @@ -143,12 +139,10 @@ in type = types.listOf types.str; default = []; description = '' - Include only files and directories matching the - specified patterns. + Include only files and directories matching these + patterns (the empty list includes everything). - Note that exclusions specified via - <literal>excludes</literal> take precedence over - inclusions. + Exclusions have precedence over inclusions. ''; }; @@ -156,10 +150,10 @@ in type = types.bool; default = false; description = '' - Attempt to reduce tarsnap memory consumption. This - option will slow down the process of creating - archives, but may help on systems where the average - size of files being backed up is less than 1 MB. + Reduce memory consumption by not caching small files. + Possibly beneficial if the average file size is smaller + than 1 MB and the number of files is lower than the + total amount of RAM in KB. ''; }; @@ -167,11 +161,9 @@ in type = types.bool; default = false; description = '' - Try even harder to reduce tarsnap memory - consumption. This can significantly slow down - tarsnap, but reduces its memory usage by an - additional factor of 2 beyond what the - <literal>lowmem</literal> option does. + Reduce memory consumption by a factor of 2 beyond what + <literal>lowmem</literal> does, at the cost of significantly + slowing down the archiving process. ''; }; }; @@ -188,25 +180,22 @@ in gamedata = { directories = [ "/var/lib/minecraft "]; - period = "*/30 * * * *"; + period = "*:30"; }; } ''; description = '' - Configuration of a Tarsnap archive. In the example, your - machine will have two tarsnap archives: - <literal>gamedata</literal> (backed up every 30 minutes) and - <literal>nixos</literal> (backed up at 1:15 AM every night by - default). You can control individual archive backups using - <literal>systemctl</literal>, using the - <literal>tarsnap@nixos</literal> or - <literal>tarsnap@gamedata</literal> units. For example, - <literal>systemctl start tarsnap@nixos</literal> will - immediately create a new NixOS archive. By default, archives - are suffixed with the timestamp of when they were started, - down to second resolution. This means you can use GNU - <literal>sort</literal> to sort output easily. + Tarsnap archive configurations. Each attribute names an archive + to be created at a given time interval, according to the options + associated with it. When uploading to the tarsnap server, + archive names are suffixed by a 1 second resolution timestamp. + + For each member of the set is created a timer which triggers the + instanced <literal>tarsnap@</literal> service unit. You may use + <command>systemctl start tarsnap@archive-name</command> to + manually trigger creation of <literal>archive-name</literal> at + any time. ''; }; }; @@ -216,38 +205,45 @@ in assertions = (mapAttrsToList (name: cfg: { assertion = cfg.directories != []; - message = "Must specify directories for Tarsnap to back up"; - }) cfg.config) ++ + message = "Must specify paths for tarsnap to back up"; + }) cfg.archives) ++ (mapAttrsToList (name: cfg: - { assertion = cfg.lowmem -> !cfg.verylowmem && (cfg.verylowmem -> !cfg.lowmem); + { assertion = !(cfg.lowmem && cfg.verylowmem); message = "You cannot set both lowmem and verylowmem"; - }) cfg.config); + }) cfg.archives); systemd.services."tarsnap@" = { - description = "Tarsnap Backup of '%i'"; + description = "Tarsnap archive '%i'"; requires = [ "network.target" ]; path = [ pkgs.tarsnap pkgs.coreutils ]; scriptArgs = "%i"; script = '' - mkdir -p -m 0755 $(dirname ${cfg.cachedir}) - mkdir -p -m 0600 ${cfg.cachedir} + mkdir -p -m 0755 ${dirOf cfg.cachedir} + mkdir -p -m 0700 ${cfg.cachedir} DIRS=`cat /etc/tarsnap/$1.dirs` exec tarsnap --configfile /etc/tarsnap/$1.conf -c -f $1-$(date +"%Y%m%d%H%M%S") $DIRS ''; + + serviceConfig = { + IOSchedulingClass = "idle"; + NoNewPrivileges = "true"; + CapabilityBoundingSet = "CAP_DAC_READ_SEARCH"; + }; }; - services.cron.systemCronJobs = mapAttrsToList (name: cfg: - "${cfg.period} root ${config.systemd.package}/bin/systemctl start tarsnap@${name}" - ) cfg.config; + systemd.timers = mapAttrs' (name: cfg: nameValuePair "tarsnap@${name}" + { timerConfig.OnCalendar = cfg.period; + wantedBy = [ "timers.target" ]; + }) cfg.archives; environment.etc = (mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.conf" { text = configFile cfg; - }) cfg.config) // + }) cfg.archives) // (mapAttrs' (name: cfg: nameValuePair "tarsnap/${name}.dirs" { text = concatStringsSep " " cfg.directories; - }) cfg.config); + }) cfg.archives); environment.systemPackages = [ pkgs.tarsnap ]; }; diff --git a/nixos/modules/services/cluster/kubernetes.nix b/nixos/modules/services/cluster/kubernetes.nix index 7fd2d77aa825..d9ae0454ba5e 100644 --- a/nixos/modules/services/cluster/kubernetes.nix +++ b/nixos/modules/services/cluster/kubernetes.nix @@ -44,6 +44,12 @@ in { type = types.path; }; + dockerCfg = mkOption { + description = "Kubernetes contents of dockercfg file."; + default = ""; + type = types.lines; + }; + apiserver = { enable = mkOption { description = "Whether to enable kubernetes apiserver."; @@ -217,13 +223,13 @@ in { }; machines = mkOption { - description = "Kubernetes apiserver list of machines to schedule to schedule onto"; + description = "Kubernetes controller list of machines to schedule to schedule onto"; default = []; type = types.listOf types.str; }; extraOpts = mkOption { - description = "Kubernetes scheduler extra command line options."; + description = "Kubernetes controller extra command line options."; default = ""; type = types.str; }; @@ -260,6 +266,30 @@ in { type = types.bool; }; + apiServers = mkOption { + 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; + }; + + cadvisorPort = mkOption { + description = "Kubernetes kubelet local cadvisor port."; + default = config.services.cadvisor.port; + type = types.int; + }; + + clusterDns = mkOption { + description = "Use alternative dns."; + default = ""; + type = types.str; + }; + + clusterDomain = mkOption { + description = "Use alternative domain."; + default = ""; + type = types.str; + }; + extraOpts = mkOption { description = "Kubernetes kubelet extra command line options."; default = ""; @@ -295,6 +325,7 @@ in { systemd.services.kubernetes-apiserver = { description = "Kubernetes Api Server"; wantedBy = [ "multi-user.target" ]; + requires = ["kubernetes-setup.service"]; after = [ "network-interfaces.target" "etcd.service" ]; serviceConfig = { ExecStart = let @@ -306,26 +337,25 @@ in { (concatImapStringsSep "\n" (i: v: v + "," + (toString i)) (mapAttrsToList (name: token: token + "," + name) cfg.apiserver.tokenAuth)); in ''${cfg.package}/bin/kube-apiserver \ - -etcd_servers=${concatMapStringsSep "," (f: "http://${f}") cfg.etcdServers} \ - -address=${cfg.apiserver.address} \ - -port=${toString cfg.apiserver.port} \ - -read_only_port=${toString cfg.apiserver.readOnlyPort} \ - -public_address_override=${cfg.apiserver.publicAddress} \ - -allow_privileged=${if cfg.apiserver.allowPrivileged then "true" else "false"} \ + --etcd_servers=${concatMapStringsSep "," (f: "http://${f}") cfg.etcdServers} \ + --address=${cfg.apiserver.address} \ + --port=${toString cfg.apiserver.port} \ + --read_only_port=${toString cfg.apiserver.readOnlyPort} \ + --public_address_override=${cfg.apiserver.publicAddress} \ + --allow_privileged=${if cfg.apiserver.allowPrivileged then "true" else "false"} \ ${optionalString (cfg.apiserver.tlsCertFile!="") - "-tls_cert_file=${cfg.apiserver.tlsCertFile}"} \ + "--tls_cert_file=${cfg.apiserver.tlsCertFile}"} \ ${optionalString (cfg.apiserver.tlsPrivateKeyFile!="") - "-tls_private_key_file=${cfg.apiserver.tlsPrivateKeyFile}"} \ + "--tls_private_key_file=${cfg.apiserver.tlsPrivateKeyFile}"} \ ${optionalString (cfg.apiserver.tokenAuth!=[]) - "-token_auth_file=${tokenAuthFile}"} \ - -authorization_mode=${cfg.apiserver.authorizationMode} \ + "--token_auth_file=${tokenAuthFile}"} \ + --authorization_mode=${cfg.apiserver.authorizationMode} \ ${optionalString (cfg.apiserver.authorizationMode == "ABAC") - "-authorization_policy_file=${authorizationPolicyFile}"} \ - ${optionalString (cfg.apiserver.tlsCertFile!="" && cfg.apiserver.tlsCertFile!="") - "-secure_port=${toString cfg.apiserver.securePort}"} \ - -portal_net=${cfg.apiserver.portalNet} \ - -logtostderr=true \ - ${optionalString cfg.verbose "-v=6 -log_flush_frequency=1s"} \ + "--authorization_policy_file=${authorizationPolicyFile}"} \ + --secure_port=${toString cfg.apiserver.securePort} \ + --portal_net=${cfg.apiserver.portalNet} \ + --logtostderr=true \ + ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \ ${cfg.apiserver.extraOpts} ''; User = "kubernetes"; @@ -345,11 +375,11 @@ in { after = [ "network-interfaces.target" "kubernetes-apiserver.service" ]; serviceConfig = { ExecStart = ''${cfg.package}/bin/kube-scheduler \ - -address=${cfg.scheduler.address} \ - -port=${toString cfg.scheduler.port} \ - -master=${cfg.scheduler.master} \ - -logtostderr=true \ - ${optionalString cfg.verbose "-v=6 -log_flush_frequency=1s"} \ + --address=${cfg.scheduler.address} \ + --port=${toString cfg.scheduler.port} \ + --master=${cfg.scheduler.master} \ + --logtostderr=true \ + ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \ ${cfg.scheduler.extraOpts} ''; User = "kubernetes"; @@ -364,13 +394,12 @@ in { after = [ "network-interfaces.target" "kubernetes-apiserver.service" ]; serviceConfig = { ExecStart = ''${cfg.package}/bin/kube-controller-manager \ - -address=${cfg.controllerManager.address} \ - -port=${toString cfg.controllerManager.port} \ - -master=${cfg.controllerManager.master} \ - ${optionalString (cfg.controllerManager.machines != []) - "-machines=${concatStringsSep "," cfg.controllerManager.machines}"} \ - -logtostderr=true \ - ${optionalString cfg.verbose "-v=6 -log_flush_frequency=1s"} \ + --address=${cfg.controllerManager.address} \ + --port=${toString cfg.controllerManager.port} \ + --master=${cfg.controllerManager.master} \ + --machines=${concatStringsSep "," cfg.controllerManager.machines} \ + --logtostderr=true \ + ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \ ${cfg.controllerManager.extraOpts} ''; User = "kubernetes"; @@ -382,23 +411,28 @@ in { systemd.services.kubernetes-kubelet = { description = "Kubernetes Kubelet Service"; wantedBy = [ "multi-user.target" ]; + requires = ["kubernetes-setup.service"]; after = [ "network-interfaces.target" "etcd.service" "docker.service" ]; - serviceConfig = { - ExecStart = ''${cfg.package}/bin/kubelet \ - -etcd_servers=${concatMapStringsSep "," (f: "http://${f}") cfg.etcdServers} \ - -address=${cfg.kubelet.address} \ - -port=${toString cfg.kubelet.port} \ - -hostname_override=${cfg.kubelet.hostname} \ - -allow_privileged=${if cfg.kubelet.allowPrivileged then "true" else "false"} \ - -root_dir=${cfg.dataDir} \ - -logtostderr=true \ - ${optionalString cfg.verbose "-v=6 -log_flush_frequency=1s"} \ + script = '' + export PATH="/bin:/sbin:/usr/bin:/usr/sbin:$PATH" + exec ${cfg.package}/bin/kubelet \ + --etcd_servers=${concatMapStringsSep "," (f: "http://${f}") cfg.etcdServers} \ + --api_servers=${concatMapStringsSep "," (f: "http://${f}") cfg.kubelet.apiServers} \ + --address=${cfg.kubelet.address} \ + --port=${toString cfg.kubelet.port} \ + --hostname_override=${cfg.kubelet.hostname} \ + --allow_privileged=${if cfg.kubelet.allowPrivileged then "true" else "false"} \ + --root_dir=${cfg.dataDir} \ + --cadvisor_port=${toString cfg.kubelet.cadvisorPort} \ + ${optionalString (cfg.kubelet.clusterDns != "") + ''--cluster_dns=${cfg.kubelet.clusterDns}''} \ + ${optionalString (cfg.kubelet.clusterDomain != "") + ''--cluster_domain=${cfg.kubelet.clusterDomain}''} \ + --logtostderr=true \ + ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \ ${cfg.kubelet.extraOpts} ''; - User = "kubernetes"; - PermissionsStartOnly = true; - WorkingDirectory = cfg.dataDir; - }; + serviceConfig.WorkingDirectory = cfg.dataDir; }; }) @@ -409,10 +443,10 @@ in { after = [ "network-interfaces.target" "etcd.service" ]; serviceConfig = { ExecStart = ''${cfg.package}/bin/kube-proxy \ - -etcd_servers=${concatMapStringsSep "," (s: "http://${s}") cfg.etcdServers} \ - -bind_address=${cfg.proxy.address} \ - -logtostderr=true \ - ${optionalString cfg.verbose "-v=6 -log_flush_frequency=1s"} \ + --etcd_servers=${concatMapStringsSep "," (s: "http://${s}") cfg.etcdServers} \ + --bind_address=${cfg.proxy.address} \ + --logtostderr=true \ + ${optionalString cfg.verbose "--v=6 --log_flush_frequency=1s"} \ ${cfg.proxy.extraOpts} ''; }; @@ -427,6 +461,8 @@ in { (mkIf (any (el: el == "node") cfg.roles) { virtualisation.docker.enable = mkDefault true; + services.cadvisor.enable = mkDefault true; + services.cadvisor.port = mkDefault 4194; services.kubernetes.kubelet.enable = mkDefault true; services.kubernetes.proxy.enable = mkDefault true; }) @@ -442,6 +478,16 @@ in { cfg.kubelet.enable || cfg.proxy.enable ) { + systemd.services.kubernetes-setup = { + description = "Kubernetes setup."; + 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 + ''; + }; + services.kubernetes.package = mkDefault pkgs.kubernetes; environment.systemPackages = [ cfg.package ]; diff --git a/nixos/modules/services/cluster/panamax.nix b/nixos/modules/services/cluster/panamax.nix index a7233f23c913..b47ff744fc27 100644 --- a/nixos/modules/services/cluster/panamax.nix +++ b/nixos/modules/services/cluster/panamax.nix @@ -124,14 +124,15 @@ in { }; preStart = '' - rm -rf ${cfg.dataDir}/state/tmp mkdir -p ${cfg.dataDir}/ui/state/{log,tmp} + chown -R panamax:panamax ${cfg.dataDir} ''; serviceConfig = { ExecStart = "${panamax_ui}/bin/bundle exec rails server --binding 127.0.0.1 --port ${toString cfg.UIPort}"; User = "panamax"; Group = "panamax"; + PermissionsStartOnly = true; }; }; @@ -145,6 +146,8 @@ in { services.journald.enableHttpGateway = mkDefault true; services.fleet.enable = mkDefault true; + services.cadvisor.enable = mkDefault true; + services.cadvisor.port = mkDefault 3002; virtualisation.docker.enable = mkDefault true; environment.systemPackages = [ panamax_api panamax_ui ]; diff --git a/nixos/modules/services/computing/slurm/slurm.nix b/nixos/modules/services/computing/slurm/slurm.nix new file mode 100644 index 000000000000..019d7fbb16cd --- /dev/null +++ b/nixos/modules/services/computing/slurm/slurm.nix @@ -0,0 +1,130 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.slurm; + # configuration file can be generated by http://slurm.schedmd.com/configurator.html + configFile = pkgs.writeText "slurm.conf" + '' + ${optionalString (cfg.controlMachine != null) ''controlMachine=${cfg.controlMachine}''} + ${optionalString (cfg.controlAddr != null) ''controlAddr=${cfg.controlAddr}''} + ${optionalString (cfg.nodeName != null) ''nodeName=${cfg.nodeName}''} + ${optionalString (cfg.partitionName != null) ''partitionName=${cfg.partitionName}''} + ${cfg.extraConfig} + ''; +in + +{ + + ###### interface + + options = { + + services.slurm = { + + server = { + enable = mkEnableOption "slurm control daemon"; + + }; + + client = { + enable = mkEnableOption "slurm rlient daemon"; + + }; + + controlMachine = mkOption { + type = types.nullOr types.str; + default = null; + example = null; + description = '' + The short hostname of the machine where SLURM control functions are + executed (i.e. the name returned by the command "hostname -s", use "tux001" + rather than "tux001.my.com"). + ''; + }; + + controlAddr = mkOption { + type = types.nullOr types.str; + default = cfg.controlMachine; + example = null; + description = '' + Name that ControlMachine should be referred to in establishing a + communications path. + ''; + }; + + nodeName = mkOption { + type = types.nullOr types.str; + default = null; + example = "linux[1-32] CPUs=1 State=UNKNOWN"; + description = '' + Name that SLURM uses to refer to a node (or base partition for BlueGene + systems). Typically this would be the string that "/bin/hostname -s" + returns. Note that now you have to write node's parameters after the name. + ''; + }; + + partitionName = mkOption { + type = types.nullOr types.str; + default = null; + example = "debug Nodes=linux[1-32] Default=YES MaxTime=INFINITE State=UP"; + description = '' + Name by which the partition may be referenced. Note that now you have + to write patrition's parameters after the name. + ''; + }; + + extraConfig = mkOption { + default = ""; + type = types.lines; + description = '' + Extra configuration options that will be added verbatim at + the end of the slurm configuration file. + ''; + }; + }; + + }; + + + ###### implementation + + config = mkIf (cfg.client.enable || cfg.server.enable) { + + environment.systemPackages = [ pkgs.slurm-llnl ]; + + systemd.services.slurmd = mkIf (cfg.client.enable) { + path = with pkgs; [ slurm-llnl coreutils ]; + + wantedBy = [ "multi-user.target" ]; + after = [ "systemd-tmpfiles-clean.service" ]; + + serviceConfig = { + Type = "forking"; + ExecStart = "${pkgs.slurm-llnl}/bin/slurmd -f ${configFile}"; + PIDFile = "/run/slurmd.pid"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + }; + }; + + systemd.services.slurmctld = mkIf (cfg.server.enable) { + path = with pkgs; [ slurm-llnl munge coreutils ]; + + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "auditd.service" "munged.service" "slurmdbd.service" ]; + requires = [ "munged.service" ]; + + serviceConfig = { + Type = "forking"; + ExecStart = "${pkgs.slurm-llnl}/bin/slurmctld"; + PIDFile = "/run/slurmctld.pid"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + }; + environment = { SLURM_CONF = "${configFile}"; }; + }; + + }; + +} diff --git a/nixos/modules/services/databases/couchdb.nix b/nixos/modules/services/databases/couchdb.nix index e1fe6be6f6a3..2b1d07c355ef 100644 --- a/nixos/modules/services/databases/couchdb.nix +++ b/nixos/modules/services/databases/couchdb.nix @@ -131,8 +131,8 @@ in { type = types.string; default = "/var/lib/couchdb/couchdb.ini"; description = '' - Custom configuration file. File needs to be readable and writable - from couchdb user/group. + Configuration file for persisting runtime changes. File + needs to be readable and writable from couchdb user/group. ''; }; @@ -157,12 +157,15 @@ in { mkdir -p ${cfg.databaseDir}; mkdir -p ${cfg.viewIndexDir}; touch ${cfg.configFile} + touch -a ${cfg.logFile} if [ "$(id -u)" = 0 ]; then - chown ${cfg.user}:${cfg.group} ${cfg.uriFile} + chown ${cfg.user}:${cfg.group} `dirname ${cfg.uriFile}`; + (-f ${cfg.uriFile} && chown ${cfg.user}:${cfg.group} ${cfg.uriFile}) || true chown ${cfg.user}:${cfg.group} ${cfg.databaseDir} chown ${cfg.user}:${cfg.group} ${cfg.viewIndexDir} chown ${cfg.user}:${cfg.group} ${cfg.configFile} + chown ${cfg.user}:${cfg.group} ${cfg.logFile} fi ''; diff --git a/nixos/modules/services/databases/mongodb.nix b/nixos/modules/services/databases/mongodb.nix index 02e44ad88704..14ffdad9217d 100644 --- a/nixos/modules/services/databases/mongodb.nix +++ b/nixos/modules/services/databases/mongodb.nix @@ -120,6 +120,7 @@ in }; preStart = '' + rm ${cfg.dbpath}/mongod.lock || true if ! test -e ${cfg.dbpath}; then install -d -m0700 -o ${cfg.user} ${cfg.dbpath} fi diff --git a/nixos/modules/services/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix index b94a3fbf3de7..05b13492052a 100644 --- a/nixos/modules/services/databases/mysql.nix +++ b/nixos/modules/services/databases/mysql.nix @@ -8,9 +8,7 @@ let mysql = cfg.package; - is55 = mysql.mysqlVersion == "5.5"; - - mysqldDir = if is55 then "${mysql}/bin" else "${mysql}/libexec"; + atLeast55 = versionAtLeast mysql.mysqlVersion "5.5"; pidFile = "${cfg.pidDir}/mysqld.pid"; @@ -24,7 +22,7 @@ let port = ${toString cfg.port} ${optionalString (cfg.replication.role == "master" || cfg.replication.role == "slave") "log-bin=mysql-bin"} ${optionalString (cfg.replication.role == "master" || cfg.replication.role == "slave") "server-id = ${toString cfg.replication.serverId}"} - ${optionalString (cfg.replication.role == "slave" && !is55) + ${optionalString (cfg.replication.role == "slave" && !atLeast55) '' master-host = ${cfg.replication.masterHost} master-user = ${cfg.replication.masterUser} @@ -75,7 +73,7 @@ in }; pidDir = mkOption { - default = "/var/run/mysql"; + default = "/run/mysqld"; description = "Location of the file which stores the PID of the MySQL server"; }; @@ -180,15 +178,19 @@ in mkdir -m 0700 -p ${cfg.pidDir} chown -R ${cfg.user} ${cfg.pidDir} + + # Make the socket directory + mkdir -m 0700 -p /run/mysqld + chown -R ${cfg.user} /run/mysqld ''; - serviceConfig.ExecStart = "${mysqldDir}/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions}"; + serviceConfig.ExecStart = "${mysql}/bin/mysqld --defaults-extra-file=${myCnf} ${mysqldOptions}"; postStart = '' # Wait until the MySQL server is available for use count=0 - while [ ! -e /tmp/mysql.sock ] + while [ ! -e /run/mysqld/mysqld.sock ] do if [ $count -eq 30 ] then @@ -222,7 +224,7 @@ in fi '') cfg.initialDatabases} - ${optionalString (cfg.replication.role == "slave" && is55) + ${optionalString (cfg.replication.role == "slave" && atLeast55) '' # Set up the replication master diff --git a/nixos/modules/services/games/minecraft-server.nix b/nixos/modules/services/games/minecraft-server.nix index 4c734aefa469..d2c8af6de0c5 100644 --- a/nixos/modules/services/games/minecraft-server.nix +++ b/nixos/modules/services/games/minecraft-server.nix @@ -8,6 +8,7 @@ in { options = { services.minecraft-server = { + enable = mkOption { type = types.bool; default = false; @@ -15,7 +16,23 @@ in If enabled, start a Minecraft Server. The listening port for the server is always <literal>25565</literal>. The server data will be loaded from and saved to - <literal>/var/lib/minecraft</literal>. + <literal>${cfg.dataDir}</literal>. + ''; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/minecraft"; + description = '' + Directory to store minecraft database and other state/data files. + ''; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = '' + Whether to open ports in the firewall (if enabled) for the server. ''; }; @@ -30,7 +47,7 @@ in config = mkIf cfg.enable { users.extraUsers.minecraft = { description = "Minecraft Server Service user"; - home = "/var/lib/minecraft"; + home = cfg.dataDir; createHome = true; uid = config.ids.uids.minecraft; }; @@ -43,9 +60,14 @@ in serviceConfig.Restart = "always"; serviceConfig.User = "minecraft"; script = '' - cd /var/lib/minecraft + cd ${cfg.dataDir} exec ${pkgs.minecraft-server}/bin/minecraft-server ${cfg.jvmOpts} ''; }; + + networking.firewall = mkIf cfg.openFirewall { + allowedUDPPorts = [ 25565 ]; + allowedTCPPorts = [ 25565 ]; + }; }; } diff --git a/nixos/modules/services/games/minetest-server.nix b/nixos/modules/services/games/minetest-server.nix new file mode 100644 index 000000000000..996e313386fe --- /dev/null +++ b/nixos/modules/services/games/minetest-server.nix @@ -0,0 +1,104 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.minetest-server; + flag = val: name: if val != null then "--${name} ${val} " else ""; + flags = [ + (flag cfg.gameId "gameid") + (flag cfg.world "world") + (flag cfg.configPath "config") + (flag cfg.logPath "logfile") + (flag cfg.port "port") + ]; +in +{ + options = { + services.minetest-server = { + enable = mkOption { + type = types.bool; + default = false; + description = "If enabled, starts a Minetest Server."; + }; + + gameId = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Id of the game to use. To list available games run + `minetestserver --gameid list`. + + If only one game exists, this option can be null. + ''; + }; + + world = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Name of the world to use. To list available worlds run + `minetestserver --world list`. + + If only one world exists, this option can be null. + ''; + }; + + configPath = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Path to the config to use. + + If set to null, the config of the running user will be used: + `~/.minetest/minetest.conf`. + ''; + }; + + logPath = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Path to logfile for logging. + + If set to null, logging will be output to stdout which means + all output will be catched by systemd. + ''; + }; + + port = mkOption { + type = types.nullOr types.int; + default = null; + description = '' + Port number to bind to. + + If set to null, the default 30000 will be used. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + users.extraUsers.minetest = { + description = "Minetest Server Service user"; + home = "/var/lib/minetest"; + createHome = true; + uid = config.ids.uids.minetest; + }; + + systemd.services.minetest-server = { + description = "Minetest Server Service"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + serviceConfig.Restart = "always"; + serviceConfig.User = "minetest"; + + script = '' + cd /var/lib/minetest + + exec ${pkgs.minetest}/bin/minetestserver ${concatStrings flags} + ''; + }; + }; +} diff --git a/nixos/modules/services/hardware/tcsd.nix b/nixos/modules/services/hardware/tcsd.nix index d7f6c188feb8..220b154bd97a 100644 --- a/nixos/modules/services/hardware/tcsd.nix +++ b/nixos/modules/services/hardware/tcsd.nix @@ -128,12 +128,12 @@ in users.extraUsers = optionalAttrs (cfg.user == "tss") (singleton { name = "tss"; group = "tss"; - uid = config.ids.uids.nginx; + uid = config.ids.uids.tss; }); users.extraGroups = optionalAttrs (cfg.group == "tss") (singleton { name = "tss"; - gid = config.ids.gids.nginx; + gid = config.ids.gids.tss; }); }; } diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix index 39180f4d37ec..50588e449587 100644 --- a/nixos/modules/services/hardware/udev.nix +++ b/nixos/modules/services/hardware/udev.nix @@ -28,6 +28,7 @@ let # Perform substitutions in all udev rules files. udevRules = stdenv.mkDerivation { name = "udev-rules"; + preferLocalBuild = true; buildCommand = '' mkdir -p $out shopt -s nullglob @@ -236,7 +237,10 @@ in system.activationScripts.udevd = '' - echo "" > /proc/sys/kernel/hotplug + # The deprecated hotplug uevent helper is not used anymore + if [ -e /proc/sys/kernel/hotplug ]; then + echo "" > /proc/sys/kernel/hotplug + fi # Regenerate the hardware database /var/lib/udev/hwdb.bin # whenever systemd changes. diff --git a/nixos/modules/services/logging/fluentd.nix b/nixos/modules/services/logging/fluentd.nix new file mode 100644 index 000000000000..61eeec504e0d --- /dev/null +++ b/nixos/modules/services/logging/fluentd.nix @@ -0,0 +1,39 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.fluentd; +in { + ###### interface + + options = { + + services.fluentd = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable fluentd."; + }; + + config = mkOption { + type = types.lines; + default = ""; + description = "Fluentd config."; + }; + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + systemd.services.fluentd = with pkgs; { + description = "Fluentd Daemon"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkgs.fluentd}/bin/fluentd -c ${pkgs.writeText "fluentd.conf" cfg.config}"; + }; + }; + }; +} diff --git a/nixos/modules/services/misc/disnix.nix b/nixos/modules/services/misc/disnix.nix index 219c7ed95874..48bb9e4293e7 100644 --- a/nixos/modules/services/misc/disnix.nix +++ b/nixos/modules/services/misc/disnix.nix @@ -132,7 +132,7 @@ in restartIfChanged = false; - path = [ pkgs.nix pkgs.disnix dysnomia ]; + path = [ pkgs.nix pkgs.disnix dysnomia "/run/current-system/sw" ]; environment = { HOME = "/root"; diff --git a/nixos/modules/services/misc/mediatomb.nix b/nixos/modules/services/misc/mediatomb.nix new file mode 100644 index 000000000000..23227548039c --- /dev/null +++ b/nixos/modules/services/misc/mediatomb.nix @@ -0,0 +1,282 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + uid = config.ids.uids.mediatomb; + gid = config.ids.gids.mediatomb; + cfg = config.services.mediatomb; + + mtConf = pkgs.writeText "config.xml" '' + <?xml version="1.0" encoding="UTF-8"?> + <config version="2" xmlns="http://mediatomb.cc/config/2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://mediatomb.cc/config/2 http://mediatomb.cc/config/2.xsd"> + <server> + <ui enabled="yes" show-tooltips="yes"> + <accounts enabled="no" session-timeout="30"> + <account user="mediatomb" password="mediatomb"/> + </accounts> + </ui> + <name>${cfg.serverName}</name> + <udn>uuid:${cfg.uuid}</udn> + <home>${cfg.dataDir}</home> + <webroot>${pkgs.mediatomb}/share/mediatomb/web</webroot> + <storage> + <sqlite3 enabled="yes"> + <database-file>mediatomb.db</database-file> + </sqlite3> + </storage> + <protocolInfo extend="${if cfg.ps3Support then "yes" else "no"}"/> + ${if cfg.dsmSupport then '' + <custom-http-headers> + <add header="X-User-Agent: redsonic"/> + </custom-http-headers> + + <manufacturerURL>redsonic.com</manufacturerURL> + <modelNumber>105</modelNumber> + '' else ""} + ${if cfg.tg100Support then '' + <upnp-string-limit>101</upnp-string-limit> + '' else ""} + <extended-runtime-options> + <mark-played-items enabled="yes" suppress-cds-updates="yes"> + <string mode="prepend">*</string> + <mark> + <content>video</content> + </mark> + </mark-played-items> + </extended-runtime-options> + </server> + <import hidden-files="no"> + <scripting script-charset="UTF-8"> + <common-script>/nix/store/cngbzn39vidd6jm4wgzxfafqll74ybfa-mediatomb-0.12.1/share/mediatomb/js/common.js</common-script> + <playlist-script>/nix/store/cngbzn39vidd6jm4wgzxfafqll74ybfa-mediatomb-0.12.1/share/mediatomb/js/playlists.js</playlist-script> + <virtual-layout type="builtin"> + <import-script>/nix/store/cngbzn39vidd6jm4wgzxfafqll74ybfa-mediatomb-0.12.1/share/mediatomb/js/import.js</import-script> + </virtual-layout> + </scripting> + <mappings> + <extension-mimetype ignore-unknown="no"> + <map from="mp3" to="audio/mpeg"/> + <map from="ogx" to="application/ogg"/> + <map from="ogv" to="video/ogg"/> + <map from="oga" to="audio/ogg"/> + <map from="ogg" to="audio/ogg"/> + <map from="ogm" to="video/ogg"/> + <map from="asf" to="video/x-ms-asf"/> + <map from="asx" to="video/x-ms-asf"/> + <map from="wma" to="audio/x-ms-wma"/> + <map from="wax" to="audio/x-ms-wax"/> + <map from="wmv" to="video/x-ms-wmv"/> + <map from="wvx" to="video/x-ms-wvx"/> + <map from="wm" to="video/x-ms-wm"/> + <map from="wmx" to="video/x-ms-wmx"/> + <map from="m3u" to="audio/x-mpegurl"/> + <map from="pls" to="audio/x-scpls"/> + <map from="flv" to="video/x-flv"/> + <map from="mkv" to="video/x-matroska"/> + <map from="mka" to="audio/x-matroska"/> + ${if cfg.ps3Support then '' + <map from="avi" to="video/divx"/> + '' else ""} + ${if cfg.dsmSupport then '' + <map from="avi" to="video/avi"/> + '' else ""} + </extension-mimetype> + <mimetype-upnpclass> + <map from="audio/*" to="object.item.audioItem.musicTrack"/> + <map from="video/*" to="object.item.videoItem"/> + <map from="image/*" to="object.item.imageItem"/> + </mimetype-upnpclass> + <mimetype-contenttype> + <treat mimetype="audio/mpeg" as="mp3"/> + <treat mimetype="application/ogg" as="ogg"/> + <treat mimetype="audio/ogg" as="ogg"/> + <treat mimetype="audio/x-flac" as="flac"/> + <treat mimetype="audio/x-ms-wma" as="wma"/> + <treat mimetype="audio/x-wavpack" as="wv"/> + <treat mimetype="image/jpeg" as="jpg"/> + <treat mimetype="audio/x-mpegurl" as="playlist"/> + <treat mimetype="audio/x-scpls" as="playlist"/> + <treat mimetype="audio/x-wav" as="pcm"/> + <treat mimetype="audio/L16" as="pcm"/> + <treat mimetype="video/x-msvideo" as="avi"/> + <treat mimetype="video/mp4" as="mp4"/> + <treat mimetype="audio/mp4" as="mp4"/> + <treat mimetype="application/x-iso9660" as="dvd"/> + <treat mimetype="application/x-iso9660-image" as="dvd"/> + </mimetype-contenttype> + </mappings> + <online-content> + <YouTube enabled="no" refresh="28800" update-at-start="no" purge-after="604800" racy-content="exclude" format="mp4" hd="no"> + <favorites user="mediatomb"/> + <standardfeed feed="most_viewed" time-range="today"/> + <playlists user="mediatomb"/> + <uploads user="mediatomb"/> + <standardfeed feed="recently_featured" time-range="today"/> + </YouTube> + </online-content> + </import> + <transcoding enabled="${if cfg.transcoding then "yes" else "no"}"> + <mimetype-profile-mappings> + <transcode mimetype="video/x-flv" using="vlcmpeg"/> + <transcode mimetype="application/ogg" using="vlcmpeg"/> + <transcode mimetype="application/ogg" using="oggflac2raw"/> + <transcode mimetype="audio/x-flac" using="oggflac2raw"/> + </mimetype-profile-mappings> + <profiles> + <profile name="oggflac2raw" enabled="no" type="external"> + <mimetype>audio/L16</mimetype> + <accept-url>no</accept-url> + <first-resource>yes</first-resource> + <accept-ogg-theora>no</accept-ogg-theora> + <agent command="ogg123" arguments="-d raw -o byteorder:big -f %out %in"/> + <buffer size="1048576" chunk-size="131072" fill-size="262144"/> + </profile> + <profile name="vlcmpeg" enabled="no" type="external"> + <mimetype>video/mpeg</mimetype> + <accept-url>yes</accept-url> + <first-resource>yes</first-resource> + <accept-ogg-theora>yes</accept-ogg-theora> + <agent command="vlc" arguments="-I dummy %in --sout #transcode{venc=ffmpeg,vcodec=mp2v,vb=4096,fps=25,aenc=ffmpeg,acodec=mpga,ab=192,samplerate=44100,channels=2}:standard{access=file,mux=ps,dst=%out} vlc:quit"/> + <buffer size="14400000" chunk-size="512000" fill-size="120000"/> + </profile> + </profiles> + </transcoding> + </config> + ''; + +in { + + + ###### interface + + options = { + + services.mediatomb = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable the mediatomb DLNA server. + ''; + }; + + serverName = mkOption { + type = types.string; + default = "mediatomb"; + description = '' + How to identify the server on the network. + ''; + }; + + ps3Support = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable ps3 specific tweaks. + WARNING: incompatible with DSM 320 support. + ''; + }; + + dsmSupport = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable D-Link DSM 320 specific tweaks. + WARNING: incompatible with ps3 support. + ''; + }; + + tg100Support = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable Telegent TG100 specific tweaks. + ''; + }; + + transcoding = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable transcoding. + ''; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/mediatomb"; + description = '' + The directory where mediatomb stores its state, data, etc. + ''; + }; + + user = mkOption { + default = "mediatomb"; + description = "User account under which mediatomb runs."; + }; + + group = mkOption { + default = "mediatomb"; + description = "Group account under which mediatomb runs."; + }; + + port = mkOption { + default = 49152; + description = '' + The network port to listen on. + ''; + }; + + uuid = mkOption { + default = "fdfc8a4e-a3ad-4c1d-b43d-a2eedb03a687"; + description = '' + A unique (on your network) to identify the server by. + ''; + }; + + customCfg = mkOption { + type = types.bool; + default = false; + description = '' + Allow mediatomb to create and use its own config file inside ${cfg.dataDir}. + ''; + }; + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + systemd.services.mediatomb = { + description = "MediaTomb media Server"; + after = [ "local-fs.target" "network.target" ]; + wantedBy = [ "multi-user.target" ]; + path = [ pkgs.mediatomb ]; + serviceConfig.ExecStart = "${pkgs.mediatomb}/bin/mediatomb -p ${toString cfg.port} ${if cfg.customCfg then "" else "-c ${mtConf}"} -m ${cfg.dataDir}"; + serviceConfig.User = "${cfg.user}"; + }; + + users.extraGroups = optionalAttrs (cfg.group == "mediatomb") (singleton { + name = "mediatomb"; + gid = gid; + }); + + users.extraUsers = optionalAttrs (cfg.user == "mediatomb") (singleton { + name = "mediatomb"; + isSystemUser = true; + group = cfg.group; + home = "${cfg.dataDir}"; + createHome = true; + description = "Mediatomb DLNA Server User"; + }); + + networking.firewall = { + allowedUDPPorts = [ 1900 cfg.port ]; + allowedTCPPorts = [ cfg.port ]; + }; + }; +} diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix index f231998d8f47..6d25fef45768 100644 --- a/nixos/modules/services/misc/nix-daemon.nix +++ b/nixos/modules/services/misc/nix-daemon.nix @@ -20,6 +20,8 @@ let extraGroups = [ "nixbld" ]; }; + nixbldUsers = map makeNixBuildUser (range 1 cfg.nrBuildUsers); + nixConf = let # If we're using a chroot for builds, then provide /bin/sh in @@ -357,7 +359,9 @@ in nix.nrBuildUsers = mkDefault (lib.max 10 cfg.maxJobs); - users.extraUsers = map makeNixBuildUser (range 1 cfg.nrBuildUsers); + users.extraUsers = nixbldUsers; + + services.xserver.displayManager.hiddenUsers = map ({ name, ... }: name) nixbldUsers; system.activationScripts.nix = stringAfter [ "etc" "users" ] '' @@ -375,9 +379,6 @@ in /nix/var/nix/gcroots/per-user \ /nix/var/nix/profiles/per-user \ /nix/var/nix/gcroots/tmp - - ln -sf /nix/var/nix/profiles /nix/var/nix/gcroots/ - ln -sf /nix/var/nix/manifests /nix/var/nix/gcroots/ ''; }; diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix index c0d7885280a5..c570a01fb3b2 100644 --- a/nixos/modules/services/misc/nixos-manual.nix +++ b/nixos/modules/services/misc/nixos-manual.nix @@ -3,7 +3,7 @@ # of the virtual consoles. The latter is useful for the installation # CD. -{ config, lib, pkgs, baseModules, ... } @ extraArgs: +{ config, lib, pkgs, baseModules, ... }: with lib; @@ -14,11 +14,12 @@ let versionModule = { system.nixosVersionSuffix = config.system.nixosVersionSuffix; system.nixosRevision = config.system.nixosRevision; + nixpkgs.system = config.nixpkgs.system; }; eval = evalModules { modules = [ versionModule ] ++ baseModules; - args = (removeAttrs extraArgs ["config" "options"]) // { modules = [ ]; }; + args = (config._module.args) // { modules = [ ]; }; }; manual = import ../../../doc/manual { diff --git a/nixos/modules/services/misc/ripple-data-api.nix b/nixos/modules/services/misc/ripple-data-api.nix new file mode 100644 index 000000000000..6e5ac7ab00bd --- /dev/null +++ b/nixos/modules/services/misc/ripple-data-api.nix @@ -0,0 +1,168 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.rippleDataApi; + + deployment_env_config = builtins.toJSON { + production = { + port = toString cfg.port; + maxSockets = 150; + batchSize = 100; + startIndex = 32570; + rippleds = cfg.rippleds; + redis = { + enable = cfg.redis.enable; + host = cfg.redis.host; + port = cfg.redis.port; + options.auth_pass = null; + }; + }; + }; + + db_config = builtins.toJSON { + production = { + username = optional (cfg.couchdb.pass != "") cfg.couchdb.user; + password = optional (cfg.couchdb.pass != "") cfg.couchdb.pass; + host = cfg.couchdb.host; + port = cfg.couchdb.port; + database = cfg.couchdb.db; + protocol = "http"; + }; + }; + +in { + options = { + services.rippleDataApi = { + enable = mkEnableOption "Whether to enable ripple data api."; + + port = mkOption { + description = "Ripple data api port"; + default = 5993; + type = types.int; + }; + + redis = { + enable = mkOption { + description = "Whether to enable caching of ripple data to redis."; + default = true; + type = types.bool; + }; + + host = mkOption { + description = "Ripple data api redis host."; + default = "localhost"; + type = types.str; + }; + + port = mkOption { + description = "Ripple data api redis port."; + default = 5984; + type = types.int; + }; + }; + + couchdb = { + host = mkOption { + description = "Ripple data api couchdb host."; + default = "localhost"; + type = types.str; + }; + + port = mkOption { + description = "Ripple data api couchdb port."; + default = 5984; + type = types.int; + }; + + db = mkOption { + description = "Ripple data api couchdb database."; + default = "rippled"; + type = types.str; + }; + + user = mkOption { + description = "Ripple data api couchdb username."; + default = "rippled"; + type = types.str; + }; + + pass = mkOption { + description = "Ripple data api couchdb password."; + default = ""; + type = types.str; + }; + + create = mkOption { + description = "Whether to create couchdb database needed by ripple data api."; + type = types.bool; + default = true; + }; + }; + + rippleds = mkOption { + description = "List of rippleds to be used by ripple data api."; + default = [ + "http://s_east.ripple.com:51234" + "http://s_west.ripple.com:51234" + ]; + type = types.listOf types.str; + }; + }; + }; + + config = mkIf (cfg.enable) { + services.couchdb.enable = mkDefault true; + services.couchdb.bindAddress = mkDefault "0.0.0.0"; + services.redis.enable = mkDefault true; + + systemd.services.ripple-data-api = { + after = [ "couchdb.service" "redis.service" "ripple-data-api-importer.service" ]; + wantedBy = [ "multi-user.target" ]; + + environment = { + NODE_ENV = "production"; + DEPLOYMENT_ENVS_CONFIG = pkgs.writeText "deployment.environment.json" deployment_env_config; + DB_CONFIG = pkgs.writeText "db.config.json" db_config; + }; + + serviceConfig = { + ExecStart = "${pkgs.ripple-data-api}/bin/api"; + User = "ripple-data-api"; + }; + }; + + systemd.services.ripple-data-importer = { + after = [ "couchdb.service" ]; + wantedBy = [ "multi-user.target" ]; + path = [ pkgs.curl ]; + + environment = { + NODE_ENV = "production"; + DEPLOYMENT_ENVS_CONFIG = pkgs.writeText "deployment.environment.json" deployment_env_config; + DB_CONFIG = pkgs.writeText "db.config.json" db_config; + LOG_FILE = "/dev/null"; + }; + + serviceConfig = { + ExecStart = "${pkgs.ripple-data-api}/bin/importer live debug2"; + User = "ripple-data-api"; + }; + + preStart = mkMerge [ + (mkIf (cfg.couchdb.create) '' + HOST="http://${optionalString (cfg.couchdb.pass != "") "${cfg.couchdb.user}:${cfg.couchdb.pass}@"}${cfg.couchdb.host}:${toString cfg.couchdb.port}" + curl -X PUT $HOST/${cfg.couchdb.db} || true + '') + "${pkgs.ripple-data-api}/bin/update-views" + ]; + }; + + users.extraUsers = singleton + { name = "ripple-data-api"; + description = "Ripple data api user"; + uid = config.ids.uids.ripple-data-api; + }; + }; +} diff --git a/nixos/modules/services/misc/rippled.nix b/nixos/modules/services/misc/rippled.nix index 2c1fec9f6d7c..85a1ed8ae9e3 100644 --- a/nixos/modules/services/misc/rippled.nix +++ b/nixos/modules/services/misc/rippled.nix @@ -1,5 +1,3 @@ -# configuration building is commented out until better tested. - { config, lib, pkgs, ... }: with lib; @@ -7,266 +5,366 @@ with lib; let cfg = config.services.rippled; - rippledStateCfgFile = "/var/lib/rippled/rippled.cfg"; + b2i = val: if val then "1" else "0"; + + dbCfg = db: '' + type=${db.type} + path=${db.path} + ${optionalString (db.compression != null) ("compression=${b2i db.compression}") } + ${optionalString (db.onlineDelete != null) ("online_delete=${toString db.onlineDelete}")} + ${optionalString (db.advisoryDelete != null) ("advisory_delete=${toString db.advisoryDelete}")} + ${db.extraOpts} + ''; rippledCfg = '' + [server] + ${concatMapStringsSep "\n" (n: "port_${n}") (attrNames cfg.ports)} + + ${concatMapStrings (p: '' + [port_${p.name}] + ip=${p.ip} + port=${toString p.port} + protocol=${concatStringsSep "," p.protocol} + ${optionalString (p.user != "") "user=${p.user}"} + ${optionalString (p.password != "") "user=${p.password}"} + admin=${if p.admin then "allow" else "no"} + ${optionalString (p.ssl.key != null) "ssl_key=${p.ssl.key}"} + ${optionalString (p.ssl.cert != null) "ssl_cert=${p.ssl.cert}"} + ${optionalString (p.ssl.chain != null) "ssl_chain=${p.ssl.chain}"} + '') (attrValues cfg.ports)} + + [database_path] + ${cfg.databasePath} + [node_db] - type=HyperLevelDB - path=/var/lib/rippled/db/hyperldb + ${dbCfg cfg.nodeDb} - [debug_logfile] - /var/log/rippled/debug.log + ${optionalString (cfg.tempDb != null) '' + [temp_db] + ${dbCfg cfg.tempDb}''} - '' - + optionalString (cfg.peerIp != null) '' - [peer_ip] - ${cfg.peerIp} + ${optionalString (cfg.importDb != null) '' + [import_db] + ${dbCfg cfg.importDb}''} - [peer_port] - ${toString cfg.peerPort} + [ips] + ${concatStringsSep "\n" cfg.ips} - '' - + cfg.extraConfig; + [ips_fixed] + ${concatStringsSep "\n" cfg.ipsFixed} - rippledCfgFile = pkgs.writeText "rippled.cfg" rippledCfg; - -in + [validators] + ${concatStringsSep "\n" cfg.validators} -{ + [node_size] + ${cfg.nodeSize} - ###### interface + [ledger_history] + ${toString cfg.ledgerHistory} - options = { + [fetch_depth] + ${toString cfg.fetchDepth} - services.rippled = { + [validation_quorum] + ${toString cfg.validationQuorum} - enable = mkOption { - default = false; - description = "Whether to enable rippled"; - }; + [sntp_servers] + ${concatStringsSep "\n" cfg.sntpServers} - # - # Rippled has a simple configuration file layout that is easy to - # build with nix. Many of the options are defined here but are - # commented out until the code to append them to the config above - # is written and they are tested. - # - # If you find a yourself implementing more options, please submit a - # pull request. - # - - /* - ips = mkOption { - default = [ "r.ripple.com 51235" ]; - example = [ "192.168.0.1" "192.168.0.1 3939" "r.ripple.com 51235" ]; - description = '' - List of hostnames or ips where the Ripple protocol is served. - For a starter list, you can either copy entries from: - https://ripple.com/ripple.txt or if you prefer you can let it - default to r.ripple.com 51235 + [rpc_startup] + { "command": "log_level", "severity": "${cfg.logLevel}" } + '' + cfg.extraConfig; - A port may optionally be specified after adding a space to the - address. By convention, if known, IPs are listed in from most - to least trusted. - ''; + portOptions = { name, ...}: { + options = { + name = mkOption { + internal = true; + default = name; }; - ipsFixed = mkOption { - default = null; - example = [ "192.168.0.1" "192.168.0.1 3939" "r.ripple.com 51235" ]; - description = '' - List of IP addresses or hostnames to which rippled should always - attempt to maintain peer connections with. This is useful for - manually forming private networks, for example to configure a - validation server that connects to the Ripple network through a - public-facing server, or for building a set of cluster peers. + ip = mkOption { + default = "127.0.0.1"; + description = "Ip where rippled listens."; + type = types.str; + }; - A port may optionally be specified after adding a space to the address - ''; + port = mkOption { + description = "Port where rippled listens."; + type = types.int; }; - */ - peerIp = mkOption { - default = null; - example = "0.0.0.0"; - description = '' - IP address or domain to bind to allow external connections from peers. - Defaults to not binding, which disallows external connections from peers. - ''; + protocol = mkOption { + description = "Protocols expose by rippled."; + type = types.listOf (types.enum ["http" "https" "ws" "wss" "peer"]); }; - peerPort = mkOption { - default = 51235; - description = '' - If peerIp is supplied, corresponding port to bind to for peer connections. - ''; + user = mkOption { + description = "When set, these credentials will be required on HTTP/S requests."; + type = types.str; + default = ""; }; - /* - peerPortProxy = mkOption { - type = types.int; - example = 51236; - description = '' - An optional, additional listening port number for peers. Incoming - connections on this port will be required to provide a PROXY Protocol - handshake, described in this document (external link): + password = mkOption { + description = "When set, these credentials will be required on HTTP/S requests."; + type = types.str; + default = ""; + }; - http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt + admin = mkOption { + description = "Controls whether or not administrative commands are allowed."; + type = types.bool; + default = false; + }; - The PROXY Protocol is a popular method used by elastic load balancing - service providers such as Amazon, to identify the true IP address and - port number of external incoming connections. + ssl = { + key = mkOption { + description = '' + Specifies the filename holding the SSL key in PEM format. + ''; + default = null; + type = types.nullOr types.path; + }; + + cert = mkOption { + description = '' + Specifies the path to the SSL certificate file in PEM format. + This is not needed if the chain includes it. + ''; + default = null; + type = types.nullOr types.path; + }; + + chain = mkOption { + description = '' + If you need a certificate chain, specify the path to the + certificate chain here. The chain may include the end certificate. + ''; + default = null; + type = types.nullOr types.path; + }; - In addition to enabling this setting, it will also be required to - use your provider-specific control panel or administrative web page - to configure your server instance to receive PROXY Protocol handshakes, - and also to restrict access to your instance to the Elastic Load Balancer. - ''; }; - - peerPrivate = mkOption { - default = null; - example = 0; - description = '' - 0: Request peers to broadcast your address. Normal outbound peer connections [default] - 1: Request peers not broadcast your address. Only connect to configured peers. - ''; - }; - - peerSslCipherList = mkOption { - default = null; - example = "ALL:!LOW:!EXP:!MD5:@STRENGTH"; - description = '' - A colon delimited string with the allowed SSL cipher modes for peer. The - choices for for ciphers are defined by the OpenSSL API function - SSL_CTX_set_cipher_list, documented here (external link): - - http://pic.dhe.ibm.com/infocenter/tpfhelp/current/index.jsp?topic=%2Fcom.ibm.ztpf-ztpfdf.doc_put.cur%2Fgtpc2%2Fcpp_ssl_ctx_set_cipher_list.html - - The default setting of "ALL:!LOW:!EXP:!MD5:@STRENGTH", which allows - non-authenticated peer connections (they are, however, secure). - ''; }; + }; - nodeSeed = mkOption { - default = null; - example = "RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE"; - description = '' - This is used for clustering. To force a particular node seed or key, the - key can be set here. The format is the same as the validation_seed field. - To obtain a validation seed, use the rippled validation_create command. - ''; + dbOptions = { + type = mkOption { + description = "Rippled database type."; + type = types.enum ["rocksdb" "nudb" "sqlite"]; + default = "rocksdb"; }; - clusterNodes = mkOption { - default = null; - example = [ "n9KorY8QtTdRx7TVDpwnG9NvyxsDwHUKUEeDLY3AkiGncVaSXZi5" ]; - description = '' - To extend full trust to other nodes, place their node public keys here. - Generally, you should only do this for nodes under common administration. - Node public keys start with an 'n'. To give a node a name for identification - place a space after the public key and then the name. - ''; + path = mkOption { + description = "Location to store the database."; + type = types.path; + default = cfg.databasePath; }; - sntpServers = mkOption { + compression = mkOption { + description = "Whether to enable snappy compression."; + type = types.nullOr types.bool; default = null; - example = [ "time.nist.gov" "pool.ntp.org" ]; - description = '' - IP address or domain of NTP servers to use for time synchronization. - ''; }; - # TODO: websocket options - - rpcAllowRemote = mkOption { - default = false; - description = '' - false: Allow RPC connections only from 127.0.0.1. [default] - true: Allow RPC connections from any IP. - ''; + onlineDelete = mkOption { + description = "Enable automatic purging of older ledger information."; + type = types.addCheck (types.nullOr types.int) (v: v > 256); + default = cfg.ledgerHistory; }; - rpcAdminAllow = mkOption { - example = [ "10.0.0.4" ]; + advisoryDelete = mkOption { description = '' - List of IP addresses allowed to have admin access. + If set, then require administrative RPC call "can_delete" + to enable online deletion of ledger records. ''; + type = types.nullOr types.bool; + default = null; }; - rpcAdminUser = mkOption { - type = types.str; - description = '' - As a server, require this as the admin user to be specified. Also, require - rpc_admin_user and rpc_admin_password to be checked for RPC admin functions. - The request must specify these as the admin_user and admin_password in the - request object. - ''; + extraOpts = mkOption { + description = "Extra database options."; + type = types.lines; + default = ""; }; + }; - rpcAdminPassword = mkOption { - type = types.str; - description = '' - As a server, require this as the admin pasword to be specified. Also, - require rpc_admin_user and rpc_admin_password to be checked for RPC admin - functions. The request must specify these as the admin_user and - admin_password in the request object. - ''; - }; +in + +{ + + ###### interface + + options = { + services.rippled = { + enable = mkEnableOption "Whether to enable rippled"; + + package = mkOption { + description = "Which rippled package to use."; + type = types.package; + default = pkgs.rippled; + }; + + ports = mkOption { + description = "Ports exposed by rippled"; + type = types.attrsOf types.optionSet; + options = [portOptions]; + default = { + rpc = { + port = 5005; + admin = true; + protocol = ["http"]; + }; + + peer = { + port = 51235; + ip = "0.0.0.0"; + protocol = ["peer"]; + }; + + ws_public = { + port = 5006; + ip = "0.0.0.0"; + protocol = ["ws" "wss"]; + }; + }; + }; - rpcIp = mkOption { - type = types.str; + nodeDb = mkOption { + description = "Rippled main database options."; + type = types.nullOr types.optionSet; + options = [dbOptions]; + default = { + type = "rocksdb"; + extraOpts = '' + open_files=2000 + filter_bits=12 + cache_mb=256 + file_size_pb=8 + file_size_mult=2; + ''; + }; + }; + + tempDb = mkOption { + description = "Rippled temporary database options."; + type = types.nullOr types.optionSet; + options = [dbOptions]; + default = null; + }; + + importDb = mkOption { + description = "Settings for performing a one-time import."; + type = types.nullOr types.optionSet; + options = [dbOptions]; + default = null; + }; + + nodeSize = mkOption { description = '' - IP address or domain to bind to allow insecure RPC connections. - Defaults to not binding, which disallows RPC connections. + Rippled size of the node you are running. + "tiny", "small", "medium", "large", and "huge" ''; + type = types.enum ["tiny" "small" "medium" "large" "huge"]; + default = "small"; }; - rpcPort = mkOption { - type = types.int; - description = '' - If rpcIp is supplied, corresponding port to bind to for peer connections. - ''; + ips = mkOption { + description = '' + List of hostnames or ips where the Ripple protocol is served. + For a starter list, you can either copy entries from: + https://ripple.com/ripple.txt or if you prefer you can let it + default to r.ripple.com 51235 + + A port may optionally be specified after adding a space to the + address. By convention, if known, IPs are listed in from most + to least trusted. + ''; + type = types.listOf types.str; + default = ["r.ripple.com 51235"]; + }; + + ipsFixed = mkOption { + description = '' + List of IP addresses or hostnames to which rippled should always + attempt to maintain peer connections with. This is useful for + manually forming private networks, for example to configure a + validation server that connects to the Ripple network through a + public-facing server, or for building a set of cluster peers. + + A port may optionally be specified after adding a space to the address + ''; + type = types.listOf types.str; + default = []; + }; + + validators = mkOption { + description = '' + List of nodes to always accept as validators. Nodes are specified by domain + or public key. + ''; + type = types.listOf types.str; + default = [ + "n949f75evCHwgyP4fPVgaHqNHxUVN15PsJEZ3B3HnXPcPjcZAoy7 RL1" + "n9MD5h24qrQqiyBC8aeqqCWvpiBiYQ3jxSr91uiDvmrkyHRdYLUj RL2" + "n9L81uNCaPgtUJfaHh89gmdvXKAmSt5Gdsw2g1iPWaPkAHW5Nm4C RL3" + "n9KiYM9CgngLvtRCQHZwgC2gjpdaZcCcbt3VboxiNFcKuwFVujzS RL4" + "n9LdgEtkmGB9E2h3K4Vp7iGUaKuq23Zr32ehxiU8FWY7xoxbWTSA RL5" + ]; }; - rpcUser = mkOption { - type = types.str; + databasePath = mkOption { description = '' - Require a this user to specified and require rpcPassword to - be checked for RPC access via the rpcIp and rpcPort. The user and password - must be specified via HTTP's basic authentication method. - As a client, supply this to the server via HTTP's basic authentication - method. + Path to the ripple database. ''; + type = types.path; + default = "/var/lib/rippled/db"; }; - rpcPassword = mkOption { - type = types.str; + validationQuorum = mkOption { description = '' - Require a this password to specified and require rpc_user to - be checked for RPC access via the rpcIp and rpcPort. The user and password - must be specified via HTTP's basic authentication method. - As a client, supply this to the server via HTTP's basic authentication - method. + The minimum number of trusted validations a ledger must have before + the server considers it fully validated. ''; + type = types.int; + default = 3; }; - rpcStartup = mkOption { - example = [ ''"command" : "log_level"'' ''"partition" : "ripplecalc"'' ''"severity" : "trace"'' ]; - description = "List of RPC commands to run at startup."; + ledgerHistory = mkOption { + description = '' + The number of past ledgers to acquire on server startup and the minimum + to maintain while running. + ''; + type = types.either types.int (types.enum ["full"]); + default = 1296000; # 1 month }; - rpcSecure = mkOption { - default = false; + fetchDepth = mkOption { description = '' - false: Server certificates are not provided for RPC clients using SSL [default] - true: Client RPC connections wil be provided with SSL certificates. + The number of past ledgers to serve to other peers that request historical + ledger data (or "full" for no limit). + ''; + type = types.either types.int (types.enum ["full"]); + default = "full"; + }; - Note that if rpc_secure is enabled, it will also be necessasry to configure the - certificate file settings located in rpcSslCert, rpcSslChain, and rpcSslKey + sntpServers = mkOption { + description = '' + IP address or domain of NTP servers to use for time synchronization.; ''; + type = types.listOf types.str; + default = [ + "time.windows.com" + "time.apple.com" + "time.nist.gov" + "pool.ntp.org" + ]; + }; + + logLevel = mkOption { + description = "Logging verbosity."; + type = types.enum ["debug" "error" "info"]; + default = "error"; }; - */ extraConfig = mkOption { default = ""; @@ -275,8 +373,11 @@ in ''; }; + config = mkOption { + internal = true; + default = pkgs.writeText "rippled.conf" rippledCfg; + }; }; - }; @@ -288,27 +389,21 @@ in { name = "rippled"; description = "Ripple server user"; uid = config.ids.uids.rippled; - home = "/var/lib/rippled"; + home = cfg.databasePath; + createHome = true; }; systemd.services.rippled = { - path = [ pkgs.rippled ]; - after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { - ExecStart = "${pkgs.rippled}/bin/rippled --fg -q --conf ${rippledStateCfgFile}"; - WorkingDirectory = "/var/lib/rippled"; + ExecStart = "${cfg.package}/bin/rippled --fg --conf ${cfg.config}"; + User = "rippled"; }; }; - networking.firewall.allowedTCPPorts = mkIf (cfg.peerIp != null) [ cfg.peerPort ]; + environment.systemPackages = [ cfg.package ]; - system.activationScripts.rippled = '' - mkdir -p /var/{lib,log}/rippled - chown -R rippled /var/{lib,log}/rippled - ln -sf ${rippledCfgFile} ${rippledStateCfgFile} - ''; }; } diff --git a/nixos/modules/services/monitoring/cadvisor.nix b/nixos/modules/services/monitoring/cadvisor.nix index 0a06291da2a4..b6cf397f35c0 100644 --- a/nixos/modules/services/monitoring/cadvisor.nix +++ b/nixos/modules/services/monitoring/cadvisor.nix @@ -90,17 +90,9 @@ in { ${optionalString cfg.storageDriverSecure "-storage_driver_secure"} ''} ''; - User = "cadvisor"; }; }; - virtualisation.docker.enable = true; - - users.extraUsers = singleton { - name = "cadvisor"; - uid = config.ids.uids.cadvisor; - description = "Cadvisor user"; - extraGroups = [ "docker" ]; - }; + virtualisation.docker.enable = mkDefault true; }; } diff --git a/nixos/modules/services/monitoring/munin.nix b/nixos/modules/services/monitoring/munin.nix index 8558c4ff8e48..31afa859e256 100644 --- a/nixos/modules/services/monitoring/munin.nix +++ b/nixos/modules/services/monitoring/munin.nix @@ -34,7 +34,7 @@ let cap=$(sed -nr 's/.*#%#\s+capabilities\s*=\s*(.+)/\1/p' $file) wrapProgram $file \ - --set PATH "/var/setuid-wrappers:/run/current-system/sw/bin:/run/current-system/sw/sbin" \ + --set PATH "/var/setuid-wrappers:/run/current-system/sw/bin:/run/current-system/sw/bin" \ --set MUNIN_LIBDIR "${pkgs.munin}/lib" \ --set MUNIN_PLUGSTATE "/var/run/munin" @@ -194,7 +194,7 @@ in mkdir -p /etc/munin/plugins rm -rf /etc/munin/plugins/* - PATH="/var/setuid-wrappers:/run/current-system/sw/bin:/run/current-system/sw/sbin" ${pkgs.munin}/sbin/munin-node-configure --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${muninPlugins} --servicedir=/etc/munin/plugins 2>/dev/null | ${pkgs.bash}/bin/bash + PATH="/var/setuid-wrappers:/run/current-system/sw/bin:/run/current-system/sw/bin" ${pkgs.munin}/sbin/munin-node-configure --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${muninPlugins} --servicedir=/etc/munin/plugins 2>/dev/null | ${pkgs.bash}/bin/bash ''; serviceConfig = { ExecStart = "${pkgs.munin}/sbin/munin-node --config ${nodeConf} --servicedir /etc/munin/plugins/"; diff --git a/nixos/modules/services/monitoring/scollector.nix b/nixos/modules/services/monitoring/scollector.nix index ce70739abbc4..0143d2e327bd 100644 --- a/nixos/modules/services/monitoring/scollector.nix +++ b/nixos/modules/services/monitoring/scollector.nix @@ -20,6 +20,10 @@ let cfg.collectors)} ''; + cmdLineOpts = concatStringsSep " " ( + [ "-h=${cfg.bosunHost}" "-c=${collectors}" ] ++ cfg.extraOpts + ); + in { options = { @@ -79,6 +83,15 @@ in { ''; }; + extraOpts = mkOption { + type = with types; listOf str; + default = []; + example = [ "-d" ]; + description = '' + Extra scollector command line options + ''; + }; + }; }; @@ -95,9 +108,7 @@ in { PermissionsStartOnly = true; User = cfg.user; Group = cfg.group; - ExecStart = '' - ${cfg.package}/bin/scollector -h=${cfg.bosunHost} -c=${collectors} - ''; + ExecStart = "${cfg.package}/bin/scollector ${cmdLineOpts}"; }; }; diff --git a/nixos/modules/services/monitoring/teamviewer.nix b/nixos/modules/services/monitoring/teamviewer.nix new file mode 100644 index 000000000000..beba5dcd1b06 --- /dev/null +++ b/nixos/modules/services/monitoring/teamviewer.nix @@ -0,0 +1,45 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.teamviewer; + +in + +{ + + ###### interface + + options = { + + services.teamviewer.enable = mkEnableOption "teamviewer daemon"; + + }; + + ###### implementation + + config = mkIf (cfg.enable) { + + environment.systemPackages = [ pkgs.teamviewer ]; + + systemd.services.teamviewerd = { + description = "TeamViewer remote control daemon"; + + wantedBy = [ "graphical.target" ]; + after = [ "NetworkManager-wait-online.service" "network.target" ]; + + serviceConfig = { + Type = "forking"; + ExecStart = "${pkgs.teamviewer}/bin/teamviewerd -d"; + PIDFile = "/run/teamviewerd.pid"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + Restart = "on-abort"; + StartLimitInterval = "60"; + StartLimitBurst = "10"; + }; + }; + }; + +} diff --git a/nixos/modules/services/network-filesystems/drbd.nix b/nixos/modules/services/network-filesystems/drbd.nix index b914724abfe2..1bd67206444e 100644 --- a/nixos/modules/services/network-filesystems/drbd.nix +++ b/nixos/modules/services/network-filesystems/drbd.nix @@ -44,7 +44,7 @@ let cfg = config.services.drbd; in boot.extraModprobeConfig = '' - options drbd usermode_helper=/run/current-system/sw/sbin/drbdadm + options drbd usermode_helper=/run/current-system/sw/bin/drbdadm ''; environment.etc = singleton diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix index 8c79bf663d15..d6babb8e9a51 100644 --- a/nixos/modules/services/network-filesystems/samba.nix +++ b/nixos/modules/services/network-filesystems/samba.nix @@ -27,7 +27,7 @@ let [ global ] security = ${cfg.securityType} passwd program = /var/setuid-wrappers/passwd %u - pam password change = ${toString cfg.syncPasswordsByPam} + pam password change = ${if cfg.syncPasswordsByPam then "yes" else "no"} invalid users = ${toString cfg.invalidUsers} ${cfg.extraConfig} diff --git a/nixos/modules/services/network-filesystems/u9fs.nix b/nixos/modules/services/network-filesystems/u9fs.nix new file mode 100644 index 000000000000..648097274641 --- /dev/null +++ b/nixos/modules/services/network-filesystems/u9fs.nix @@ -0,0 +1,75 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.u9fs; +in +{ + + options = { + + services.u9fs = { + + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to run the u9fs 9P server for Unix."; + }; + + listenStreams = mkOption { + type = types.listOf types.str; + default = [ "564" ]; + example = [ "192.168.16.1:564" ]; + description = '' + Sockets to listen for clients on. + See <command>man 5 systemd.socket</command> for socket syntax. + ''; + }; + + extraArgs = mkOption { + type = types.str; + default = ""; + example = "-a none -u nobody"; + description = + '' + Extra arguments to pass on invocation, + see <command>man 4 u9fs</command> + ''; + }; + + fsroot = mkOption { + type = types.path; + default = "/"; + example = "/srv"; + description = "File system root to serve to clients."; + }; + + }; + + }; + + config = mkIf cfg.enable { + + systemd = { + sockets.u9fs = { + description = "U9fs Listening Socket"; + wantedBy = [ "sockets.target" ]; + inherit (cfg) listenStreams; + socketConfig.Accept = "yes"; + }; + services."u9fs@" = { + description = "9P Protocol Server"; + reloadIfChanged = true; + requires = [ "u9fs.socket" ]; + serviceConfig = + { ExecStart = "-${pkgs.u9fs}/bin/u9fs ${cfg.extraArgs} ${cfg.fsroot}"; + StandardInput = "socket"; + StandardError = "journal"; + }; + }; + }; + + }; + +} diff --git a/nixos/modules/services/networking/aiccu.nix b/nixos/modules/services/networking/aiccu.nix new file mode 100644 index 000000000000..4301da288814 --- /dev/null +++ b/nixos/modules/services/networking/aiccu.nix @@ -0,0 +1,195 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.aiccu; + showBool = b: if b then "true" else "false"; + notNull = a: ! isNull a; + configFile = pkgs.writeText "aiccu.conf" '' + ${if notNull cfg.username then "username " + cfg.username else ""} + ${if notNull cfg.password then "password " + cfg.password else ""} + protocol ${cfg.protocol} + server ${cfg.server} + ipv6_interface ${cfg.interfaceName} + verbose ${showBool cfg.verbose} + daemonize true + automatic ${showBool cfg.automatic} + requiretls ${showBool cfg.requireTLS} + pidfile ${cfg.pidFile} + defaultroute ${showBool cfg.defaultRoute} + ${if notNull cfg.setupScript then cfg.setupScript else ""} + makebeats ${showBool cfg.makeHeartBeats} + noconfigure ${showBool cfg.noConfigure} + behindnat ${showBool cfg.behindNAT} + ${if cfg.localIPv4Override then "local_ipv4_override" else ""} + ''; + +in { + + options = { + + services.aiccu = { + + enable = mkOption { + type = types.bool; + default = false; + example = true; + description = "Enable aiccu IPv6 over IPv4 SiXXs tunnel"; + }; + + username = mkOption { + type = with types; nullOr str; + default = null; + example = "FAB5-SIXXS"; + description = "Login credential"; + }; + + password = mkOption { + type = with types; nullOr str; + default = null; + example = "TmAkRbBEr0"; + description = "Login credential"; + }; + + protocol = mkOption { + type = types.str; + default = "tic"; + example = "tic|tsp|l2tp"; + description = "Protocol to use for setting up the tunnel"; + }; + + server = mkOption { + type = types.str; + default = "tic.sixxs.net"; + example = "enabled.ipv6server.net"; + description = "Server to use for setting up the tunnel"; + }; + + interfaceName = mkOption { + type = types.str; + default = "aiccu"; + example = "sixxs"; + description = '' + The name of the interface that will be used as a tunnel interface. + On *BSD the ipv6_interface should be set to gifX (eg gif0) for proto-41 tunnels + or tunX (eg tun0) for AYIYA tunnels. + ''; + }; + + tunnelID = mkOption { + type = with types; nullOr str; + default = null; + example = "T12345"; + description = "The tunnel id to use, only required when there are multiple tunnels in the list"; + }; + + verbose = mkOption { + type = types.bool; + default = false; + example = true; + description = "Be verbose?"; + }; + + automatic = mkOption { + type = types.bool; + default = true; + example = false; + description = "Automatic Login and Tunnel activation"; + }; + + requireTLS = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + When set to true, if TLS is not supported on the server + the TIC transaction will fail. + When set to false, it will try a starttls, when that is + not supported it will continue. + In any case if AICCU is build with TLS support it will + try to do a 'starttls' to the TIC server to see if that + is supported. + ''; + }; + + pidFile = mkOption { + type = types.path; + default = "/run/aiccu.pid"; + example = "/var/lib/aiccu/aiccu.pid"; + description = "Location of PID File"; + }; + + defaultRoute = mkOption { + type = types.bool; + default = true; + example = false; + description = "Add a default route"; + }; + + setupScript = mkOption { + type = with types; nullOr path; + default = null; + example = "/var/lib/aiccu/fix-subnets.sh"; + description = "Script to run after setting up the interfaces"; + }; + + makeHeartBeats = mkOption { + type = types.bool; + default = true; + example = false; + description = '' + In general you don't want to turn this off + Of course only applies to AYIYA and heartbeat tunnels not to static ones + ''; + }; + + noConfigure = mkOption { + type = types.bool; + default = false; + example = true; + description = "Don't configure anything"; + }; + + behindNAT = mkOption { + type = types.bool; + default = false; + example = true; + description = "Notify the user that a NAT-kind network is detected"; + }; + + localIPv4Override = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + Overrides the IPv4 parameter received from TIC + This allows one to configure a NAT into "DMZ" mode and then + forwarding the proto-41 packets to an internal host. + + This is only needed for static proto-41 tunnels! + AYIYA and heartbeat tunnels don't require this. + ''; + }; + + }; + }; + + config = mkIf cfg.enable { + + systemd.services.aiccu = { + description = "Automatic IPv6 Connectivity Client Utility"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkgs.aiccu}/bin/aiccu start ${configFile}"; + ExecStop = "${pkgs.aiccu}/bin/aiccu stop"; + Type = "forking"; + PIDFile = cfg.pidFile; + Restart = "no"; # aiccu startup errors are serious, do not pound the tic server or be banned. + }; + }; + + }; +} diff --git a/nixos/modules/services/networking/btsync.nix b/nixos/modules/services/networking/btsync.nix index 34bddf908731..8b90f295ed46 100644 --- a/nixos/modules/services/networking/btsync.nix +++ b/nixos/modules/services/networking/btsync.nix @@ -4,6 +4,9 @@ with lib; let cfg = config.services.btsync; + + bittorrentSync = cfg.package; + listenAddr = cfg.httpListenAddr + ":" + (toString cfg.httpListenPort); boolStr = x: if x then "true" else "false"; @@ -57,7 +60,7 @@ let '' { "device_name": "${cfg.deviceName}", - "storage_path": "/var/lib/btsync/", + "storage_path": "${cfg.storagePath}", "listening_port": ${toString cfg.listeningPort}, "use_gui": false, @@ -195,6 +198,23 @@ in ''; }; + package = mkOption { + type = types.package; + example = literalExample "pkgs.bittorrentSync20"; + description = '' + Branch of bittorrent sync to use. + ''; + }; + + storagePath = mkOption { + type = types.path; + default = "/var/lib/btsync"; + example = "/var/lib/btsync"; + description = '' + Where to store the bittorrent sync files. + ''; + }; + apiKey = mkOption { type = types.str; default = ""; @@ -256,9 +276,11 @@ in } ]; + services.btsync.package = mkOptionDefault pkgs.bittorrentSync14; + users.extraUsers.btsync = { description = "Bittorrent Sync Service user"; - home = "/var/lib/btsync"; + home = cfg.storagePath; createHome = true; uid = config.ids.uids.btsync; group = "btsync"; @@ -292,6 +314,6 @@ in }; }; - environment.systemPackages = [ pkgs.bittorrentSync ]; + environment.systemPackages = [ cfg.package ]; }; } diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix index 3ae010e81070..5308fd995085 100644 --- a/nixos/modules/services/networking/consul.nix +++ b/nixos/modules/services/networking/consul.nix @@ -178,7 +178,7 @@ in ExecReload = "${pkgs.consul}/bin/consul reload"; PermissionsStartOnly = true; User = if cfg.dropPrivileges then "consul" else null; - TimeoutStartSec = "${toString (20 + (3 * cfg.joinRetries))}s"; + TimeoutStartSec = "0"; } // (optionalAttrs (cfg.leaveOnStop) { ExecStop = "${pkgs.consul}/bin/consul leave"; }); @@ -209,13 +209,14 @@ in echo "$ADDR" } echo "{" > /etc/consul-addrs.json + delim=" " '' + concatStrings (flip mapAttrsToList cfg.interface (name: i: optionalString (i != null) '' - echo " \"${name}_addr\": \"$(getAddr "${i}")\"," >> /etc/consul-addrs.json + echo "$delim \"${name}_addr\": \"$(getAddr "${i}")\"" >> /etc/consul-addrs.json + delim="," '')) + '' - echo " \"\": \"\"" >> /etc/consul-addrs.json echo "}" >> /etc/consul-addrs.json ''; postStart = '' diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix index bb94a8dacfa2..f01deb6ee7c8 100644 --- a/nixos/modules/services/networking/ddclient.nix +++ b/nixos/modules/services/networking/ddclient.nix @@ -3,24 +3,22 @@ let inherit (lib) mkOption mkIf singleton; - inherit (pkgs) ddclient; stateDir = "/var/spool/ddclient"; - ddclientUser = "ddclient"; - - ddclientFlags = "-foreground -file ${ddclientCfg}"; - + ddclientFlags = "-foreground -verbose -noquiet -file ${ddclientCfg}"; + ddclientPIDFile = "${stateDir}/ddclient.pid"; ddclientCfg = pkgs.writeText "ddclient.conf" '' daemon=600 cache=${stateDir}/ddclient.cache - pid=${stateDir}/ddclient.pid - use=${config.services.ddclient.web} + pid=${ddclientPIDFile} + use=${config.services.ddclient.use} login=${config.services.ddclient.username} password=${config.services.ddclient.password} protocol=${config.services.ddclient.protocol} server=${config.services.ddclient.server} + ssl=${if config.services.ddclient.ssl then "yes" else "yes"} wildcard=YES ${config.services.ddclient.domain} ${config.services.ddclient.extraConfig} @@ -34,10 +32,11 @@ in options = { - services.ddclient = { + services.ddclient = with lib.types; { enable = mkOption { default = false; + type = bool; description = '' Whether to synchronise your machine's IP address with a dynamic DNS provider (e.g. dyndns.org). ''; @@ -45,6 +44,7 @@ in domain = mkOption { default = ""; + type = str; description = '' Domain name to synchronize. ''; @@ -52,76 +52,93 @@ in username = mkOption { default = ""; + type = str; description = '' Username. ''; }; password = mkOption { - default = "" ; + default = ""; + type = str; description = '' Password. ''; }; protocol = mkOption { - default = "dyndns2" ; + default = "dyndns2"; + type = str; description = '' - Protocol to use with dynamic DNS provider. (see also, http://sourceforge.net/apps/trac/ddclient/wiki/Protocols) + Protocol to use with dynamic DNS provider (see http://sourceforge.net/apps/trac/ddclient/wiki/Protocols). ''; }; server = mkOption { - default = "members.dyndns.org" ; + default = ""; + type = str; description = '' - Server + Server address. + ''; + }; + + ssl = mkOption { + default = true; + type = bool; + description = '' + Whether to use to use SSL/TLS to connect to dynamic DNS provider. ''; }; extraConfig = mkOption { - default = "" ; + default = ""; + type = str; description = '' Extra configuration. Contents will be added verbatim to the configuration file. ''; }; - web = mkOption { - default = "web, web=checkip.dyndns.com/, web-skip='Current IP Address: '" ; - description = ""; + use = mkOption { + default = "web, web=checkip.dyndns.com/, web-skip='Current IP Address: '"; + type = str; + description = '' + Method to determine the IP address to send to the dymanic DNS provider. + ''; }; - }; - }; ###### implementation config = mkIf config.services.ddclient.enable { - - environment.systemPackages = [ ddclient ]; - - users.extraUsers = singleton - { name = ddclientUser; - uid = config.ids.uids.ddclient; - description = "ddclient daemon user"; - home = stateDir; - }; - - jobs.ddclient = - { name = "ddclient"; - startOn = "startup"; + environment.systemPackages = [ ddclient ]; - preStart = - '' - mkdir -m 0755 -p ${stateDir} - chown ${ddclientUser} ${stateDir} - ''; + users.extraUsers = singleton { + name = ddclientUser; + uid = config.ids.uids.ddclient; + description = "ddclient daemon user"; + home = stateDir; + }; - exec = "${ddclient}/bin/ddclient ${ddclientFlags}"; + systemd.services.ddclient = { + description = "Dynamic DNS Client"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + # This may change back to forking if too many problems occur: + type = "simple"; + User = ddclientUser; + Group = "nogroup"; #TODO get this to work + PermissionsStartOnly = "true"; + PIDFile = ddclientPIDFile; + ExecStartPre = '' + ${pkgs.stdenv.shell} -c "${pkgs.coreutils}/bin/mkdir -m 0755 -p ${stateDir} && ${pkgs.coreutils}/bin/chown ${ddclientUser} ${stateDir}" + ''; + ExecStart = "${ddclient}/bin/ddclient ${ddclientFlags}"; + #ExecStartPost = "${pkgs.coreutils}/bin/rm -r ${stateDir}"; # Should we have this? }; - + }; }; - } diff --git a/nixos/modules/services/networking/dnsmasq.nix b/nixos/modules/services/networking/dnsmasq.nix index fbb211911f1c..7ddabf73106e 100644 --- a/nixos/modules/services/networking/dnsmasq.nix +++ b/nixos/modules/services/networking/dnsmasq.nix @@ -82,7 +82,7 @@ in systemd.services.dnsmasq = { description = "dnsmasq daemon"; - after = [ "network.target" "systemd-resolved.conf" ]; + after = [ "network.target" "systemd-resolved.service" ]; wantedBy = [ "multi-user.target" ]; path = [ dnsmasq ]; preStart = '' diff --git a/nixos/modules/services/networking/haproxy.nix b/nixos/modules/services/networking/haproxy.nix index 887ea79c34b1..09e48ec4bff0 100644 --- a/nixos/modules/services/networking/haproxy.nix +++ b/nixos/modules/services/networking/haproxy.nix @@ -18,42 +18,8 @@ with lib; }; config = mkOption { - type = types.lines; - default = - '' - global - log 127.0.0.1 local6 - maxconn 24000 - daemon - nbproc 1 - - defaults - mode http - option httpclose - - # Remove requests from the queue if people press stop button - option abortonclose - - # Try to connect this many times on failure - retries 3 - - # If a client is bound to a particular backend but it goes down, - # send them to a different one - option redispatch - - monitor-uri /haproxy-ping - - timeout connect 7s - timeout queue 300s - timeout client 300s - timeout server 300s - - # Enable status page at this URL, on the port HAProxy is bound to - stats enable - stats uri /haproxy-status - stats refresh 5s - stats realm Haproxy statistics - ''; + type = types.nullOr types.lines; + default = null; description = '' Contents of the HAProxy configuration file, <filename>haproxy.conf</filename>. @@ -66,6 +32,11 @@ with lib; config = mkIf cfg.enable { + assertions = [{ + assertion = cfg.config != null; + message = "You must provide services.haproxy.config."; + }]; + systemd.services.haproxy = { description = "HAProxy"; after = [ "network.target" ]; diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix index f72c7fb39d6c..f00c5d1f701d 100644 --- a/nixos/modules/services/networking/networkmanager.nix +++ b/nixos/modules/services/networking/networkmanager.nix @@ -71,6 +71,13 @@ let ${coreutils}/bin/rm -f $tmp $tmp.ns ''; + # pre-up and pre-down hooks were added in NM 0.9.10, but we still use 0.9.0 + dispatcherTypesSubdirMap = { + "basic" = ""; + /*"pre-up" = "pre-up.d/"; + "pre-down" = "pre-down.d/";*/ + }; + in { ###### interface @@ -118,6 +125,30 @@ in { ''; }; + dispatcherScripts = mkOption { + type = types.listOf (types.submodule { + options = { + source = mkOption { + type = types.str; + description = '' + A script source. + ''; + }; + + type = mkOption { + type = types.enum (attrNames dispatcherTypesSubdirMap); + default = "basic"; + description = '' + Dispatcher hook type. Only basic hooks are currently available. + ''; + }; + }; + }); + default = []; + description = '' + A list of scripts which will be executed in response to network events. + ''; + }; }; }; @@ -152,16 +183,24 @@ in { { source = "${networkmanager_pptp}/etc/NetworkManager/VPN/nm-pptp-service.name"; target = "NetworkManager/VPN/nm-pptp-service.name"; } + { source = "${networkmanager_l2tp}/etc/NetworkManager/VPN/nm-l2tp-service.name"; + target = "NetworkManager/VPN/nm-l2tp-service.name"; + } ] ++ optional (cfg.appendNameservers == [] || cfg.insertNameservers == []) { source = overrideNameserversScript; target = "NetworkManager/dispatcher.d/02overridedns"; - }; + } + ++ lib.imap (i: s: { + text = s.source; + target = "NetworkManager/dispatcher.d/${dispatcherTypesSubdirMap.${s.type}}03userscript${lib.fixedWidthNumber 4 i}"; + }) cfg.dispatcherScripts; environment.systemPackages = cfg.packages ++ [ networkmanager_openvpn networkmanager_vpnc networkmanager_openconnect networkmanager_pptp + networkmanager_l2tp modemmanager ]; @@ -205,6 +244,7 @@ in { networkmanager_vpnc networkmanager_openconnect networkmanager_pptp + networkmanager_l2tp modemmanager ]; diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix index 140b7ed2da37..36d9f5d2f166 100644 --- a/nixos/modules/services/networking/nsd.nix +++ b/nixos/modules/services/networking/nsd.nix @@ -9,6 +9,14 @@ let stateDir = "/var/lib/nsd"; pidFile = stateDir + "/var/nsd.pid"; + nsdPkg = pkgs.nsd.override { + bind8Stats = cfg.bind8Stats; + ipv6 = cfg.ipv6; + ratelimit = cfg.ratelimit.enable; + rootServer = cfg.rootServer; + zoneStats = length (collect (x: (x.zoneStats or null) != null) cfg.zones) > 0; + }; + zoneFiles = pkgs.stdenv.mkDerivation { preferLocalBuild = true; name = "nsd-env"; @@ -107,6 +115,7 @@ let zone: name: "${name}" zonefile: "${stateDir}/zones/${name}" + ${maybeString "zonestats: " zone.zoneStats} ${maybeString "outgoing-interface: " zone.outgoingInterface} ${forEach " rrl-whitelist: " zone.rrlWhitelist} @@ -270,6 +279,19 @@ let Use imports or pkgs.lib.readFile if you don't want this data in your config file. ''; }; + + zoneStats = mkOption { + type = types.nullOr types.str; + default = null; + example = "%s"; + description = '' + When set to something distinct to null NSD is able to collect + statistics per zone. All statistics of this zone(s) will be added + to the group specified by this given name. Use "%s" to use the zones + name as the group. The groups are output from nsd-control stats + and stats_noreset. + ''; + }; }; }; @@ -286,6 +308,15 @@ in ''; }; + bind8Stats = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + Wheter to enable BIND8 like statisics. + ''; + }; + rootServer = mkOption { type = types.bool; default = false; @@ -659,13 +690,6 @@ in config = mkIf cfg.enable { - # this is not working :( - nixpkgs.config.nsd = { - ipv6 = cfg.ipv6; - ratelimit = cfg.ratelimit.enable; - rootServer = cfg.rootServer; - }; - users.extraGroups = singleton { name = username; gid = config.ids.gids.nsd; @@ -688,7 +712,7 @@ in serviceConfig = { PIDFile = pidFile; Restart = "always"; - ExecStart = "${pkgs.nsd}/sbin/nsd -d -c ${configFile}"; + ExecStart = "${nsdPkg}/sbin/nsd -d -c ${configFile}"; }; preStart = '' diff --git a/nixos/modules/services/networking/rdnssd.nix b/nixos/modules/services/networking/rdnssd.nix index 4c1891816e3e..95833d31e99d 100644 --- a/nixos/modules/services/networking/rdnssd.nix +++ b/nixos/modules/services/networking/rdnssd.nix @@ -4,7 +4,12 @@ { config, lib, pkgs, ... }: with lib; - +let + mergeHook = pkgs.writeScript "rdnssd-merge-hook" '' + #! ${pkgs.stdenv.shell} -e + ${pkgs.openresolv}/bin/resolvconf -u + ''; +in { ###### interface @@ -30,18 +35,39 @@ with lib; config = mkIf config.services.rdnssd.enable { - jobs.rdnssd = - { description = "RDNSS daemon"; - - # Start before the network interfaces are brought up so that - # the daemon receives RDNSS advertisements from the kernel. - startOn = "starting network-interfaces"; - - # !!! Should write to /var/run/rdnssd/resolv.conf and run the daemon under another uid. - exec = "${pkgs.ndisc6}/sbin/rdnssd --resolv-file /etc/resolv.conf -u root"; - - daemonType = "fork"; + systemd.services.rdnssd = { + description = "RDNSS daemon"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + preStart = '' + # Create the proper run directory + mkdir -p /run/rdnssd + touch /run/rdnssd/resolv.conf + chown -R rdnssd /run/rdnssd + + # Link the resolvconf interfaces to rdnssd + rm -f /run/resolvconf/interfaces/rdnssd + ln -s /run/rdnssd/resolv.conf /run/resolvconf/interfaces/rdnssd + ${mergeHook} + ''; + + postStop = '' + rm -f /run/resolvconf/interfaces/rdnssd + ${mergeHook} + ''; + + serviceConfig = { + ExecStart = "@${pkgs.ndisc6}/bin/rdnssd rdnssd -p /run/rdnssd/rdnssd.pid -r /run/rdnssd/resolv.conf -u rdnssd -H ${mergeHook}"; + Type = "forking"; + PIDFile = "/run/rdnssd/rdnssd.pid"; }; + }; + + users.extraUsers.rdnssd = { + description = "RDNSSD Daemon User"; + uid = config.ids.uids.rdnssd; + }; }; diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index c0ad9e17c413..b2740bd33b7f 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -9,12 +9,6 @@ let nssModulesPath = config.system.nssModules.path; - permitRootLoginCheck = v: - v == "yes" || - v == "without-password" || - v == "forced-commands-only" || - v == "no"; - knownHosts = map (h: getAttr h cfg.knownHosts) (attrNames cfg.knownHosts); knownHostsText = flip (concatMapStringsSep "\n") knownHosts @@ -116,12 +110,9 @@ in permitRootLogin = mkOption { default = "without-password"; - type = types.addCheck types.str permitRootLoginCheck; + type = types.enum ["yes" "without-password" "forced-commands-only" "no"]; description = '' - Whether the root user can login using ssh. Valid values are - <literal>yes</literal>, <literal>without-password</literal>, - <literal>forced-commands-only</literal> or - <literal>no</literal>. + Whether the root user can login using ssh. ''; }; @@ -195,12 +186,14 @@ in default = [ { path = "/etc/ssh/ssh_host_dsa_key"; type = "dsa"; - bits = 1024; } { path = "/etc/ssh/ssh_host_ecdsa_key"; type = "ecdsa"; bits = 521; } + { path = "/etc/ssh/ssh_host_ed25519_key"; + type = "ed25519"; + } ]; description = '' NixOS can automatically generate SSH host keys. This option @@ -323,7 +316,7 @@ in ${flip concatMapStrings cfg.hostKeys (k: '' if ! [ -f "${k.path}" ]; then - ssh-keygen -t "${k.type}" -b "${toString k.bits}" -f "${k.path}" -N "" + ssh-keygen -t "${k.type}" ${if k ? bits then "-b ${toString k.bits}" else ""} -f "${k.path}" -N "" fi '')} ''; @@ -379,6 +372,8 @@ in UsePAM yes + UsePrivilegeSeparation sandbox + AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"} ${concatMapStrings (port: '' Port ${toString port} diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix index 679aa81a13da..b573a356b351 100644 --- a/nixos/modules/services/printing/cupsd.nix +++ b/nixos/modules/services/printing/cupsd.nix @@ -183,7 +183,7 @@ in # gets loaded, and then cups cannot access the printers. boot.blacklistedKernelModules = [ "usblp" ]; - systemd.services.cupsd = + systemd.services.cups = { description = "CUPS Printing Daemon"; wantedBy = [ "multi-user.target" ]; diff --git a/nixos/modules/services/security/munge.nix b/nixos/modules/services/security/munge.nix new file mode 100644 index 000000000000..919c2c2b0e15 --- /dev/null +++ b/nixos/modules/services/security/munge.nix @@ -0,0 +1,61 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.munge; + +in + +{ + + ###### interface + + options = { + + services.munge = { + enable = mkEnableOption "munge service"; + + password = mkOption { + default = "/etc/munge/munge.key"; + type = types.string; + description = '' + The path to a daemon's secret key. + ''; + }; + + }; + + }; + + ###### implementation + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.munge ]; + + systemd.services.munged = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + path = [ pkgs.munge pkgs.coreutils ]; + + preStart = '' + chmod 0700 ${cfg.password} + mkdir -p /var/lib/munge -m 0711 + mkdir -p /var/log/munge -m 0700 + mkdir -p /run/munge -m 0755 + ''; + + serviceConfig = { + ExecStart = "${pkgs.munge}/bin/munged --syslog --key-file ${cfg.password}"; + PIDFile = "/run/munge/munged.pid"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + }; + + }; + + }; + +} diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix index 928f16c94489..d40f7d6d05d9 100644 --- a/nixos/modules/services/system/dbus.nix +++ b/nixos/modules/services/system/dbus.nix @@ -130,6 +130,9 @@ in config.system.path ]; + # Don't restart dbus-daemon. Bad things tend to happen if we do. + systemd.services.dbus.reloadIfChanged = true; + environment.pathsToLink = [ "/etc/dbus-1" "/share/dbus-1" ]; }; diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix index 1b38ea3b679b..135113b3ceb1 100644 --- a/nixos/modules/services/torrent/transmission.nix +++ b/nixos/modules/services/torrent/transmission.nix @@ -9,28 +9,16 @@ let homeDir = "/var/lib/transmission"; downloadDir = "${homeDir}/Downloads"; incompleteDir = "${homeDir}/.incomplete"; + settingsDir = "${homeDir}/.config/transmission-daemon"; - settingsFile = "${settingsDir}/settings.json"; + settingsFile = pkgs.writeText "settings.json" (builtins.toJSON fullSettings); # Strings must be quoted, ints and bools must not (for settings.json). toOption = x: if x == true then "true" else if x == false then "false" else if isInt x then toString x - else toString ''\"${x}\"''; - - # All lines in settings.json end with a ',' (comma), except for the last - # line. This is standard JSON. But a comma can also appear *inside* some - # fields, notably the "rpc-whitelist" field. This is difficult to handle in - # sed so we simply ignore it and say that if you want to change the option at - # the last line of settings.json, you have to do it manually. At this time of - # writing, the last option is "utp-enable":true. - attrsToSedArgs = as: - concatStrings (concatLists (mapAttrsToList (name: value: - #map (x: '' -e 's=\(\"${name}\":\)[^,]*\(.*\)=\1 ${toOption x}\2=' '') # breaks if comma inside value field - map (x: '' -e 's=\(\"${name}\":\).*=\1 ${toOption x},=' '') # always append ',' (breaks last line in settings.json) - (if isList value then value else [value])) - as)); + else toString ''"${x}"''; # for users in group "transmission" to have access to torrents fullSettings = cfg.settings // { umask = 2; }; @@ -73,7 +61,7 @@ in boolean values must not. See https://trac.transmissionbt.com/wiki/EditConfigFiles for - documentation and/or look at ${settingsFile}. + documentation. ''; }; @@ -95,7 +83,7 @@ in # 1) Only the "transmission" user and group have access to torrents. # 2) Optionally update/force specific fields into the configuration file. serviceConfig.ExecStartPre = '' - ${pkgs.stdenv.shell} -c "chmod 770 ${homeDir} && mkdir -p ${settingsDir} ${downloadDir} ${incompleteDir} && ${pkgs.transmission}/bin/transmission-daemon -d |& sed ${attrsToSedArgs fullSettings} > ${settingsFile}.tmp && mv ${settingsFile}.tmp ${settingsFile}" + ${pkgs.stdenv.shell} -c "chmod 770 ${homeDir} && mkdir -p ${settingsDir} ${downloadDir} ${incompleteDir} && rm -f ${settingsDir}/settings.json && cp -f ${settingsFile} ${settingsDir}/settings.json" ''; serviceConfig.ExecStart = "${pkgs.transmission}/bin/transmission-daemon -f --port ${toString config.services.transmission.port}"; serviceConfig.ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix index 6a830827fd78..2b5cba68d457 100644 --- a/nixos/modules/services/web-servers/apache-httpd/default.nix +++ b/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -171,6 +171,9 @@ let SSLRandomSeed startup builtin SSLRandomSeed connect builtin + + SSLProtocol All -SSLv2 -SSLv3 + SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!EXP ''; diff --git a/nixos/modules/services/web-servers/apache-httpd/owncloud.nix b/nixos/modules/services/web-servers/apache-httpd/owncloud.nix index 3bea3c3ee1dd..a5e539bc9ba7 100644 --- a/nixos/modules/services/web-servers/apache-httpd/owncloud.nix +++ b/nixos/modules/services/web-servers/apache-httpd/owncloud.nix @@ -384,8 +384,7 @@ rec { }; adminPassword = mkOption { - description = "The admin password for accessing owncloud. - Warning: this is stored in cleartext in the Nix store!"; + description = "The admin password for accessing owncloud."; }; dbType = mkOption { @@ -571,7 +570,7 @@ rec { chown wwwrun:wwwrun ${config.dataDir}/owncloud.log || true - QUERY="INSERT INTO groups (gid) values('admin'); INSERT INTO users (uid,password) values('${config.adminUser}','`echo -n "${config.adminPassword}" | ${pkgs.openssl}/bin/openssl dgst -sha1 | ${pkgs.gawk}/bin/awk '{print $2}'`'); INSERT INTO group_user (gid,uid) values('admin','${config.adminUser}');" + QUERY="INSERT INTO groups (gid) values('admin'); INSERT INTO users (uid,password) values('${config.adminUser}','${builtins.hashString "sha1" config.adminPassword}'); INSERT INTO group_user (gid,uid) values('admin','${config.adminUser}');" ${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/psql -h "/tmp" -U postgres -d ${config.dbName} -Atw -c "$QUERY" || true ''; } diff --git a/nixos/modules/services/web-servers/fcgiwrap.nix b/nixos/modules/services/web-servers/fcgiwrap.nix index 7e91e7b60eef..2c5e433003c8 100644 --- a/nixos/modules/services/web-servers/fcgiwrap.nix +++ b/nixos/modules/services/web-servers/fcgiwrap.nix @@ -4,7 +4,6 @@ with lib; let cfg = config.services.fcgiwrap; - in { options = { @@ -21,29 +20,53 @@ in { description = "Number of processes to prefork."; }; - bindSocket = mkOption { - type = types.string; - default = "unix:/run/fcgiwrap.sock"; - description = '' - Socket to bind to. Valid socket URLs are: - unix:/path/to/socket for Unix sockets - tcp:dot.ted.qu.ad:port for IPv4 sockets - tcp6:[ipv6_addr]:port for IPv6 sockets - ''; + socketType = mkOption { + type = types.addCheck types.str (t: t == "unix" || t == "tcp" || t == "tcp6"); + default = "unix"; + description = "Socket type: 'unix', 'tcp' or 'tcp6'."; + }; + + socketAddress = mkOption { + type = types.str; + default = "/run/fcgiwrap.sock"; + example = "1.2.3.4:5678"; + description = "Socket address. In case of a UNIX socket, this should be its filesystem path."; + }; + + user = mkOption { + type = types.nullOr types.str; + default = null; + description = "User permissions for the socket."; + }; + + group = mkOption { + type = types.nullOr types.str; + default = null; + description = "Group permissions for the socket."; }; }; }; config = mkIf cfg.enable { - systemd.services.fcgiwrap = { after = [ "nss-user-lookup.target" ]; - wantedBy = [ "multi-user.target" ]; + wantedBy = optional (cfg.socketType != "unix") "multi-user.target"; serviceConfig = { - ExecStart = "${pkgs.fcgiwrap}/sbin/fcgiwrap -c ${builtins.toString cfg.preforkProcesses} -s ${cfg.bindSocket}"; - }; + ExecStart = "${pkgs.fcgiwrap}/sbin/fcgiwrap -c ${builtins.toString cfg.preforkProcesses} ${ + if (cfg.socketType != "unix") then "-s ${cfg.socketType}:${cfg.socketAddress}" else "" + }"; + } // (if cfg.user != null && cfg.group != null then { + User = cfg.user; + Group = cfg.group; + } else { } ); }; + systemd.sockets = if (cfg.socketType == "unix") then { + fcgiwrap = { + wantedBy = [ "sockets.target" ]; + socketConfig.ListenStream = cfg.socketAddress; + }; + } else { }; }; } diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 0af1b58b7cae..0f21ef012639 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -102,6 +102,9 @@ in ''; serviceConfig = { ExecStart = "${nginx}/bin/nginx -c ${configFile} -p ${cfg.stateDir}"; + Restart = "on-failure"; + RestartSec = "10s"; + StartLimitInterval = "1min"; }; }; diff --git a/nixos/modules/services/x11/desktop-managers/default.nix b/nixos/modules/services/x11/desktop-managers/default.nix index 9165658a7be7..998bcd354c53 100644 --- a/nixos/modules/services/x11/desktop-managers/default.nix +++ b/nixos/modules/services/x11/desktop-managers/default.nix @@ -19,7 +19,7 @@ in # E.g., if KDE is enabled, it supersedes xterm. imports = [ ./none.nix ./xterm.nix ./xfce.nix ./kde4.nix ./kde5.nix - ./e19.nix ./gnome3.nix ./xbmc.nix ./kodi.nix + ./e19.nix ./gnome3.nix ./kodi.nix ]; options = { diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix index 9c3c65dcfaa7..02e51577e3e2 100644 --- a/nixos/modules/services/x11/desktop-managers/kde5.nix +++ b/nixos/modules/services/x11/desktop-managers/kde5.nix @@ -88,7 +88,9 @@ in }; environment.systemPackages = - [ + filter isDerivation (builtins.attrValues plasma5) + ++ filter isDerivation (builtins.attrValues kf5) + ++ [ pkgs.qt4 # qtconfig is the only way to set Qt 4 theme kdeApps.kde-baseapps @@ -97,13 +99,12 @@ in kdeApps.konsole kdeApps.oxygen-icons + kdeApps.kde-runtime + pkgs.hicolor_icon_theme pkgs.orion # GTK theme, nearly identical to Breeze - ] - ++ filter isDerivation (builtins.attrValues plasma5) - ++ filter isDerivation (builtins.attrValues kf5) - ++ phononBackendPackages; + ] ++ phononBackendPackages; environment.pathsToLink = [ "/share" ]; @@ -121,6 +122,8 @@ in fonts.fonts = [ plasma5.oxygen-fonts ]; + programs.ssh.askPassword = "${plasma5.ksshaskpass}/bin/ksshaskpass"; + # Enable helpful DBus services. services.udisks2.enable = true; services.upower.enable = config.powerManagement.enable; diff --git a/nixos/modules/services/x11/desktop-managers/xbmc.nix b/nixos/modules/services/x11/desktop-managers/xbmc.nix deleted file mode 100644 index 97e966ca0197..000000000000 --- a/nixos/modules/services/x11/desktop-managers/xbmc.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.xserver.desktopManager.xbmc; -in - -{ - options = { - services.xserver.desktopManager.xbmc = { - enable = mkOption { - default = false; - example = true; - description = "Enable the xbmc multimedia center."; - }; - }; - }; - - config = mkIf cfg.enable { - services.xserver.desktopManager.session = [{ - name = "xbmc"; - start = '' - ${pkgs.xbmc}/bin/xbmc --lircdev /var/run/lirc/lircd --standalone & - waitPID=$! - ''; - }]; - - environment.systemPackages = [ pkgs.xbmc ]; - }; -} \ 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 6a14a163c19a..fce5bf11f053 100644 --- a/nixos/modules/services/x11/desktop-managers/xfce.nix +++ b/nixos/modules/services/x11/desktop-managers/xfce.nix @@ -46,7 +46,6 @@ in pkgs.which # Needed by the xfce's xinitrc script. pkgs.xfce.exo pkgs.xfce.gtk_xfce_engine - pkgs.xfce.libxfcegui4 # For the icons. pkgs.xfce.mousepad pkgs.xfce.ristretto pkgs.xfce.terminal diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix index 601971d27b69..c5012dbb5e30 100644 --- a/nixos/modules/services/x11/display-managers/default.nix +++ b/nixos/modules/services/x11/display-managers/default.nix @@ -89,6 +89,10 @@ let ${config.hardware.pulseaudio.package}/bin/pactl load-module module-device-manager "do_routing=1" ''} + # Tell systemd about our $DISPLAY. This is needed by the + # ssh-agent unit. + ${config.systemd.package}/bin/systemctl --user import-environment DISPLAY + # Load X defaults. ${xorg.xrdb}/bin/xrdb -merge ${xresourcesXft} if test -e ~/.Xresources; then @@ -204,6 +208,14 @@ in description = "Shell commands executed just before the window or desktop manager is started."; }; + hiddenUsers = mkOption { + type = types.listOf types.str; + default = [ "nobody" ]; + description = '' + A list of users which will not be shown in the display manager. + ''; + }; + desktopManagerHandlesLidAndPower = mkOption { type = types.bool; default = true; diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix index b3da0cda04a3..a7ebafa28b38 100644 --- a/nixos/modules/services/x11/display-managers/gdm.nix +++ b/nixos/modules/services/x11/display-managers/gdm.nix @@ -95,15 +95,23 @@ in auth required pam_succeed_if.so uid >= 1000 quiet auth optional ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so - auth sufficient pam_unix.so nullok likeauth - auth required pam_deny.so + auth ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so nullok likeauth + ${optionalString config.security.pam.enableEcryptfs + "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"} + + ${optionalString (! config.security.pam.enableEcryptfs) + "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"} session required pam_env.so envfile=${config.system.build.pamEnvironment} session required pam_unix.so + ${optionalString config.security.pam.enableEcryptfs + "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} session required pam_loginuid.so session optional ${pkgs.systemd}/lib/security/pam_systemd.so session optional ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so auto_start @@ -115,15 +123,22 @@ in auth required pam_succeed_if.so uid >= 1000 quiet auth optional ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so - auth sufficient pam_unix.so nullok likeauth - auth required pam_deny.so + auth ${if config.security.pam.enableEcryptfs then "required" else "sufficient"} pam_unix.so nullok likeauth + ${optionalString config.security.pam.enableEcryptfs + "auth required ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"} + ${optionalString (! config.security.pam.enableEcryptfs) + "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"} session required pam_env.so envfile=${config.system.build.pamEnvironment} session required pam_unix.so + ${optionalString config.security.pam.enableEcryptfs + "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} session required pam_loginuid.so session optional ${pkgs.systemd}/lib/security/pam_systemd.so session optional ${gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so auto_start diff --git a/nixos/modules/services/x11/display-managers/kdm.nix b/nixos/modules/services/x11/display-managers/kdm.nix index 42eaacfe84af..d0b69c5452c2 100644 --- a/nixos/modules/services/x11/display-managers/kdm.nix +++ b/nixos/modules/services/x11/display-managers/kdm.nix @@ -38,7 +38,7 @@ let ''} [X-*-Greeter] - HiddenUsers=root,nixbld1,nixbld2,nixbld3,nixbld4,nixbld5,nixbld6,nixbld7,nixbld8,nixbld9,nixbld10 + HiddenUsers=root,${concatStringsSep "," dmcfg.hiddenUsers} PluginsLogin=${kdebase_workspace}/lib/kde4/kgreet_classic.so ${optionalString (cfg.themeDirectory != null) '' diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix index 98e3fd6d6a5d..6a7b810261da 100644 --- a/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixos/modules/services/x11/display-managers/lightdm.nix @@ -18,6 +18,9 @@ let exec ${dmcfg.xserverBin} ${dmcfg.xserverArgs} ''; + theme = pkgs.gnome3.gnome_themes_standard; + icons = pkgs.gnome3.gnome_icon_theme; + # The default greeter provided with this expression is the GTK greeter. # Again, we need a few things in the environment for the greeter to run with # fonts/icons. @@ -26,19 +29,16 @@ let buildInputs = [ pkgs.makeWrapper ]; buildCommand = '' - mkdir -p $out/gtk-3.0/ - - # This wrapper ensures that we actually get ?? (fonts should be OK now) + # This wrapper ensures that we actually get themes makeWrapper ${pkgs.lightdm_gtk_greeter}/sbin/lightdm-gtk-greeter \ $out/greeter \ - --set XDG_DATA_DIRS ${pkgs.gnome2.gnome_icon_theme}/share \ - --set XDG_CONFIG_HOME $out/ - - # We need this to ensure that it actually tries to find icons from gnome-icon-theme - cat - > $out/gtk-3.0/settings.ini << EOF - [Settings] - gtk-icon-theme-name=gnome - EOF + --prefix PATH : "${pkgs.glibc}/bin" \ + --set GDK_PIXBUF_MODULE_FILE "$(find ${theme} -name loaders.cache)" \ + --set GTK_PATH "${theme}:${pkgs.gtk3}" \ + --set GTK_EXE_PREFIX "${theme}" \ + --set GTK_DATA_PREFIX "${theme}" \ + --set XDG_DATA_DIRS "${theme}/share:${icons}/share" \ + --set XDG_CONFIG_HOME "${theme}/share" cat - > $out/lightdm-gtk-greeter.desktop << EOF [Desktop Entry] @@ -50,6 +50,14 @@ let ''; }; + usersConf = writeText "users.conf" + '' + [UserList] + minimum-uid=500 + hidden-users=${concatStringsSep " " dmcfg.hiddenUsers} + hidden-shells=/run/current-system/sw/bin/nologin + ''; + lightdmConf = writeText "lightdm.conf" '' [LightDM] @@ -63,10 +71,19 @@ let greeter-session = ${cfg.greeter.name} ''; + gtkGreeterConf = writeText "lightdm-gtk-greeter.conf" + '' + [greeter] + theme-name = Adwaita + icon-theme-name = Adwaita + background = ${cfg.background} + ''; + in { options = { services.xserver.displayManager.lightdm = { + enable = mkOption { default = false; description = '' @@ -84,6 +101,14 @@ in package = wrappedGtkGreeter; }; }; + + background = mkOption { + default = "${pkgs.nixos-artwork}/gnome/Gnome_Dark.png"; + description = '' + The background image or color to use. + ''; + }; + }; }; @@ -97,10 +122,14 @@ in # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH execCmd = '' export PATH=${lightdm}/sbin:$PATH - ${lightdm}/sbin/lightdm --log-dir=/var/log --run-dir=/run --config=${lightdmConf} + exec ${lightdm}/sbin/lightdm --log-dir=/var/log --run-dir=/run ''; }; + environment.etc."lightdm/lightdm-gtk-greeter.conf".source = gtkGreeterConf; + environment.etc."lightdm/lightdm.conf".source = lightdmConf; + environment.etc."lightdm/users.conf".source = usersConf; + services.dbus.enable = true; services.dbus.packages = [ lightdm ]; @@ -109,7 +138,7 @@ in users.extraUsers.lightdm = { createHome = true; - home = "/var/lib/lightdm"; + home = "/var/lib/lightdm-data"; group = "lightdm"; uid = config.ids.uids.lightdm; }; diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix new file mode 100644 index 000000000000..c44383cc6117 --- /dev/null +++ b/nixos/modules/services/x11/display-managers/sddm.nix @@ -0,0 +1,110 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + xcfg = config.services.xserver; + dmcfg = xcfg.displayManager; + cfg = dmcfg.sddm; + xEnv = config.systemd.services."display-manager".environment; + + xserverWrapper = pkgs.writeScript "xserver-wrapper" '' + #!/bin/sh + ${concatMapStrings (n: "export ${n}=\"${getAttr n xEnv}\"\n") (attrNames xEnv)} + exec ${dmcfg.xserverBin} ${dmcfg.xserverArgs} "$@" + ''; + + cfgFile = pkgs.writeText "sddm.conf" '' + [General] + HaltCommand=${pkgs.systemd}/bin/systemctl poweroff + RebootCommand=${pkgs.systemd}/bin/systemctl reboot + + [Theme] + Current=${cfg.theme} + + [Users] + MaximumUid=${toString config.ids.uids.nixbld} + HideUsers=${concatStringsSep "," dmcfg.hiddenUsers} + HideShells=/run/current-system/sw/bin/nologin + + [XDisplay] + MinimumVT=${toString xcfg.tty} + ServerPath=${xserverWrapper} + XephyrPath=${pkgs.xorg.xorgserver}/bin/Xephyr + SessionCommand=${dmcfg.session.script} + SessionDir=${dmcfg.session.desktops} + XauthPath=${pkgs.xorg.xauth}/bin/xauth + ''; + +in +{ + options = { + + services.xserver.displayManager.sddm = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable sddm as the display manager. + ''; + }; + + theme = mkOption { + type = types.str; + default = "maui"; + description = '' + Greeter theme to use. + ''; + }; + }; + + }; + + config = mkIf cfg.enable { + + services.xserver.displayManager.slim.enable = false; + + services.xserver.displayManager.job = { + logsXsession = true; + + #execCmd = "${pkgs.sddm}/bin/sddm"; + execCmd = "exec ${pkgs.sddm}/bin/sddm"; + }; + + security.pam.services = { + sddm = { + allowNullPassword = true; + startSession = true; + }; + + sddm-greeter.text = '' + auth required pam_succeed_if.so audit quiet_success user = sddm + auth optional pam_permit.so + + account required pam_succeed_if.so audit quiet_success user = sddm + account sufficient pam_unix.so + + password required pam_deny.so + + session required pam_succeed_if.so audit quiet_success user = sddm + session required pam_env.so envfile=${config.system.build.pamEnvironment} + session optional ${pkgs.systemd}/lib/security/pam_systemd.so + session optional pam_keyinit.so force revoke + session optional pam_permit.so + ''; + }; + + users.extraUsers.sddm = { + createHome = true; + home = "/var/lib/sddm"; + group = "sddm"; + uid = config.ids.uids.sddm; + }; + + environment.etc."sddm.conf".source = cfgFile; + + users.extraGroups.sddm.gid = config.ids.gids.sddm; + + }; +} diff --git a/nixos/modules/services/x11/hardware/multitouch.nix b/nixos/modules/services/x11/hardware/multitouch.nix index 6e6e88e67218..f8386b5e333b 100644 --- a/nixos/modules/services/x11/hardware/multitouch.nix +++ b/nixos/modules/services/x11/hardware/multitouch.nix @@ -2,9 +2,15 @@ with lib; -let cfg = config.services.xserver.multitouch; in - -{ +let cfg = config.services.xserver.multitouch; + disabledTapConfig = '' + Option "MaxTapTime" "0" + Option "MaxTapMove" "0" + Option "TapButton1" "0" + Option "TapButton2" "0" + Option "TapButton3" "0" + ''; +in { options = { @@ -30,6 +36,33 @@ let cfg = config.services.xserver.multitouch; in description = "Whether to ignore touches detected as being the palm (i.e when typing)"; }; + tapButtons = mkOption { + type = types.bool; + default = true; + example = false; + description = "Whether to enable tap buttons."; + }; + + buttonsMap = mkOption { + type = types.listOf types.int; + default = [3 2 0]; + example = [1 3 2]; + description = "Remap touchpad buttons."; + apply = map toString; + }; + + additionalOptions = mkOption { + type = types.str; + default = ""; + example = '' + Option "ScaleDistance" "50" + Option "RotateDistance" "60" + ''; + description = '' + Additional options for mtrack touchpad driver. + ''; + }; + }; }; @@ -46,12 +79,17 @@ let cfg = config.services.xserver.multitouch; in Identifier "Touchpads" Driver "mtrack" Option "IgnorePalm" "${if cfg.ignorePalm then "true" else "false"}" + Option "ClickFinger1" "${builtins.elemAt cfg.buttonsMap 0}" + Option "ClickFinger2" "${builtins.elemAt cfg.buttonsMap 1}" + Option "ClickFinger3" "${builtins.elemAt cfg.buttonsMap 2}" + ${optionalString (!cfg.tapButtons) disabledTapConfig} ${optionalString cfg.invertScroll '' Option "ScrollUpButton" "5" Option "ScrollDownButton" "4" Option "ScrollLeftButton" "7" Option "ScrollRightButton" "6" ''} + ${cfg.additionalOptions} EndSection ''; diff --git a/nixos/modules/services/x11/unclutter.nix b/nixos/modules/services/x11/unclutter.nix new file mode 100644 index 000000000000..556d9e187fdd --- /dev/null +++ b/nixos/modules/services/x11/unclutter.nix @@ -0,0 +1,33 @@ +{ config, lib, pkgs, ... }: +with lib; +let cfg = config.services.unclutter; +in { + options = { + services.unclutter.enable = mkOption { + type = types.bool; + default = false; + example = true; + description = "Enable unclutter to hide your mouse cursor when inactive"; + }; + + services.unclutter.arguments = mkOption { + description = "Arguments to pass to unclutter command"; + default = "-idle 1"; + type = types.uniq types.string; + }; + }; + + config = mkIf cfg.enable { + systemd.services.unclutter = { + description = "unclutter"; + requires = [ "display-manager.service" ]; + after = [ "display-manager.service" ]; + wantedBy = [ "graphical.target" ]; + serviceConfig.ExecStart = '' + ${pkgs.unclutter}/bin/unclutter ${cfg.arguments} + ''; + 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 628d475c9684..097e4fe70d58 100644 --- a/nixos/modules/services/x11/window-managers/default.nix +++ b/nixos/modules/services/x11/window-managers/default.nix @@ -8,14 +8,18 @@ in { imports = [ + ./afterstep.nix ./bspwm.nix ./compiz.nix + ./fluxbox.nix ./herbstluftwm.nix ./i3.nix ./metacity.nix ./openbox.nix + ./ratpoison.nix ./sawfish.nix ./stumpwm.nix + ./spectrwm.nix ./twm.nix ./windowmaker.nix ./wmii.nix diff --git a/nixos/modules/services/x11/window-managers/spectrwm.nix b/nixos/modules/services/x11/window-managers/spectrwm.nix new file mode 100644 index 000000000000..5db6b41ba8fd --- /dev/null +++ b/nixos/modules/services/x11/window-managers/spectrwm.nix @@ -0,0 +1,33 @@ + +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.xserver.windowManager.spectrwm; +in + +{ + options = { + services.xserver.windowManager.spectrwm = { + enable = mkOption { + default = false; + example = true; + description = "Enable the spectrwm window manager."; + }; + }; + }; + + config = mkIf cfg.enable { + services.xserver.windowManager = { + session = [{ + name = "spectrwm"; + start = '' + ${pkgs.spectrwm}/bin/spectrwm & + waitPID=$! + ''; + }]; + }; + environment.systemPackages = [ pkgs.spectrwm ]; + }; +} diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl index dbe13c022f09..7aa4b12a6543 100644 --- a/nixos/modules/system/activation/switch-to-configuration.pl +++ b/nixos/modules/system/activation/switch-to-configuration.pl @@ -9,19 +9,21 @@ use Cwd 'abs_path'; my $out = "@out@"; +# To be robust against interruption, record what units need to be started etc. my $startListFile = "/run/systemd/start-list"; my $restartListFile = "/run/systemd/restart-list"; my $reloadListFile = "/run/systemd/reload-list"; my $action = shift @ARGV; -if (!defined $action || ($action ne "switch" && $action ne "boot" && $action ne "test")) { +if (!defined $action || ($action ne "switch" && $action ne "boot" && $action ne "test" && $action ne "dry-activate")) { print STDERR <<EOF; Usage: $0 [switch|boot|test] -switch: make the configuration the boot default and activate now -boot: make the configuration the boot default -test: activate the configuration, but don\'t make it the boot default +switch: make the configuration the boot default and activate now +boot: make the configuration the boot default +test: activate the configuration, but don\'t make it the boot default +dry-activate: show what would be done if this configuration were activated EOF exit 1; } @@ -56,8 +58,6 @@ EOF exit 100; } -syslog(LOG_NOTICE, "switching to system configuration $out"); - # Ignore SIGHUP so that we're not killed if we're running on (say) # virtual console 1 and we restart the "tty1" unit. $SIG{PIPE} = "IGNORE"; @@ -116,6 +116,11 @@ sub boolIsTrue { return $s eq "yes" || $s eq "true"; } +sub recordUnit { + my ($fn, $unit) = @_; + write_file($fn, { append => 1 }, "$unit\n") if $action ne "dry-activate"; +} + # As a fingerprint for determining whether a unit has changed, we use # its absolute path. If it has an override file, we append *its* # absolute path as well. @@ -124,9 +129,20 @@ sub fingerprintUnit { return abs_path($s) . (-f "${s}.d/overrides.conf" ? " " . abs_path "${s}.d/overrides.conf" : ""); } -# Stop all services that no longer exist or have changed in the new -# configuration. -my (@unitsToStop, @unitsToSkip); +# Figure out what units need to be stopped, started, restarted or reloaded. +my (%unitsToStop, %unitsToSkip, %unitsToStart, %unitsToRestart, %unitsToReload); + +my %unitsToFilter; # units not shown + +$unitsToStart{$_} = 1 foreach + split('\n', read_file($startListFile, err_mode => 'quiet') // ""); + +$unitsToRestart{$_} = 1 foreach + split('\n', read_file($restartListFile, err_mode => 'quiet') // ""); + +$unitsToReload{$_} = 1 foreach + split '\n', read_file($reloadListFile, err_mode => 'quiet') // ""; + my $activePrev = getActiveUnits; while (my ($unit, $state) = each %{$activePrev}) { my $baseUnit = $unit; @@ -141,7 +157,7 @@ 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") { - push @unitsToStop, $unit; + $unitsToStop{$unit} = 1; } elsif ($unit =~ /\.target$/) { @@ -155,7 +171,10 @@ while (my ($unit, $state) = each %{$activePrev}) { # should not be the case. Just ignore it. if ($unit ne "suspend.target" && $unit ne "hibernate.target" && $unit ne "hybrid-sleep.target") { unless (boolIsTrue($unitInfo->{'RefuseManualStart'} // "no")) { - write_file($startListFile, { append => 1 }, "$unit\n"); + $unitsToStart{$unit} = 1; + recordUnit($startListFile, $unit); + # Don't spam the user with target units that always get started. + $unitsToFilter{$unit} = 1; } } @@ -171,7 +190,7 @@ while (my ($unit, $state) = each %{$activePrev}) { # (unless there is a PartOf dependency), so this is just a # bookkeeping thing to get systemd to do the right thing. if (boolIsTrue($unitInfo->{'X-StopOnReconfiguration'} // "no")) { - push @unitsToStop, $unit; + $unitsToStop{$unit} = 1; } } @@ -180,16 +199,18 @@ while (my ($unit, $state) = each %{$activePrev}) { # Do nothing. These cannot be restarted directly. } elsif ($unit =~ /\.mount$/) { # Reload the changed mount unit to force a remount. - write_file($reloadListFile, { append => 1 }, "$unit\n"); + $unitsToReload{$unit} = 1; + recordUnit($reloadListFile, $unit); } elsif ($unit =~ /\.socket$/ || $unit =~ /\.path$/ || $unit =~ /\.slice$/) { # FIXME: do something? } else { my $unitInfo = parseUnit($newUnitFile); if (boolIsTrue($unitInfo->{'X-ReloadIfChanged'} // "no")) { - write_file($reloadListFile, { append => 1 }, "$unit\n"); + $unitsToReload{$unit} = 1; + recordUnit($reloadListFile, $unit); } elsif (!boolIsTrue($unitInfo->{'X-RestartIfChanged'} // "yes") || boolIsTrue($unitInfo->{'RefuseManualStop'} // "no") ) { - push @unitsToSkip, $unit; + $unitsToSkip{$unit} = 1; } else { # If this unit is socket-activated, then stop the # socket unit(s) as well, and restart the @@ -202,8 +223,9 @@ while (my ($unit, $state) = each %{$activePrev}) { } foreach my $socket (@sockets) { if (defined $activePrev->{$socket}) { - push @unitsToStop, $socket; - write_file($startListFile, { append => 1 }, "$socket\n"); + $unitsToStop{$unit} = 1; + $unitsToStart{$unit} = 1; + recordUnit($startListFile, $socket); $socketActivated = 1; } } @@ -213,7 +235,8 @@ while (my ($unit, $state) = each %{$activePrev}) { # This unit should be restarted instead of # stopped and started. - write_file($restartListFile, { append => 1 }, "$unit\n"); + $unitsToRestart{$unit} = 1; + recordUnit($restartListFile, $unit); } else { @@ -222,10 +245,11 @@ while (my ($unit, $state) = each %{$activePrev}) { # We write this to a file to ensure that the # service gets restarted if we're interrupted. if (!$socketActivated) { - write_file($startListFile, { append => 1 }, "$unit\n"); + $unitsToStart{$unit} = 1; + recordUnit($startListFile, $unit); } - push @unitsToStop, $unit; + $unitsToStop{$unit} = 1; } } @@ -268,14 +292,16 @@ foreach my $mountPoint (keys %$prevFss) { my $unit = pathToUnitName($mountPoint) . ".mount"; if (!defined $new) { # Filesystem entry disappeared, so unmount it. - push @unitsToStop, $unit; + $unitsToStop{$unit} = 1; } elsif ($prev->{fsType} ne $new->{fsType} || $prev->{device} ne $new->{device}) { # Filesystem type or device changed, so unmount and mount it. - write_file($startListFile, { append => 1 }, "$unit\n"); - push @unitsToStop, $unit; + $unitsToStop{$unit} = 1; + $unitsToStart{$unit} = 1; + recordUnit($startListFile, $unit); } elsif ($prev->{options} ne $new->{options}) { # Mount options changes, so remount it. - write_file($reloadListFile, { append => 1 }, "$unit\n"); + $unitsToReload{$unit} = 1; + recordUnit($reloadListFile, $unit); } } @@ -294,14 +320,51 @@ foreach my $device (keys %$prevSwaps) { # FIXME: update swap options (i.e. its priority). } -if (scalar @unitsToStop > 0) { - @unitsToStop = unique(@unitsToStop); - print STDERR "stopping the following units: ", join(", ", sort(@unitsToStop)), "\n"; - system("systemctl", "stop", "--", @unitsToStop); # FIXME: ignore errors? + +# Should we have systemd re-exec itself? +my $restartSystemd = abs_path("/proc/1/exe") ne abs_path("@systemd@/lib/systemd/systemd"); + + +sub filterUnits { + my ($units) = @_; + my @res; + foreach my $unit (sort(keys %{$units})) { + push @res, $unit if !defined $unitsToFilter{$unit}; + } + return @res; } -print STDERR "NOT restarting the following units: ", join(", ", sort(@unitsToSkip)), "\n" - if scalar @unitsToSkip > 0; +my @unitsToStopFiltered = filterUnits(\%unitsToStop); +my @unitsToStartFiltered = filterUnits(\%unitsToStart); + + +# Show dry-run actions. +if ($action eq "dry-activate") { + print STDERR "would stop the following units: ", join(", ", @unitsToStopFiltered), "\n" + if scalar @unitsToStopFiltered > 0; + print STDERR "would NOT stop the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n" + if scalar(keys %unitsToSkip) > 0; + print STDERR "would restart systemd\n" if $restartSystemd; + print STDERR "would restart the following units: ", join(", ", sort(keys %unitsToRestart)), "\n" + if scalar(keys %unitsToRestart) > 0; + print STDERR "would start the following units: ", join(", ", @unitsToStartFiltered), "\n" + if scalar @unitsToStartFiltered; + print STDERR "would reload the following units: ", join(", ", sort(keys %unitsToReload)), "\n" + if scalar(keys %unitsToReload) > 0; + exit 0; +} + + +syslog(LOG_NOTICE, "switching to system configuration $out"); + +if (scalar (keys %unitsToStop) > 0) { + print STDERR "stopping the following units: ", join(", ", @unitsToStopFiltered), "\n" + if scalar @unitsToStopFiltered; + system("systemctl", "stop", "--", sort(keys %unitsToStop)); # FIXME: ignore errors? +} + +print STDERR "NOT restarting the following changed units: ", join(", ", sort(keys %unitsToSkip)), "\n" + if scalar(keys %unitsToSkip) > 0; # Activate the new configuration (i.e., update /etc, make accounts, # and so on). @@ -310,7 +373,7 @@ print STDERR "activating the configuration...\n"; system("$out/activate", "$out") == 0 or $res = 2; # Restart systemd if necessary. -if (abs_path("/proc/1/exe") ne abs_path("@systemd@/lib/systemd/systemd")) { +if ($restartSystemd) { print STDERR "restarting systemd...\n"; system("@systemd@/bin/systemctl", "daemon-reexec") == 0 or $res = 2; } @@ -321,16 +384,19 @@ system("@systemd@/bin/systemctl", "reset-failed"); # Make systemd reload its units. system("@systemd@/bin/systemctl", "daemon-reload") == 0 or $res = 3; -# Signal dbus to reload its configuration before starting other units. -# Other units may rely on newly installed policy files under /etc/dbus-1 -system("@systemd@/bin/systemctl", "reload-or-restart", "dbus.service"); +# Reload units that need it. This includes remounting changed mount +# units. +if (scalar(keys %unitsToReload) > 0) { + print STDERR "reloading the following units: ", join(", ", sort(keys %unitsToReload)), "\n"; + system("@systemd@/bin/systemctl", "reload", "--", sort(keys %unitsToReload)) == 0 or $res = 4; + unlink($reloadListFile); +} # Restart changed services (those that have to be restarted rather # than stopped and started). -my @restart = unique(split('\n', read_file($restartListFile, err_mode => 'quiet') // "")); -if (scalar @restart > 0) { - print STDERR "restarting the following units: ", join(", ", sort(@restart)), "\n"; - system("@systemd@/bin/systemctl", "restart", "--", @restart) == 0 or $res = 4; +if (scalar(keys %unitsToRestart) > 0) { + print STDERR "restarting the following units: ", join(", ", sort(keys %unitsToRestart)), "\n"; + system("@systemd@/bin/systemctl", "restart", "--", sort(keys %unitsToRestart)) == 0 or $res = 4; unlink($restartListFile); } @@ -340,20 +406,11 @@ if (scalar @restart > 0) { # that are symlinks to other units. We shouldn't start both at the # same time because we'll get a "Failed to add path to set" error from # systemd. -my @start = unique("default.target", "timers.target", "sockets.target", split('\n', read_file($startListFile, err_mode => 'quiet') // "")); -print STDERR "starting the following units: ", join(", ", sort(@start)), "\n"; -system("@systemd@/bin/systemctl", "start", "--", @start) == 0 or $res = 4; +print STDERR "starting the following units: ", join(", ", @unitsToStartFiltered), "\n" + if scalar @unitsToStartFiltered; +system("@systemd@/bin/systemctl", "start", "--", sort(keys %unitsToStart)) == 0 or $res = 4; unlink($startListFile); -# Reload units that need it. This includes remounting changed mount -# units. -my @reload = unique(split '\n', read_file($reloadListFile, err_mode => 'quiet') // ""); -if (scalar @reload > 0) { - print STDERR "reloading the following units: ", join(", ", sort(@reload)), "\n"; - system("@systemd@/bin/systemctl", "reload", "--", @reload) == 0 or $res = 4; - unlink($reloadListFile); -} - # Print failed and new units. my (@failed, @new, @restarting); diff --git a/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix b/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix index 4b5e84f53c1a..6153578612c1 100644 --- a/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix +++ b/nixos/modules/system/boot/loader/generations-dir/generations-dir.nix @@ -24,6 +24,7 @@ in enable = mkOption { default = false; + type = types.bool; description = '' Whether to create symlinks to the system generations under <literal>/boot</literal>. When enabled, @@ -42,6 +43,7 @@ in copyKernels = mkOption { default = false; + type = types.bool; description = " Whether copy the necessary boot files into /boot, so /nix/store is not needed by the boot loader. diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix index a166709d39a3..585c8854feec 100644 --- a/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixos/modules/system/boot/loader/grub/grub.nix @@ -179,6 +179,7 @@ in }; splashImage = mkOption { + type = types.nullOr types.path; example = literalExample "./my-background.png"; description = '' Background image used for GRUB. It must be a 640x480, diff --git a/nixos/modules/system/boot/loader/init-script/init-script.nix b/nixos/modules/system/boot/loader/init-script/init-script.nix index 3b33d42b4ae4..374d9524ff1e 100644 --- a/nixos/modules/system/boot/loader/init-script/init-script.nix +++ b/nixos/modules/system/boot/loader/init-script/init-script.nix @@ -23,6 +23,7 @@ in enable = mkOption { default = false; + type = types.bool; description = '' Some systems require a /sbin/init script which is started. Or having it makes starting NixOS easier. diff --git a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix index d3f32418a64c..1ea3ddd8867c 100644 --- a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix +++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix @@ -21,6 +21,7 @@ in boot.loader.raspberryPi.enable = mkOption { default = false; + type = types.bool; description = '' Whether to create files with the system generations in <literal>/boot</literal>. diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix index e1e472186e37..20eee8e06e07 100644 --- a/nixos/modules/system/boot/luksroot.nix +++ b/nixos/modules/system/boot/luksroot.nix @@ -405,29 +405,19 @@ in # copy the cryptsetup binary and it's dependencies boot.initrd.extraUtilsCommands = '' - cp -pdv ${pkgs.cryptsetup}/sbin/cryptsetup $out/bin - - cp -pdv ${pkgs.libgcrypt}/lib/libgcrypt*.so.* $out/lib - cp -pdv ${pkgs.libgpgerror}/lib/libgpg-error*.so.* $out/lib - cp -pdv ${pkgs.cryptsetup}/lib/libcryptsetup*.so.* $out/lib - cp -pdv ${pkgs.popt}/lib/libpopt*.so.* $out/lib + copy_bin_and_libs ${pkgs.cryptsetup}/bin/cryptsetup ${optionalString luks.yubikeySupport '' - cp -pdv ${pkgs.ykpers}/bin/ykchalresp $out/bin - cp -pdv ${pkgs.ykpers}/bin/ykinfo $out/bin - cp -pdv ${pkgs.openssl}/bin/openssl $out/bin - - cc -O3 -I${pkgs.openssl}/include -L${pkgs.openssl}/lib ${./pbkdf2-sha512.c} -o $out/bin/pbkdf2-sha512 -lcrypto - strip -s $out/bin/pbkdf2-sha512 + copy_bin_and_libs ${pkgs.ykpers}/bin/ykchalresp + copy_bin_and_libs ${pkgs.ykpers}/bin/ykinfo + copy_bin_and_libs ${pkgs.openssl}/bin/openssl - cp -pdv ${pkgs.libusb1}/lib/libusb*.so.* $out/lib - cp -pdv ${pkgs.ykpers}/lib/libykpers*.so.* $out/lib - cp -pdv ${pkgs.libyubikey}/lib/libyubikey*.so.* $out/lib - cp -pdv ${pkgs.openssl}/lib/libssl*.so.* $out/lib - cp -pdv ${pkgs.openssl}/lib/libcrypto*.so.* $out/lib + cc -O3 -I${pkgs.openssl}/include -L${pkgs.openssl}/lib ${./pbkdf2-sha512.c} -o pbkdf2-sha512 -lcrypto + strip -s pbkdf2-sha512 + copy_bin_and_libs pbkdf2-sha512 - mkdir -p $out/etc/ssl - cp -pdv ${pkgs.openssl}/etc/ssl/openssl.cnf $out/etc/ssl + mkdir -p $out/etc/ssl + cp -pdv ${pkgs.openssl}/etc/ssl/openssl.cnf $out/etc/ssl cat > $out/bin/openssl-wrap <<EOF #!$out/bin/sh diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index a34a13602650..5af644279e5f 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -177,20 +177,24 @@ fi if test -e /sys/power/resume -a -e /sys/power/disk; then if test -n "@resumeDevice@"; then resumeDev="@resumeDevice@" + resumeInfo="$(udevadm info -q property "$resumeDev" )" else for sd in @resumeDevices@; do # Try to detect resume device. According to Ubuntu bug: # https://bugs.launchpad.net/ubuntu/+source/pm-utils/+bug/923326/comments/1 # When there are multiple swap devices, we can't know where will hibernate # image reside. We can check all of them for swsuspend blkid. - if [ "$(udevadm info -q property "$sd" | sed -n 's/^ID_FS_TYPE=//p')" = "swsuspend" ]; then + resumeInfo="$(udevadm info -q property "$sd" )" + if [ "$(echo "$resumeInfo" | sed -n 's/^ID_FS_TYPE=//p')" = "swsuspend" ]; then resumeDev="$sd" break fi done fi - if test -n "$resumeDev"; then - readlink -f "$resumeDev" > /sys/power/resume 2> /dev/null || echo "failed to resume..." + if test -e "$resumeDev"; then + resumeMajor="$(echo "$resumeInfo" | sed -n 's/^MAJOR=//p')" + resumeMinor="$(echo "$resumeInfo" | sed -n 's/^MINOR=//p')" + echo "$resumeMajor:$resumeMinor" > /sys/power/resume 2> /dev/null || echo "failed to resume..." fi fi diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index 16bebe03740a..8b58eccdcec7 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -39,46 +39,60 @@ let mkdir -p $out/bin $out/lib ln -s $out/bin $out/sbin - # Copy what we need from Glibc. - cp -pv ${pkgs.glibc}/lib/ld*.so.? $out/lib - cp -pv ${pkgs.glibc}/lib/libc.so.* $out/lib - cp -pv ${pkgs.glibc}/lib/libm.so.* $out/lib - cp -pv ${pkgs.glibc}/lib/libpthread.so.* $out/lib - cp -pv ${pkgs.glibc}/lib/librt.so.* $out/lib - cp -pv ${pkgs.glibc}/lib/libdl.so.* $out/lib - cp -pv ${pkgs.gcc.cc}/lib*/libgcc_s.so.* $out/lib + copy_bin_and_libs () { + [ -f "$out/bin/$(basename $1)" ] && rm "$out/bin/$(basename $1)" + cp -pdv $1 $out/bin + } # Copy BusyBox. - cp -pvd ${pkgs.busybox}/bin/* ${pkgs.busybox}/sbin/* $out/bin/ + for BIN in ${pkgs.busybox}/{s,}bin/*; do + copy_bin_and_libs $BIN + done # Copy some utillinux stuff. - cp -vf --remove-destination ${pkgs.utillinux}/sbin/blkid $out/bin - cp -pdv ${pkgs.utillinux}/lib/libblkid*.so.* $out/lib - cp -pdv ${pkgs.utillinux}/lib/libuuid*.so.* $out/lib + copy_bin_and_libs ${pkgs.utillinux}/sbin/blkid # Copy dmsetup and lvm. - cp -v ${pkgs.lvm2}/sbin/dmsetup $out/bin/dmsetup - cp -v ${pkgs.lvm2}/sbin/lvm $out/bin/lvm - cp -v ${pkgs.lvm2}/lib/libdevmapper.so.*.* $out/lib - cp -v ${pkgs.systemd}/lib/libsystemd.so.* $out/lib + copy_bin_and_libs ${pkgs.lvm2}/sbin/dmsetup + copy_bin_and_libs ${pkgs.lvm2}/sbin/lvm # Add RAID mdadm tool. - cp -v ${pkgs.mdadm}/sbin/mdadm $out/bin/mdadm + copy_bin_and_libs ${pkgs.mdadm}/sbin/mdadm # Copy udev. - cp -v ${udev}/lib/systemd/systemd-udevd ${udev}/bin/udevadm $out/bin - cp -v ${udev}/lib/udev/*_id $out/bin - cp -pdv ${udev}/lib/libudev.so.* $out/lib - cp -v ${pkgs.kmod}/lib/libkmod.so.* $out/lib - cp -v ${pkgs.acl}/lib/libacl.so.* $out/lib - cp -v ${pkgs.attr}/lib/libattr.so.* $out/lib + copy_bin_and_libs ${udev}/lib/systemd/systemd-udevd + copy_bin_and_libs ${udev}/bin/udevadm + for BIN in ${udev}/lib/udev/*_id; do + copy_bin_and_libs $BIN + done # Copy modprobe. - cp -v ${pkgs.kmod}/bin/kmod $out/bin/ + copy_bin_and_libs ${pkgs.kmod}/bin/kmod ln -sf kmod $out/bin/modprobe ${config.boot.initrd.extraUtilsCommands} + # Copy ld manually since it isn't detected correctly + cp -pv ${pkgs.glibc}/lib/ld*.so.? $out/lib + + # Copy all of the needed libraries for the binaries + for BIN in $(find $out/{bin,sbin} -type f); do + echo "Copying libs for bin $BIN" + LDD="$(ldd $BIN)" || continue + LIBS="$(echo "$LDD" | awk '{print $3}' | sed '/^$/d')" + for LIB in $LIBS; do + [ ! -f "$out/lib/$(basename $LIB)" ] && cp -pdv $LIB $out/lib + while [ "$(readlink $LIB)" != "" ]; do + LINK="$(readlink $LIB)" + if [ "${LINK:0:1}" != "/" ]; then + LINK="$(dirname $LIB)/$LINK" + fi + LIB="$LINK" + [ ! -f "$out/lib/$(basename $LIB)" ] && cp -pdv $LIB $out/lib + done + done + done + # Strip binaries further than normal. chmod -R u+w $out stripDirs "lib bin" "-s" @@ -100,10 +114,11 @@ let echo "testing patched programs..." $out/bin/ash -c 'echo hello world' | grep "hello world" export LD_LIBRARY_PATH=$out/lib - $out/bin/mount --help 2>&1 | grep "BusyBox" + $out/bin/mount --help 2>&1 | grep -q "BusyBox" + $out/bin/blkid --help 2>&1 | grep -q 'libblkid' $out/bin/udevadm --version - $out/bin/dmsetup --version 2>&1 | tee -a log | grep "version:" - LVM_SYSTEM_DIR=$out $out/bin/lvm version 2>&1 | tee -a log | grep "LVM" + $out/bin/dmsetup --version 2>&1 | tee -a log | grep -q "version:" + LVM_SYSTEM_DIR=$out $out/bin/lvm version 2>&1 | tee -a log | grep -q "LVM" $out/bin/mdadm --version ${config.boot.initrd.extraUtilsCommandsTest} @@ -205,7 +220,7 @@ let # The closure of the init script of boot stage 1 is what we put in # the initial RAM disk. initialRamdisk = pkgs.makeInitrd { - inherit (config.boot.initrd) compressor; + inherit (config.boot.initrd) compressor prepend; contents = [ { object = bootStage1; @@ -247,6 +262,14 @@ in ''; }; + boot.initrd.prepend = mkOption { + default = [ ]; + type = types.listOf types.str; + description = '' + Other initrd files to prepend to the final initrd we are building. + ''; + }; + boot.initrd.checkJournalingFS = mkOption { default = true; type = types.bool; diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index f853a8f6775c..29c449d4d0be 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -1,7 +1,7 @@ { config, lib, pkgs, utils, ... }: -with lib; with utils; +with lib; with import ./systemd-unit-options.nix { inherit config lib; }; let @@ -13,7 +13,7 @@ let makeUnit = name: unit: let - pathSafeName = lib.replaceChars ["@" "\\"] ["-" "-"] name; + pathSafeName = lib.replaceChars ["@" ":" "\\"] ["-" "-" "-"] name; in if unit.enable then pkgs.runCommand "unit-${pathSafeName}" { preferLocalBuild = true; inherit (unit) text; } diff --git a/nixos/modules/tasks/filesystems/btrfs.nix b/nixos/modules/tasks/filesystems/btrfs.nix index d0a2ac645e0b..049f7708d739 100644 --- a/nixos/modules/tasks/filesystems/btrfs.nix +++ b/nixos/modules/tasks/filesystems/btrfs.nix @@ -17,13 +17,9 @@ in boot.initrd.extraUtilsCommands = mkIf inInitrd '' - mkdir -p $out/bin - cp -v ${pkgs.btrfsProgs}/bin/btrfs $out/bin + copy_bin_and_libs ${pkgs.btrfsProgs}/bin/btrfs ln -sv btrfs $out/bin/btrfsck ln -sv btrfsck $out/bin/fsck.btrfs - # !!! Increases uncompressed initrd by 240k - cp -pv ${pkgs.zlib}/lib/libz.so* $out/lib - cp -pv ${pkgs.lzo}/lib/liblzo2.so* $out/lib ''; boot.initrd.extraUtilsCommandsTest = mkIf inInitrd diff --git a/nixos/modules/tasks/filesystems/cifs.nix b/nixos/modules/tasks/filesystems/cifs.nix index c60f175db841..3932b5c9acf9 100644 --- a/nixos/modules/tasks/filesystems/cifs.nix +++ b/nixos/modules/tasks/filesystems/cifs.nix @@ -18,7 +18,7 @@ in boot.initrd.extraUtilsCommands = mkIf inInitrd '' - cp -v ${pkgs.cifs_utils}/sbin/mount.cifs $out/bin + copy_bin_and_libs ${pkgs.cifs_utils}/sbin/mount.cifs ''; }; diff --git a/nixos/modules/tasks/filesystems/ext.nix b/nixos/modules/tasks/filesystems/ext.nix index 24592e9d5882..cc9d0ef37d59 100644 --- a/nixos/modules/tasks/filesystems/ext.nix +++ b/nixos/modules/tasks/filesystems/ext.nix @@ -10,12 +10,11 @@ boot.initrd.extraUtilsCommands = '' # Copy e2fsck and friends. - cp -v ${pkgs.e2fsprogs}/sbin/e2fsck $out/bin - cp -v ${pkgs.e2fsprogs}/sbin/tune2fs $out/bin + copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/e2fsck + copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/tune2fs ln -sv e2fsck $out/bin/fsck.ext2 ln -sv e2fsck $out/bin/fsck.ext3 ln -sv e2fsck $out/bin/fsck.ext4 - cp -pdv ${pkgs.e2fsprogs}/lib/lib*.so.* $out/lib ''; }; diff --git a/nixos/modules/tasks/filesystems/f2fs.nix b/nixos/modules/tasks/filesystems/f2fs.nix index 1ed7b1b6a62e..430ac630a885 100644 --- a/nixos/modules/tasks/filesystems/f2fs.nix +++ b/nixos/modules/tasks/filesystems/f2fs.nix @@ -13,9 +13,7 @@ in boot.initrd.availableKernelModules = mkIf inInitrd [ "f2fs" ]; boot.initrd.extraUtilsCommands = mkIf inInitrd '' - mkdir -p $out/bin $out/lib - cp -v ${pkgs.f2fs-tools}/sbin/fsck.f2fs $out/bin - cp -pdv ${pkgs.f2fs-tools}/lib/lib*.so.* $out/lib + copy_bin_and_libs ${pkgs.f2fs-tools}/sbin/fsck.f2fs ''; }; } diff --git a/nixos/modules/tasks/filesystems/jfs.nix b/nixos/modules/tasks/filesystems/jfs.nix index b7091ce9b184..fc3905c7dc20 100644 --- a/nixos/modules/tasks/filesystems/jfs.nix +++ b/nixos/modules/tasks/filesystems/jfs.nix @@ -13,7 +13,7 @@ in boot.initrd.kernelModules = mkIf inInitrd [ "jfs" ]; boot.initrd.extraUtilsCommands = mkIf inInitrd '' - cp -v ${pkgs.jfsutils}/sbin/fsck.jfs "$out/bin/" + copy_bin_and_libs ${pkgs.jfsutils}/sbin/fsck.jfs ''; }; } diff --git a/nixos/modules/tasks/filesystems/reiserfs.nix b/nixos/modules/tasks/filesystems/reiserfs.nix index a3bfb3fed8ef..ab4c43e2ab82 100644 --- a/nixos/modules/tasks/filesystems/reiserfs.nix +++ b/nixos/modules/tasks/filesystems/reiserfs.nix @@ -17,8 +17,8 @@ in boot.initrd.extraUtilsCommands = mkIf inInitrd '' - cp -v ${pkgs.reiserfsprogs}/sbin/reiserfsck $out/bin - ln -sv reiserfsck $out/bin/fsck.reiserfs + copy_bin_and_libs ${pkgs.reiserfsprogs}/sbin/reiserfsck + ln -s reiserfsck $out/bin/fsck.reiserfs ''; }; diff --git a/nixos/modules/tasks/filesystems/unionfs-fuse.nix b/nixos/modules/tasks/filesystems/unionfs-fuse.nix index fe195e0db0b6..3e38bffa3ba2 100644 --- a/nixos/modules/tasks/filesystems/unionfs-fuse.nix +++ b/nixos/modules/tasks/filesystems/unionfs-fuse.nix @@ -7,9 +7,8 @@ boot.initrd.kernelModules = [ "fuse" ]; boot.initrd.extraUtilsCommands = '' - cp -v ${pkgs.fuse}/lib/libfuse* $out/lib - cp -v ${pkgs.fuse}/sbin/mount.fuse $out/bin - cp -v ${pkgs.unionfs-fuse}/bin/unionfs $out/bin + copy_bin_and_libs ${pkgs.fuse}/sbin/mount.fuse + copy_bin_and_libs ${pkgs.unionfs-fuse}/bin/unionfs substitute ${pkgs.unionfs-fuse}/sbin/mount.unionfs-fuse $out/bin/mount.unionfs-fuse \ --replace '${pkgs.bash}/bin/bash' /bin/sh \ --replace '${pkgs.fuse}/sbin' /bin \ diff --git a/nixos/modules/tasks/filesystems/vfat.nix b/nixos/modules/tasks/filesystems/vfat.nix index 4cfe6e208f7e..958e27ae8a32 100644 --- a/nixos/modules/tasks/filesystems/vfat.nix +++ b/nixos/modules/tasks/filesystems/vfat.nix @@ -17,7 +17,7 @@ in boot.initrd.extraUtilsCommands = mkIf inInitrd '' - cp -v ${pkgs.dosfstools}/sbin/dosfsck $out/bin + copy_bin_and_libs ${pkgs.dosfstools}/sbin/dosfsck ln -sv dosfsck $out/bin/fsck.vfat ''; diff --git a/nixos/modules/tasks/filesystems/xfs.nix b/nixos/modules/tasks/filesystems/xfs.nix index 5225b62a88c5..d7c3930f4a3c 100644 --- a/nixos/modules/tasks/filesystems/xfs.nix +++ b/nixos/modules/tasks/filesystems/xfs.nix @@ -17,7 +17,7 @@ in boot.initrd.extraUtilsCommands = mkIf inInitrd '' - cp -v ${pkgs.xfsprogs}/sbin/fsck.xfs $out/bin + copy_bin_and_libs ${pkgs.xfsprogs}/sbin/fsck.xfs ''; # Trick just to set 'sh' after the extraUtils nuke-refs. diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix index 93782ffa4d58..d4b10e9ed09e 100644 --- a/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixos/modules/tasks/filesystems/zfs.nix @@ -55,8 +55,7 @@ in boot.zfs = { useGit = mkOption { type = types.bool; - # TODO(wkennington): Revert when 0.6.4 is out - default = versionAtLeast config.boot.kernelPackages.kernel.version "3.19"; + default = false; example = true; description = '' Use the git version of the SPL and ZFS packages. @@ -204,11 +203,14 @@ in kernelModules = [ "spl" "zfs" ]; extraUtilsCommands = '' - cp -v ${zfsUserPkg}/sbin/zfs $out/bin - cp -v ${zfsUserPkg}/sbin/zdb $out/bin - cp -v ${zfsUserPkg}/sbin/zpool $out/bin - cp -pdv ${zfsUserPkg}/lib/lib*.so* $out/lib - cp -pdv ${pkgs.zlib}/lib/lib*.so* $out/lib + copy_bin_and_libs ${zfsUserPkg}/sbin/zfs + copy_bin_and_libs ${zfsUserPkg}/sbin/zdb + copy_bin_and_libs ${zfsUserPkg}/sbin/zpool + ''; + extraUtilsCommandsTest = mkIf inInitrd + '' + $out/bin/zfs --help >/dev/null 2>&1 + $out/bin/zpool --help >/dev/null 2>&1 ''; postDeviceCommands = concatStringsSep "\n" (['' ZFS_FORCE="${optionalString cfgZfs.forceImportRoot "-f"}" diff --git a/nixos/modules/tasks/kbd.nix b/nixos/modules/tasks/kbd.nix index 03c42404e5d5..8d26998021d3 100644 --- a/nixos/modules/tasks/kbd.nix +++ b/nixos/modules/tasks/kbd.nix @@ -22,6 +22,7 @@ in # FIXME: still needed? boot.extraTTYs = mkOption { default = []; + type = types.listOf types.string; example = ["tty8" "tty9"]; description = '' Tty (virtual console) devices, in addition to the consoles on diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix index 70158fc7252b..8223c5a4941e 100644 --- a/nixos/modules/tasks/network-interfaces-systemd.nix +++ b/nixos/modules/tasks/network-interfaces-systemd.nix @@ -35,7 +35,10 @@ in assertions = [ { assertion = cfg.defaultGatewayWindowSize == null; message = "networking.defaultGatewayWindowSize is not supported by networkd."; - } ]; + } ] ++ flip mapAttrsToList cfg.bridges (n: { rstp, ... }: { + assertion = !rstp; + message = "networking.bridges.${n}.rstp is not supported by networkd."; + }); systemd.services.dhcpcd.enable = mkDefault false; diff --git a/nixos/modules/tasks/trackpoint.nix b/nixos/modules/tasks/trackpoint.nix index 5d1bb631b54f..778cdc5d30dd 100644 --- a/nixos/modules/tasks/trackpoint.nix +++ b/nixos/modules/tasks/trackpoint.nix @@ -16,7 +16,7 @@ with lib; Enable sensitivity and speed configuration for trackpoints. ''; }; - + sensitivity = mkOption { default = 128; example = 255; @@ -44,7 +44,7 @@ with lib; Enable scrolling while holding the middle mouse button. ''; }; - + }; }; @@ -70,7 +70,7 @@ with lib; '' Section "InputClass" Identifier "Trackpoint Wheel Emulation" - MatchProduct "TPPS/2 IBM TrackPoint|DualPoint Stick|Synaptics Inc. Composite TouchPad / TrackPoint|ThinkPad USB Keyboard with TrackPoint|USB Trackpoint pointing device|Composite TouchPad / TrackPoint" + MatchProduct "Elantech PS/2 TrackPoint|TPPS/2 IBM TrackPoint|DualPoint Stick|Synaptics Inc. Composite TouchPad / TrackPoint|ThinkPad USB Keyboard with TrackPoint|USB Trackpoint pointing device|Composite TouchPad / TrackPoint" MatchDevicePath "/dev/input/event*" Option "EmulateWheel" "true" Option "EmulateWheelButton" "2" diff --git a/nixos/modules/virtualisation/amazon-config.nix b/nixos/modules/virtualisation/amazon-config.nix index e816ed2d183a..a27e52a8e68c 100644 --- a/nixos/modules/virtualisation/amazon-config.nix +++ b/nixos/modules/virtualisation/amazon-config.nix @@ -1,5 +1,3 @@ -{ config, pkgs, modulesPath, ... }: - { - imports = [ "${modulesPath}/virtualisation/amazon-image.nix" ]; + imports = [ ./amazon-image.nix ]; } diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix index 0473c2454e22..600a29f31bc5 100644 --- a/nixos/modules/virtualisation/amazon-image.nix +++ b/nixos/modules/virtualisation/amazon-image.nix @@ -165,7 +165,7 @@ in boot.initrd.extraUtilsCommands = '' # We need swapon in the initrd. - cp --remove-destination ${pkgs.utillinux}/sbin/swapon $out/bin + copy_bin_and_libs ${pkgs.utillinux}/sbin/swapon ''; # Don't put old configurations in the GRUB menu. The user has no diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix index c461cf8c00cb..da39dda85353 100644 --- a/nixos/modules/virtualisation/containers.nix +++ b/nixos/modules/virtualisation/containers.nix @@ -10,6 +10,7 @@ let isExecutable = true; src = ./nixos-container.pl; perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl"; + su = "${pkgs.shadow.su}/bin/su"; inherit (pkgs) utillinux; }; @@ -202,7 +203,7 @@ in script = '' mkdir -p -m 0755 "$root/etc" "$root/var/lib" - mkdir -p -m 0700 "$root/var/lib/private" "$root/root" + mkdir -p -m 0700 "$root/var/lib/private" "$root/root" /run/containers if ! [ -e "$root/etc/os-release" ]; then touch "$root/etc/os-release" fi @@ -211,7 +212,7 @@ in "/nix/var/nix/profiles/per-container/$INSTANCE" \ "/nix/var/nix/gcroots/per-container/$INSTANCE" - cp -f /etc/resolv.conf "$root/etc/resolv.conf" + cp --remove-destination /etc/resolv.conf "$root/etc/resolv.conf" if [ "$PRIVATE_NETWORK" = 1 ]; then extraFlags+=" --network-veth" @@ -260,11 +261,21 @@ in ip route add $LOCAL_ADDRESS dev $ifaceHost fi fi + + # Get the leader PID so that we can signal it in + # preStop. We can't use machinectl there because D-Bus + # might be shutting down. FIXME: in systemd 219 we can + # just signal systemd-nspawn to do a clean shutdown. + machinectl show "$INSTANCE" | sed 's/Leader=\(.*\)/\1/;t;d' > "/run/containers/$INSTANCE.pid" ''; preStop = '' - machinectl poweroff "$INSTANCE" || true + pid="$(cat /run/containers/$INSTANCE.pid)" + if [ -n "$pid" ]; then + kill -RTMIN+4 "$pid" + fi + rm -f "/run/containers/$INSTANCE.pid" ''; restartIfChanged = false; diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix index 4d493b3896f2..ee5485071a35 100644 --- a/nixos/modules/virtualisation/google-compute-image.nix +++ b/nixos/modules/virtualisation/google-compute-image.nix @@ -7,6 +7,9 @@ in { imports = [ ../profiles/headless.nix ../profiles/qemu-guest.nix ]; + # https://cloud.google.com/compute/docs/tutorials/building-images + networking.firewall.enable = mkDefault false; + system.build.googleComputeImage = pkgs.vmTools.runInLinuxVM ( pkgs.runCommand "google-compute-image" @@ -95,6 +98,7 @@ in boot.kernelParams = [ "console=ttyS0" "panic=1" "boot.panic_on_fail" ]; boot.initrd.kernelModules = [ "virtio_scsi" ]; + boot.kernelModules = [ "virtio_pci" "virtio_net" ]; # Generate a GRUB menu. Amazon's pv-grub uses this to boot our kernel/initrd. boot.loader.grub.device = "/dev/sda"; @@ -108,6 +112,7 @@ in # at instance creation time. services.openssh.enable = true; services.openssh.permitRootLogin = "without-password"; + services.openssh.passwordAuthentication = mkDefault false; # Force getting the hostname from Google Compute. networking.hostName = mkDefault ""; @@ -129,10 +134,10 @@ in wantedBy = [ "sshd.service" ]; before = [ "sshd.service" ]; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; + after = [ "network-online.target" "ip-up.target" ]; + wants = [ "network-online.target" "ip-up.target" ]; - script = let wget = "${pkgs.wget}/bin/wget --retry-connrefused -t 6 --waitretry=10"; in + script = let wget = "${pkgs.wget}/bin/wget --retry-connrefused -t 15 --waitretry=10 --header='Metadata-Flavor: Google'"; in '' # When dealing with cryptographic keys, we want to keep things private. umask 077 @@ -140,7 +145,7 @@ in if ! [ -e /root/.ssh/authorized_keys ]; then echo "obtaining SSH key..." mkdir -m 0700 -p /root/.ssh - ${wget} -O /root/authorized-keys-metadata http://metadata/0.1/meta-data/authorized-keys + ${wget} -O /root/authorized-keys-metadata http://metadata.google.internal/0.1/meta-data/authorized-keys if [ $? -eq 0 -a -e /root/authorized-keys-metadata ]; then cat /root/authorized-keys-metadata | cut -d: -f2- > /root/key.pub if ! grep -q -f /root/key.pub /root/.ssh/authorized_keys; then @@ -156,7 +161,7 @@ in ${flip concatMapStrings config.services.openssh.hostKeys (k : let kName = baseNameOf k.path; in '' echo "trying to obtain SSH private host key ${kName}" - ${wget} -O /root/${kName} http://metadata/0.1/meta-data/attributes/${kName} && : + ${wget} -O /root/${kName} http://metadata.google.internal/0.1/meta-data/attributes/${kName} && : if [ $? -eq 0 -a -e /root/${kName} ]; then countKeys=$((countKeys+1)) mv -f /root/${kName} ${k.path} @@ -178,5 +183,79 @@ in serviceConfig.RemainAfterExit = true; serviceConfig.StandardError = "journal+console"; serviceConfig.StandardOutput = "journal+console"; - }; + }; + + # Setings taken from https://cloud.google.com/compute/docs/tutorials/building-images#providedkernel + boot.kernel.sysctl = { + # enables syn flood protection + "net.ipv4.tcp_syncookies" = mkDefault "1"; + + # ignores source-routed packets + "net.ipv4.conf.all.accept_source_route" = mkDefault "0"; + + # ignores source-routed packets + "net.ipv4.conf.default.accept_source_route" = mkDefault "0"; + + # ignores ICMP redirects + "net.ipv4.conf.all.accept_redirects" = mkDefault "0"; + + # ignores ICMP redirects + "net.ipv4.conf.default.accept_redirects" = mkDefault "0"; + + # ignores ICMP redirects from non-GW hosts + "net.ipv4.conf.all.secure_redirects" = mkDefault "1"; + + # ignores ICMP redirects from non-GW hosts + "net.ipv4.conf.default.secure_redirects" = mkDefault "1"; + + # don't allow traffic between networks or act as a router + "net.ipv4.ip_forward" = mkDefault "0"; + + # don't allow traffic between networks or act as a router + "net.ipv4.conf.all.send_redirects" = mkDefault "0"; + + # don't allow traffic between networks or act as a router + "net.ipv4.conf.default.send_redirects" = mkDefault "0"; + + # reverse path filtering - IP spoofing protection + "net.ipv4.conf.all.rp_filter" = mkDefault "1"; + + # reverse path filtering - IP spoofing protection + "net.ipv4.conf.default.rp_filter" = mkDefault "1"; + + # ignores ICMP broadcasts to avoid participating in Smurf attacks + "net.ipv4.icmp_echo_ignore_broadcasts" = mkDefault "1"; + + # ignores bad ICMP errors + "net.ipv4.icmp_ignore_bogus_error_responses" = mkDefault "1"; + + # logs spoofed, source-routed, and redirect packets + "net.ipv4.conf.all.log_martians" = mkDefault "1"; + + # log spoofed, source-routed, and redirect packets + "net.ipv4.conf.default.log_martians" = mkDefault "1"; + + # implements RFC 1337 fix + "net.ipv4.tcp_rfc1337" = mkDefault "1"; + + # randomizes addresses of mmap base, heap, stack and VDSO page + "kernel.randomize_va_space" = mkDefault "2"; + + # provides protection from ToCToU races + "fs.protected_hardlinks" = mkDefault "1"; + + # provides protection from ToCToU races + "fs.protected_symlinks" = mkDefault "1"; + + # makes locating kernel addresses more difficult + "kernel.kptr_restrict" = mkDefault "1"; + + # set ptrace protections + "kernel.yama.ptrace_scope" = mkDefault "1"; + + # set perf only available to root + "kernel.perf_event_paranoid" = mkDefault "2"; + + }; + } diff --git a/nixos/modules/virtualisation/lxc.nix b/nixos/modules/virtualisation/lxc.nix index 10d3a6575fb9..22da012e4141 100644 --- a/nixos/modules/virtualisation/lxc.nix +++ b/nixos/modules/virtualisation/lxc.nix @@ -32,7 +32,9 @@ in default = ""; description = '' - This is the system-wide LXC config. See lxc.system.conf(5). + This is the system-wide LXC config. See + <citerefentry><refentrytitle>lxc.system.conf</refentrytitle> + <manvolnum>5</manvolnum></citerefentry>. ''; }; @@ -43,7 +45,8 @@ in description = '' Default config (default.conf) for new containers, i.e. for - network config. See lxc.container.conf(5). + network config. See <citerefentry><refentrytitle>lxc.container.conf + </refentrytitle><manvolnum>5</manvolnum></citerefentry>. ''; }; @@ -54,7 +57,9 @@ in description = '' This is the config file for managing unprivileged user network - administration access in LXC. See lxc-user-net(5). + administration access in LXC. See <citerefentry> + <refentrytitle>lxc-user-net</refentrytitle><manvolnum>5</manvolnum> + </citerefentry>. ''; }; diff --git a/nixos/modules/virtualisation/nixos-container.pl b/nixos/modules/virtualisation/nixos-container.pl index 94edfb37948a..f1d9e64ee38f 100644 --- a/nixos/modules/virtualisation/nixos-container.pl +++ b/nixos/modules/virtualisation/nixos-container.pl @@ -8,6 +8,7 @@ use Fcntl ':flock'; use Getopt::Long qw(:config gnu_getopt); my $nsenter = "@utillinux@/bin/nsenter"; +my $su = "@su@"; # Ensure a consistent umask. umask 0022; @@ -22,6 +23,7 @@ Usage: nixos-container list nixos-container start <container-name> nixos-container stop <container-name> nixos-container status <container-name> + nixos-container update <container-name> [--config <string>] nixos-container login <container-name> nixos-container root-login <container-name> nixos-container run <container-name> -- args... @@ -271,14 +273,14 @@ elsif ($action eq "login") { } elsif ($action eq "root-login") { - runInContainer("su", "root", "-l"); + runInContainer("@su@", "root", "-l"); } elsif ($action eq "run") { shift @ARGV; shift @ARGV; # Escape command. my $s = join(' ', map { s/'/'\\''/g; "'$_'" } @ARGV); - runInContainer("su", "root", "-l", "-c", "exec " . $s); + runInContainer("@su@", "root", "-l", "-c", "exec " . $s); } elsif ($action eq "show-ip") { diff --git a/nixos/modules/virtualisation/parallels-guest.nix b/nixos/modules/virtualisation/parallels-guest.nix index 141e70974058..2f40283b3e1d 100644 --- a/nixos/modules/virtualisation/parallels-guest.nix +++ b/nixos/modules/virtualisation/parallels-guest.nix @@ -82,7 +82,7 @@ in systemd.services.prlshprint = { description = "Parallels Shared Printer Tool"; wantedBy = [ "multi-user.target" ]; - bindsTo = [ "cupsd.service" ]; + bindsTo = [ "cups.service" ]; serviceConfig = { Type = "forking"; ExecStart = "${prl-tools}/bin/prlshprint"; diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index a5a133dfa5dc..8c7e840910de 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -346,7 +346,7 @@ in boot.initrd.extraUtilsCommands = '' # We need mke2fs in the initrd. - cp -vf --remove-destination ${pkgs.e2fsprogs}/sbin/mke2fs $out/bin + copy_bin_and_libs ${pkgs.e2fsprogs}/sbin/mke2fs ''; boot.initrd.postDeviceCommands = diff --git a/nixos/modules/virtualisation/xen-dom0.nix b/nixos/modules/virtualisation/xen-dom0.nix index f3a24c5cf25b..ea9f61aad6a6 100644 --- a/nixos/modules/virtualisation/xen-dom0.nix +++ b/nixos/modules/virtualisation/xen-dom0.nix @@ -5,18 +5,8 @@ with lib; let - cfg = config.virtualisation.xen; - xen = pkgs.xen; - - xendConfig = pkgs.writeText "xend-config.sxp" - '' - (loglevel DEBUG) - (network-script network-bridge) - (vif-script vif-bridge) - ''; - in { @@ -58,23 +48,62 @@ in ''; }; + virtualisation.xen.bridge = + mkOption { + default = "xenbr0"; + description = + '' + Create a bridge for the Xen domUs to connect to. + ''; + }; + + virtualisation.xen.stored = + mkOption { + type = types.path; + description = + '' + Xen Store daemon to use. Defaults to oxenstored of the xen package. + ''; + }; + + virtualisation.xen.trace = + mkOption { + default = false; + description = + '' + Enable Xen tracing. + ''; + }; }; ###### implementation config = mkIf cfg.enable { + assertions = [ { + assertion = pkgs.stdenv.isx86_64; + message = "Xen currently not supported on ${pkgs.stdenv.system}"; + } { + assertion = config.boot.loader.grub.enable && (config.boot.loader.grub.efiSupport == false); + message = "Xen currently does not support EFI boot"; + } ]; + + virtualisation.xen.stored = mkDefault "${xen}/bin/oxenstored"; environment.systemPackages = [ xen ]; - # Domain 0 requires a pvops-enabled kernel. - boot.kernelPackages = pkgs.linuxPackages_3_2_xen; + # Make sure Domain 0 gets the required configuration + #boot.kernelPackages = pkgs.boot.kernelPackages.override { features={xen_dom0=true;}; }; boot.kernelModules = - [ "xen_evtchn" "xen_gntdev" "xen_blkback" "xen_netback" "xen_pciback" - "blktap" "tun" + [ "xen-evtchn" "xen-gntdev" "xen-gntalloc" "xen-blkback" "xen-netback" + "xen-pciback" "evtchn" "gntdev" "netbk" "blkbk" "xen-scsibk" + "usbbk" "pciback" "xen-acpi-processor" "blktap2" "tun" "netxen_nic" + "xen_wdt" "xen-acpi-processor" "xen-privcmd" "xen-scsiback" + "xenfs" ]; + # The radeonfb kernel module causes the screen to go black as soon # as it's loaded, so don't load it. boot.blacklistedKernelModules = [ "radeonfb" ]; @@ -87,8 +116,8 @@ in options loop max_loop=64 ''; - virtualisation.xen.bootParams = - [ "loglvl=all" "guest_loglvl=all" ] ++ + virtualisation.xen.bootParams = [] ++ + optionals cfg.trace [ "loglvl=all" "guest_loglvl=all" ] ++ optional (cfg.domain0MemorySize != 0) "dom0_mem=${toString cfg.domain0MemorySize}M"; system.extraSystemBuilderCmds = @@ -101,71 +130,36 @@ in system.activationScripts.xen = '' if [ -d /proc/xen ]; then - ${pkgs.sysvtools}/bin/mountpoint -q /proc/xen || \ + ${pkgs.kmod}/bin/modprobe xenfs 2> /dev/null + ${pkgs.utillinux}/bin/mountpoint -q /proc/xen || \ ${pkgs.utillinux}/bin/mount -t xenfs none /proc/xen fi ''; - jobs.xend = - { description = "Xen Control Daemon"; - - startOn = "stopped udevtrigger"; - - path = - [ pkgs.bridge-utils pkgs.gawk pkgs.iproute pkgs.nettools - pkgs.utillinux pkgs.bash xen pkgs.pciutils pkgs.procps - ]; - - environment.XENCONSOLED_TRACE = "hv"; - - preStart = - '' - mkdir -p /var/log/xen/console -m 0700 - - ${xen}/sbin/xend start - - # Wait until Xend is running. - for ((i = 0; i < 60; i++)); do echo "waiting for xend..."; ${xen}/sbin/xend status && break; done - - ${xen}/sbin/xend status || exit 1 - ''; - - postStop = "${xen}/sbin/xend stop"; - }; - - jobs.xendomains = - { description = "Automatically starts, saves and restores Xen domains on startup/shutdown"; - - startOn = "started xend"; - - stopOn = "starting shutdown and stopping xend"; - - restartIfChanged = false; - - path = [ pkgs.xen ]; - - environment.XENDOM_CONFIG = "${xen}/etc/sysconfig/xendomains"; - - preStart = - '' - mkdir -p /var/lock/subsys -m 755 - ${xen}/etc/init.d/xendomains start - ''; - - postStop = "${xen}/etc/init.d/xendomains stop"; - }; + # Domain 0 requires a pvops-enabled kernel. + system.requiredKernelConfig = with config.lib.kernelConfig; + [ (isYes "XEN") + (isYes "X86_IO_APIC") + (isYes "ACPI") + (isYes "XEN_DOM0") + (isYes "PCI_XEN") + (isYes "XEN_DEV_EVTCHN") + (isYes "XENFS") + (isYes "XEN_COMPAT_XENFS") + (isYes "XEN_SYS_HYPERVISOR") + (isYes "XEN_GNTDEV") + (isYes "XEN_BACKEND") + (isModule "XEN_NETDEV_BACKEND") + (isModule "XEN_BLKDEV_BACKEND") + (isModule "XEN_PCIDEV_BACKEND") + (isYes "XEN_BALLOON") + (isYes "XEN_SCRUB_PAGES") + ]; - # To prevent a race between dhcpcd and xend's bridge setup script - # (which renames eth* to peth* and recreates eth* as a virtual - # device), start dhcpcd after xend. - jobs.dhcpcd.startOn = mkOverride 50 "started xend"; environment.etc = - [ { source = xendConfig; - target = "xen/xend-config.sxp"; - } - { source = "${xen}/etc/xen/scripts"; - target = "xen/scripts"; + [ { source = "${xen}/etc/xen/xl.conf"; + target = "xen/xl.conf"; } ]; @@ -174,6 +168,125 @@ in services.udev.path = [ pkgs.bridge-utils pkgs.iproute ]; + systemd.services.xen-store = { + description = "Xen Store Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "xen-store.socket" ]; + requires = [ "xen-store.socket" ]; + preStart = '' + export XENSTORED_ROOTDIR="/var/lib/xenstored" + rm -f "$XENSTORED_ROOTDIR"/tdb* &>/dev/null + + mkdir -p /var/run + ${optionalString cfg.trace "mkdir -p /var/log/xen"} + grep -q control_d /proc/xen/capabilities + ''; + serviceConfig.ExecStart = '' + ${cfg.stored}${optionalString cfg.trace " -T /var/log/xen/xenstored-trace.log"} --no-fork + ''; + postStart = '' + time=0 + timeout=30 + # Wait for xenstored to actually come up, timing out after 30 seconds + while [ $time -lt $timeout ] && ! `${pkgs.xen}/bin/xenstore-read -s / >/dev/null 2>&1` ; do + time=$(($time+1)) + sleep 1 + done + + # Exit if we timed out + if ! [ $time -lt $timeout ] ; then + echo "Could not start Xenstore Daemon" + exit 1 + fi + + ${pkgs.xen}/bin/xenstore-write "/local/domain/0/name" "Domain-0" + ${pkgs.xen}/bin/xenstore-write "/local/domain/0/domid" 0 + ''; + }; + + systemd.sockets.xen-store = { + description = "XenStore Socket for userspace API"; + wantedBy = [ "sockets.target" ]; + socketConfig = { + ListenStream = [ "/var/run/xenstored/socket" "/var/run/xenstored/socket_ro" ]; + SocketMode = "0660"; + SocketUser = "root"; + SocketGroup = "root"; + }; + }; + + + systemd.services.xen-console = { + description = "Xen Console Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "xen-store.service" ]; + preStart = '' + mkdir -p /var/run/xen + ${optionalString cfg.trace "mkdir -p /var/log/xen"} + grep -q control_d /proc/xen/capabilities + ''; + serviceConfig = { + ExecStart = '' + ${pkgs.xen}/bin/xenconsoled${optionalString cfg.trace " --log=all --log-dir=/var/log/xen"} + ''; + }; + }; + + + systemd.services.xen-qemu = { + description = "Xen Qemu Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "xen-console.service" ]; + serviceConfig.ExecStart = '' + ${pkgs.xen}/lib/xen/bin/qemu-system-i386 -xen-domid 0 -xen-attach -name dom0 -nographic -M xenpv \ + -monitor /dev/null -serial /dev/null -parallel /dev/null + ''; + }; + + + systemd.services.xen-watchdog = { + description = "Xen Watchdog Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "xen-qemu.service" ]; + serviceConfig.ExecStart = "${pkgs.xen}/bin/xenwatchdogd 30 15"; + serviceConfig.Type = "forking"; + serviceConfig.RestartSec = "1"; + serviceConfig.Restart = "on-failure"; + }; + + + systemd.services.xen-bridge = { + description = "Xen bridge"; + wantedBy = [ "multi-user.target" ]; + before = [ "xen-domains.service" ]; + serviceConfig.RemainAfterExit = "yes"; + serviceConfig.ExecStart = '' + ${pkgs.bridge-utils}/bin/brctl addbr ${cfg.bridge} + ${pkgs.inetutils}/bin/ifconfig ${cfg.bridge} up + ''; + serviceConfig.ExecStop = '' + ${pkgs.inetutils}/bin/ifconfig ${cfg.bridge} down + ${pkgs.bridge-utils}/bin/brctl delbr ${cfg.bridge} + ''; + }; + + systemd.services.xen-domains = { + description = "Xen domains - automatically starts, saves and restores Xen domains"; + wantedBy = [ "multi-user.target" ]; + after = [ "xen-bridge.service" "xen-qemu.service" ]; + ## To prevent a race between dhcpcd and xend's bridge setup script + ## (which renames eth* to peth* and recreates eth* as a virtual + ## device), start dhcpcd after xend. + before = [ "dhcpd.service" ]; + restartIfChanged = false; + serviceConfig.RemainAfterExit = "yes"; + path = [ pkgs.xen ]; + environment.XENDOM_CONFIG = "${pkgs.xen}/etc/sysconfig/xendomains"; + preStart = "mkdir -p /var/lock/subsys -m 755"; + serviceConfig.ExecStart = "${pkgs.xen}/etc/init.d/xendomains start"; + serviceConfig.ExecStop = "${pkgs.xen}/etc/init.d/xendomains stop"; + }; + }; } diff --git a/nixos/modules/virtualisation/xen-domU.nix b/nixos/modules/virtualisation/xen-domU.nix index 483589669345..2db3190ad139 100644 --- a/nixos/modules/virtualisation/xen-domU.nix +++ b/nixos/modules/virtualisation/xen-domU.nix @@ -9,7 +9,10 @@ boot.loader.grub.device = "nodev"; boot.loader.grub.extraPerEntryConfig = "root (hd0)"; - boot.initrd.kernelModules = [ "xen-blkfront" ]; + boot.initrd.kernelModules = + [ "xen-blkfront" "xen-tpmfront" "xen-kbdfront" "xen-fbfront" + "xen-netfront" "xen-pcifront" "xen-scsifront" + ]; # Send syslog messages to the Xen console. services.syslogd.tty = "hvc0"; diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix index 2381132bb45e..cb1c200ab475 100644 --- a/nixos/release-combined.nix +++ b/nixos/release-combined.nix @@ -31,7 +31,7 @@ in rec { nixpkgs = nixpkgsSrc; })) [ "unstable" ]; - tested = pkgs.releaseTools.aggregate { + tested = pkgs.lib.hydraJob (pkgs.releaseTools.aggregate { name = "nixos-${nixos.channel.version}"; meta = { description = "Release-critical builds for the NixOS channel"; @@ -57,6 +57,7 @@ in rec { (all nixos.tests.installer.simple) (all nixos.tests.installer.simpleLabels) (all nixos.tests.installer.simpleProvided) + (all nixos.tests.installer.swraid) (all nixos.tests.installer.btrfsSimple) (all nixos.tests.installer.btrfsSubvols) (all nixos.tests.installer.btrfsSubvolDefault) @@ -85,6 +86,6 @@ in rec { nixpkgs.tarball (all nixpkgs.emacs) ]; - }; + }); } diff --git a/nixos/release-small.nix b/nixos/release-small.nix index 7f53a101bdfc..11155c853696 100644 --- a/nixos/release-small.nix +++ b/nixos/release-small.nix @@ -79,7 +79,7 @@ in rec { vim; }; - tested = pkgs.releaseTools.aggregate { + tested = lib.hydraJob (pkgs.releaseTools.aggregate { name = "nixos-${nixos.channel.version}"; meta = { description = "Release-critical builds for the NixOS channel"; @@ -88,6 +88,6 @@ in rec { constituents = let all = x: map (system: x.${system}) supportedSystems; in [ nixpkgs.tarball ] ++ lib.collect lib.isDerivation nixos; - }; + }); } diff --git a/nixos/release.nix b/nixos/release.nix index 1bd3ec577318..375b65d040e6 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -3,22 +3,20 @@ , supportedSystems ? [ "x86_64-linux" "i686-linux" ] }: +with import ../lib; + let version = builtins.readFile ../.version; versionSuffix = (if stableBranch then "." else "pre") + "${toString nixpkgs.revCount}.${nixpkgs.shortRev}"; - forAllSystems = pkgs.lib.genAttrs supportedSystems; - - scrubDrv = drv: let res = { inherit (drv) drvPath outPath type name system meta; outputName = "out"; out = res; }; in res; + forAllSystems = genAttrs supportedSystems; - callTest = fn: args: forAllSystems (system: scrubDrv (import fn ({ inherit system; } // args))); + callTest = fn: args: forAllSystems (system: hydraJob (import fn ({ inherit system; } // args))); pkgs = import nixpkgs { system = "x86_64-linux"; }; - lib = pkgs.lib; - versionModule = { system.nixosVersionSuffix = versionSuffix; @@ -42,10 +40,10 @@ let in # Declare the ISO as a build product so that it shows up in Hydra. - scrubDrv (runCommand "nixos-iso-${config.system.nixosVersion}" + hydraJob (runCommand "nixos-iso-${config.system.nixosVersion}" { meta = { description = "NixOS installation CD (${description}) - ISO image for ${system}"; - maintainers = map (x: lib.getAttr x lib.maintainers) maintainers; + maintainers = map (x: lib.maintainers.${x}) maintainers; }; inherit iso; passthru = { inherit config; }; @@ -74,7 +72,7 @@ let tarball // { meta = { description = "NixOS system tarball for ${system} - ${stdenv.platform.name}"; - maintainers = map (x: lib.getAttr x lib.maintainers) maintainers; + maintainers = map (x: lib.maintainers.${x}) maintainers; }; inherit config; }; @@ -83,12 +81,12 @@ let makeClosure = module: buildFromConfig module (config: config.system.build.toplevel); - buildFromConfig = module: sel: forAllSystems (system: scrubDrv (sel (import ./lib/eval-config.nix { + buildFromConfig = module: sel: forAllSystems (system: hydraJob (sel (import ./lib/eval-config.nix { inherit system; - modules = [ module versionModule ] ++ lib.singleton + modules = [ module versionModule ] ++ singleton ({ config, lib, ... }: - { fileSystems."/".device = lib.mkDefault "/dev/sda1"; - boot.loader.grub.device = lib.mkDefault "/dev/sda"; + { fileSystems."/".device = mkDefault "/dev/sda1"; + boot.loader.grub.device = mkDefault "/dev/sda"; }); }).config)); @@ -175,10 +173,10 @@ in rec { in # Declare the OVA as a build product so that it shows up in Hydra. - scrubDrv (runCommand "nixos-ova-${config.system.nixosVersion}-${system}" + hydraJob (runCommand "nixos-ova-${config.system.nixosVersion}-${system}" { meta = { description = "NixOS VirtualBox appliance (${system})"; - maintainers = lib.maintainers.eelco; + maintainers = maintainers.eelco; }; ova = config.system.build.virtualBoxOVA; } @@ -195,9 +193,9 @@ in rec { dummy = forAllSystems (system: pkgs.runCommand "dummy" { toplevel = (import lib/eval-config.nix { inherit system; - modules = lib.singleton ({ config, pkgs, ... }: - { fileSystems."/".device = lib.mkDefault "/dev/sda1"; - boot.loader.grub.device = lib.mkDefault "/dev/sda"; + modules = singleton ({ config, pkgs, ... }: + { fileSystems."/".device = mkDefault "/dev/sda1"; + boot.loader.grub.device = mkDefault "/dev/sda"; }); }).config.system.build.toplevel; } @@ -242,33 +240,35 @@ in rec { tests.avahi = callTest tests/avahi.nix {}; tests.bittorrent = callTest tests/bittorrent.nix {}; tests.blivet = callTest tests/blivet.nix {}; - tests.cadvisor = scrubDrv (import tests/cadvisor.nix { system = "x86_64-linux"; }); + tests.cadvisor = hydraJob (import tests/cadvisor.nix { system = "x86_64-linux"; }); tests.chromium = callTest tests/chromium.nix {}; tests.cjdns = callTest tests/cjdns.nix {}; tests.containers = callTest tests/containers.nix {}; - tests.docker = scrubDrv (import tests/docker.nix { system = "x86_64-linux"; }); - tests.dockerRegistry = scrubDrv (import tests/docker-registry.nix { system = "x86_64-linux"; }); - tests.etcd = scrubDrv (import tests/etcd.nix { system = "x86_64-linux"; }); + tests.docker = hydraJob (import tests/docker.nix { system = "x86_64-linux"; }); + tests.dockerRegistry = hydraJob (import tests/docker-registry.nix { system = "x86_64-linux"; }); + tests.etcd = hydraJob (import tests/etcd.nix { system = "x86_64-linux"; }); tests.firefox = callTest tests/firefox.nix {}; tests.firewall = callTest tests/firewall.nix {}; - tests.fleet = scrubDrv (import tests/fleet.nix { system = "x86_64-linux"; }); + tests.fleet = hydraJob (import tests/fleet.nix { system = "x86_64-linux"; }); #tests.gitlab = callTest tests/gitlab.nix {}; tests.gnome3 = callTest tests/gnome3.nix {}; - tests.installer.grub1 = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).grub1.test); - tests.installer.lvm = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).lvm.test); - tests.installer.rebuildCD = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).rebuildCD.test); - tests.installer.separateBoot = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).separateBoot.test); - tests.installer.simple = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).simple.test); - tests.installer.simpleLabels = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).simpleLabels.test); - tests.installer.simpleProvided = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).simpleProvided.test); - tests.installer.btrfsSimple = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).btrfsSimple.test); - tests.installer.btrfsSubvols = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).btrfsSubvols.test); - tests.installer.btrfsSubvolDefault = forAllSystems (system: scrubDrv (import tests/installer.nix { inherit system; }).btrfsSubvolDefault.test); + tests.i3wm = callTest tests/i3wm.nix {}; + tests.installer.grub1 = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).grub1.test); + tests.installer.lvm = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).lvm.test); + tests.installer.rebuildCD = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).rebuildCD.test); + tests.installer.separateBoot = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).separateBoot.test); + tests.installer.simple = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).simple.test); + tests.installer.simpleLabels = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).simpleLabels.test); + tests.installer.simpleProvided = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).simpleProvided.test); + tests.installer.swraid = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).swraid.test); + tests.installer.btrfsSimple = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).btrfsSimple.test); + tests.installer.btrfsSubvols = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).btrfsSubvols.test); + tests.installer.btrfsSubvolDefault = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).btrfsSubvolDefault.test); tests.influxdb = callTest tests/influxdb.nix {}; tests.ipv6 = callTest tests/ipv6.nix {}; tests.jenkins = callTest tests/jenkins.nix {}; tests.kde4 = callTest tests/kde4.nix {}; - tests.kubernetes = scrubDrv (import tests/kubernetes.nix { system = "x86_64-linux"; }); + tests.kubernetes = hydraJob (import tests/kubernetes.nix { system = "x86_64-linux"; }); tests.latestKernel.login = callTest tests/login.nix { latestKernel = true; }; tests.login = callTest tests/login.nix {}; #tests.logstash = callTest tests/logstash.nix {}; @@ -298,9 +298,10 @@ in rec { # TODO: put in networking.nix after the test becomes more complete tests.networkingProxy = callTest tests/networking-proxy.nix {}; tests.nfs3 = callTest tests/nfs.nix { version = 3; }; + tests.nfs4 = callTest tests/nfs.nix { version = 4; }; tests.nsd = callTest tests/nsd.nix {}; tests.openssh = callTest tests/openssh.nix {}; - tests.panamax = scrubDrv (import tests/panamax.nix { system = "x86_64-linux"; }); + tests.panamax = hydraJob (import tests/panamax.nix { system = "x86_64-linux"; }); tests.peerflix = callTest tests/peerflix.nix {}; tests.printing = callTest tests/printing.nix {}; tests.proxy = callTest tests/proxy.nix {}; @@ -309,8 +310,12 @@ in rec { tests.simple = callTest tests/simple.nix {}; tests.tomcat = callTest tests/tomcat.nix {}; tests.udisks2 = callTest tests/udisks2.nix {}; - tests.virtualbox = callTest tests/virtualbox.nix {}; + tests.virtualbox = hydraJob (import tests/virtualbox.nix { system = "x86_64-linux"; }); tests.xfce = callTest tests/xfce.nix {}; + tests.bootBiosCdrom = forAllSystems (system: hydraJob (import tests/boot.nix { inherit system; }).bootBiosCdrom); + tests.bootBiosUsb = forAllSystems (system: hydraJob (import tests/boot.nix { inherit system; }).bootBiosUsb); + tests.bootUefiCdrom = forAllSystems (system: hydraJob (import tests/boot.nix { inherit system; }).bootUefiCdrom); + tests.bootUefiUsb = forAllSystems (system: hydraJob (import tests/boot.nix { inherit system; }).bootUefiUsb); /* Build a bunch of typical closures so that Hydra can keep track of diff --git a/nixos/tests/boot.nix b/nixos/tests/boot.nix new file mode 100644 index 000000000000..2fdbb0c00b85 --- /dev/null +++ b/nixos/tests/boot.nix @@ -0,0 +1,63 @@ +{ system ? builtins.currentSystem }: + +with import ../lib/testing.nix { inherit system; }; +with import ../lib/qemu-flags.nix; +with pkgs.lib; + +let + + iso = + (import ../lib/eval-config.nix { + inherit system; + modules = + [ ../modules/installer/cd-dvd/installation-cd-minimal.nix + ../modules/testing/test-instrumentation.nix + { key = "serial"; + boot.loader.grub.timeout = mkOverride 0 0; + + # The test cannot access the network, so any sources we + # need must be included in the ISO. + isoImage.storeContents = + [ pkgs.glibcLocales + pkgs.sudo + pkgs.docbook5 + pkgs.docbook5_xsl + pkgs.grub + pkgs.perlPackages.XMLLibXML + pkgs.unionfs-fuse + pkgs.gummiboot + ]; + } + ]; + }).config.system.build.isoImage; + + makeBootTest = name: machineConfig: + makeTest { + inherit iso; + name = "boot-" + name; + nodes = { }; + testScript = + '' + my $machine = createMachine({ ${machineConfig}, qemuFlags => '-m 768' }); + $machine->start; + $machine->waitForUnit("multi-user.target"); + $machine->shutdown; + ''; + }; +in { + bootBiosCdrom = makeBootTest "bios-cdrom" '' + cdrom => glob("${iso}/iso/*.iso") + ''; + bootBiosUsb = makeBootTest "bios-usb" '' + usb => glob("${iso}/iso/*.iso") + ''; + bootUefiCdrom = makeBootTest "uefi-cdrom" '' + cdrom => glob("${iso}/iso/*.iso"), + bios => '${pkgs.OVMF}/FV/OVMF.fd' + ''; + bootUefiUsb = makeBootTest "uefi-usb" '' + usb => glob("${iso}/iso/*.iso"), + bios => '${pkgs.OVMF}/FV/OVMF.fd' + ''; + } + diff --git a/nixos/tests/chromium.nix b/nixos/tests/chromium.nix index 368d0e43c465..026433fc7ee9 100644 --- a/nixos/tests/chromium.nix +++ b/nixos/tests/chromium.nix @@ -109,7 +109,12 @@ import ./make-test.nix ( $machine->waitUntilSucceeds("${xdo "check-startup" '' search --sync --onlyvisible --name "startup done" # close first start help popup - key Escape + key -delay 1000 Escape + # XXX: This is to make sure the popup is closed, but we better do + # screenshots to detect visual changes. + key -delay 2000 Escape + key -delay 3000 Escape + key -delay 4000 Escape windowfocus --sync windowactivate --sync ''}"); diff --git a/nixos/tests/cjdns.nix b/nixos/tests/cjdns.nix index 7bb3863c683f..45164234b1bd 100644 --- a/nixos/tests/cjdns.nix +++ b/nixos/tests/cjdns.nix @@ -3,15 +3,15 @@ let carolPubKey = "n932l3pjvmhtxxcdrqq2qpw5zc58f01vvjx01h4dtd1bb0nnu2h0.k"; carolPassword = "678287829ce4c67bc8b227e56d94422ee1b85fa11618157b2f591de6c6322b52"; carolIp4 = "192.168.0.9"; - + basicConfig = { config, pkgs, ... }: { services.cjdns.enable = true; - + # Turning off DHCP isn't very realistic but makes # the sequence of address assignment less stochastic. networking.useDHCP = false; - + networking.interfaces.eth1.prefixLength = 24; # CJDNS output is incompatible with the XML log. systemd.services.cjdns.serviceConfig.StandardOutput = "null"; @@ -41,19 +41,18 @@ import ./make-test.nix { # Bob explicitly connects to Carol over UDPInterface. bob = { config, lib, nodes, ... }: - + let carolIp4 = lib.mkForce nodes.carol.config.networking.interfaces.eth1; in - + { imports = [ basicConfig ]; - + networking.interfaces.eth1.ipAddress = "192.168.0.2"; - + services.cjdns = { UDPInterface = { bind = "0.0.0.0:1024"; connectTo."192.168.0.1:1024}" = - { hostname = "carol.hype"; - password = carolPassword; + { password = carolPassword; publicKey = carolPubKey; }; }; @@ -75,7 +74,7 @@ import ./make-test.nix { ''; networking.interfaces.eth1.ipAddress = "192.168.0.1"; - + services.cjdns = { authorizedPasswords = [ carolPassword ]; ETHInterface.bind = "eth1"; @@ -106,13 +105,13 @@ import ./make-test.nix { my $carolIp6 = cjdnsIp $carol; # ping a few times each to let the routing table establish itself - + $alice->succeed("ping6 -c 4 $carolIp6"); - $bob->succeed("ping6 -c 4 carol.hype"); + $bob->succeed("ping6 -c 4 $carolIp6"); $carol->succeed("ping6 -c 4 $aliceIp6"); $carol->succeed("ping6 -c 4 $bobIp6"); - + $alice->succeed("ping6 -c 4 $bobIp6"); $bob->succeed("ping6 -c 4 $aliceIp6"); diff --git a/nixos/tests/i3wm.nix b/nixos/tests/i3wm.nix new file mode 100644 index 000000000000..0966dba8a3c8 --- /dev/null +++ b/nixos/tests/i3wm.nix @@ -0,0 +1,28 @@ +import ./make-test.nix { + name = "i3wm"; + + machine = { lib, pkgs, ... }: { + imports = [ ./common/x11.nix ./common/user-account.nix ]; + services.xserver.displayManager.auto.user = "alice"; + services.xserver.windowManager.default = lib.mkForce "i3"; + services.xserver.windowManager.i3.enable = true; + }; + + testScript = { nodes, ... }: '' + $machine->waitForX; + $machine->waitForWindow(qr/first configuration/); + $machine->sleep(1); + $machine->screenshot("started"); + $machine->sendKeys("ret"); + $machine->sleep(1); + $machine->sendKeys("alt"); + $machine->sleep(1); + $machine->screenshot("configured"); + $machine->sendKeys("ret"); + $machine->sleep(2); + $machine->sendKeys("alt-ret"); + $machine->waitForWindow(qr/machine.*alice/); + $machine->sleep(1); + $machine->screenshot("terminal"); + ''; +} diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix index c7815bde3f5c..af87705b9279 100644 --- a/nixos/tests/installer.nix +++ b/nixos/tests/installer.nix @@ -327,12 +327,12 @@ in { $machine->succeed( "parted /dev/vda --" . " mklabel msdos" - . " mkpart primary ext2 1M 30MB" # /boot - . " mkpart extended 30M -1s" - . " mkpart logical 31M 1531M" # md0 (root), first device - . " mkpart logical 1540M 3040M" # md0 (root), second device - . " mkpart logical 3050M 3306M" # md1 (swap), first device - . " mkpart logical 3320M 3576M", # md1 (swap), second device + . " mkpart primary ext2 1M 100MB" # /boot + . " mkpart extended 100M -1s" + . " mkpart logical 102M 1602M" # md0 (root), first device + . " mkpart logical 1603M 3103M" # md0 (root), second device + . " mkpart logical 3104M 3360M" # md1 (swap), first device + . " mkpart logical 3361M 3617M", # md1 (swap), second device "udevadm settle", "ls -l /dev/vda* >&2", "cat /proc/partitions >&2", diff --git a/nixos/tests/kubernetes.nix b/nixos/tests/kubernetes.nix index 8bc7c8d618ad..0a9eda930bad 100644 --- a/nixos/tests/kubernetes.nix +++ b/nixos/tests/kubernetes.nix @@ -13,7 +13,7 @@ import ./make-test.nix rec { id: redis-master-pod containers: - name: master - image: master:5000/scratch + image: master:5000/nix cpu: 100 ports: - name: redis-server @@ -50,8 +50,8 @@ import ./make-test.nix rec { virtualisation.memorySize = 768; services.kubernetes = { roles = ["master" "node"]; + dockerCfg = ''{"master:5000":{}}''; controllerManager.machines = ["master" "node"]; - kubelet.extraOpts = "-network_container_image=master:5000/pause"; apiserver.address = "0.0.0.0"; verbose = true; }; @@ -94,7 +94,8 @@ import ./make-test.nix rec { { services.kubernetes = { roles = ["node"]; - kubelet.extraOpts = "-network_container_image=master:5000/pause"; + dockerCfg = ''{"master:5000":{}}''; + kubelet.apiServers = ["master:8080"]; verbose = true; }; virtualisation.docker.extraOptions = "--iptables=false --ip-masq=false -b cbr0 --insecure-registry master:5000"; @@ -155,14 +156,14 @@ import ./make-test.nix rec { $node->waitForUnit("kubernetes-kubelet.service"); $node->waitForUnit("kubernetes-proxy.service"); - $master->waitUntilSucceeds("kubecfg list minions | grep master"); - $master->waitUntilSucceeds("kubecfg list minions | grep node"); + $master->waitUntilSucceeds("kubectl get minions | grep master"); + $master->waitUntilSucceeds("kubectl get minions | grep node"); $client->waitForUnit("docker.service"); - $client->succeed("tar cv --files-from /dev/null | docker import - scratch"); - $client->succeed("docker tag scratch master:5000/scratch"); + $client->succeed("tar cv --files-from /dev/null | docker import - nix"); + $client->succeed("docker tag nix master:5000/nix"); $master->waitForUnit("docker-registry.service"); - $client->succeed("docker push master:5000/scratch"); + $client->succeed("docker push master:5000/nix"); $client->succeed("mkdir -p /root/pause"); $client->succeed("cp /etc/test/pause /root/pause/"); $client->succeed("cp /etc/test/Dockerfile /root/pause/"); diff --git a/nixos/tests/misc.nix b/nixos/tests/misc.nix index e1830d95b41f..b44af5316bea 100644 --- a/nixos/tests/misc.nix +++ b/nixos/tests/misc.nix @@ -102,6 +102,10 @@ import ./make-test.nix { subtest "shell-vars", sub { $machine->succeed('[ -n "$NIX_PATH" ]'); }; + + subtest "nix-db", sub { + $machine->succeed("nix-store -qR /run/current-system | grep nixos-"); + }; ''; } diff --git a/nixos/tests/nfs.nix b/nixos/tests/nfs.nix index 5ed805a16952..216fea7784a7 100644 --- a/nixos/tests/nfs.nix +++ b/nixos/tests/nfs.nix @@ -1,4 +1,4 @@ -import ./make-test.nix ({ version, ... }: +import ./make-test.nix ({ version ? 4, ... }: let diff --git a/nixos/tests/printing.nix b/nixos/tests/printing.nix index 3e5ee680c7a6..ba10f23582d7 100644 --- a/nixos/tests/printing.nix +++ b/nixos/tests/printing.nix @@ -31,8 +31,8 @@ import ./make-test.nix ({pkgs, ... }: { startAll; # Make sure that cups is up on both sides. - $server->waitForUnit("cupsd.service"); - $client->waitForUnit("cupsd.service"); + $server->waitForUnit("cups.service"); + $client->waitForUnit("cups.service"); $client->succeed("lpstat -r") =~ /scheduler is running/ or die; $client->succeed("lpstat -H") =~ "/var/run/cups/cups.sock" or die; $client->succeed("curl --fail http://localhost:631/"); diff --git a/nixos/tests/virtualbox.nix b/nixos/tests/virtualbox.nix index b2b1ec877798..827481879a3e 100644 --- a/nixos/tests/virtualbox.nix +++ b/nixos/tests/virtualbox.nix @@ -39,9 +39,8 @@ import ./make-test.nix ({ pkgs, ... }: with pkgs.lib; let ]; boot.initrd.extraUtilsCommands = '' - cp -av -t "$out/bin/" \ - "${pkgs.linuxPackages.virtualboxGuestAdditions}/sbin/mount.vboxsf" \ - "${pkgs.utillinux}/bin/unshare" + copy_bin_and_libs "${pkgs.linuxPackages.virtualboxGuestAdditions}/sbin/mount.vboxsf" + copy_bin_and_libs "${pkgs.utillinux}/bin/unshare" ${(attrs.extraUtilsCommands or (const "")) pkgs} ''; @@ -245,6 +244,7 @@ import ./make-test.nix ({ pkgs, ... }: with pkgs.lib; let for (my $i = 0; $i <= 120; $i += 10) { $machine->sleep(10); return if checkRunning_${name}; + eval { $_[0]->() } if defined $_[0]; } die "VirtualBox VM didn't start up within 2 minutes"; } @@ -336,7 +336,9 @@ in { $machine->screenshot("gui_manager_started"); $machine->sendKeys("ret"); $machine->screenshot("gui_manager_sent_startup"); - waitForStartup_simple; + waitForStartup_simple (sub { + $machine->sendKeys("ret"); + }); $machine->screenshot("gui_started"); waitForVMBoot_simple; $machine->screenshot("gui_booted"); |