diff options
author | Vladimír Čunát <vcunat@gmail.com> | 2016-03-08 09:57:58 +0100 |
---|---|---|
committer | Vladimír Čunát <vcunat@gmail.com> | 2016-03-08 09:58:19 +0100 |
commit | 09af15654f0c8091f1b9e0bbb2e523cdee194442 (patch) | |
tree | e648edef1ce4c64c533f2593aa22b8015cf0e506 /nixos | |
parent | f306e67e15bdbe9a8358c9f81319fc4fcbadc2eb (diff) | |
parent | 0ee75214f336474e127c2e3546c0406a0c4d5fa7 (diff) | |
download | nixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.tar nixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.tar.gz nixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.tar.bz2 nixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.tar.lz nixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.tar.xz nixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.tar.zst nixpkgs-09af15654f0c8091f1b9e0bbb2e523cdee194442.zip |
Merge master into closure-size
The kde-5 stuff still didn't merge well. I hand-fixed what I saw, but there may be more problems.
Diffstat (limited to 'nixos')
129 files changed, 3834 insertions, 1980 deletions
diff --git a/nixos/default.nix b/nixos/default.nix index 6359d10c880..5d69b79e13a 100644 --- a/nixos/default.nix +++ b/nixos/default.nix @@ -1,20 +1,12 @@ { configuration ? import ./lib/from-env.nix "NIXOS_CONFIG" <nixos-config> , system ? builtins.currentSystem -, extraModules ? [] - # This attribute is used to specify a different nixos version, a different - # system or additional modules which might be set conditionally. -, reEnter ? false }: let - reEnterModule = { - config.nixos.path = with (import ../lib); mkIf reEnter (mkForce null); - config.nixos.configuration = configuration; - }; eval = import ./lib/eval-config.nix { inherit system; - modules = [ configuration reEnterModule ] ++ extraModules; + modules = [ configuration ]; }; inherit (eval) pkgs; @@ -22,14 +14,14 @@ let # This is for `nixos-rebuild build-vm'. vmConfig = (import ./lib/eval-config.nix { inherit system; - modules = [ configuration reEnterModule ./modules/virtualisation/qemu-vm.nix ] ++ extraModules; + modules = [ configuration ./modules/virtualisation/qemu-vm.nix ]; }).config; # This is for `nixos-rebuild build-vm-with-bootloader'. vmWithBootLoaderConfig = (import ./lib/eval-config.nix { inherit system; modules = - [ configuration reEnterModule + [ configuration ./modules/virtualisation/qemu-vm.nix { virtualisation.useBootLoader = true; } ]; @@ -38,7 +30,7 @@ let in { - inherit (eval.config.nixos.reflect) config options; + inherit (eval) config options; system = eval.config.system.build.toplevel; diff --git a/nixos/doc/manual/configuration/configuration.xml b/nixos/doc/manual/configuration/configuration.xml index 1e488b59343..caba8fb1f4a 100644 --- a/nixos/doc/manual/configuration/configuration.xml +++ b/nixos/doc/manual/configuration/configuration.xml @@ -26,8 +26,8 @@ effect after you run <command>nixos-rebuild</command>.</para> <!-- FIXME: auto-include NixOS module docs --> <xi:include href="postgresql.xml" /> +<xi:include href="gitlab.xml" /> <xi:include href="acme.xml" /> -<xi:include href="nixos.xml" /> <!-- Apache; libvirtd virtualisation --> diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix index 0f080947833..4c0e5518f1e 100644 --- a/nixos/doc/manual/default.nix +++ b/nixos/doc/manual/default.nix @@ -56,8 +56,8 @@ let cp -prd $sources/* . # */ chmod -R u+w . cp ${../../modules/services/databases/postgresql.xml} configuration/postgresql.xml + cp ${../../modules/services/misc/gitlab.xml} configuration/gitlab.xml cp ${../../modules/security/acme.xml} configuration/acme.xml - cp ${../../modules/misc/nixos.xml} configuration/nixos.xml ln -s ${optionsDocBook} options-db.xml echo "${version}" > version ''; diff --git a/nixos/doc/manual/installation/installing.xml b/nixos/doc/manual/installation/installing.xml index 9aec57fb6d5..7e71df28cdb 100644 --- a/nixos/doc/manual/installation/installing.xml +++ b/nixos/doc/manual/installation/installing.xml @@ -22,7 +22,10 @@ (with empty password).</para></listitem> <listitem><para>If you downloaded the graphical ISO image, you can - run <command>start display-manager</command> to start KDE.</para></listitem> + run <command>start display-manager</command> to start KDE. If you + want to continue on the terminal, you can use + <command>loadkeys</command> to switch to your preferred keyboard layout. + (We even provide neo2 via <command>loadkeys de neo</command>!)</para></listitem> <listitem><para>The boot process should have brought up networking (check <command>ip a</command>). Networking is necessary for the diff --git a/nixos/doc/manual/release-notes/release-notes.xml b/nixos/doc/manual/release-notes/release-notes.xml index 6ed99315a7a..2beaab00800 100644 --- a/nixos/doc/manual/release-notes/release-notes.xml +++ b/nixos/doc/manual/release-notes/release-notes.xml @@ -9,7 +9,7 @@ <para>This section lists the release notes for each stable version of NixOS and current unstable revision.</para> -<xi:include href="rl-unstable.xml" /> +<xi:include href="rl-1603.xml" /> <xi:include href="rl-1509.xml" /> <xi:include href="rl-1412.xml" /> <xi:include href="rl-1404.xml" /> diff --git a/nixos/doc/manual/release-notes/rl-unstable.xml b/nixos/doc/manual/release-notes/rl-1603.xml index 768b51d84a4..0ede1a9ce8e 100644 --- a/nixos/doc/manual/release-notes/rl-unstable.xml +++ b/nixos/doc/manual/release-notes/rl-1603.xml @@ -2,9 +2,9 @@ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" - xml:id="sec-release-unstable"> + xml:id="sec-release-16.03"> -<title>Unstable</title> +<title>Release 16.03 (“Emu”, 2016/03/??)</title> <para>In addition to numerous new and upgraded packages, this release has the following highlights:</para> @@ -12,19 +12,6 @@ has the following highlights:</para> <itemizedlist> <listitem> - <para>You can now pin a specific version of NixOS in your <filename>configuration.nix</filename> - by setting: - -<programlisting> -nixos.path = ./nixpkgs-unstable-2015-12-06/nixos; -</programlisting> - - This will make NixOS re-evaluate your configuration with the modules of - the specified NixOS version at the given path. For more details, see - <xref linkend="module-misc-nixos" /></para> - </listitem> - - <listitem> <para>Firefox and similar browsers are now <emphasis>wrapped by default</emphasis>. The package and attribute names are plain <literal>firefox</literal> or <literal>midori</literal>, etc. Backward-compatibility attributes were set up, @@ -41,8 +28,10 @@ nixos.path = ./nixpkgs-unstable-2015-12-06/nixos; <itemizedlist> <listitem><para><literal>services/monitoring/longview.nix</literal></para></listitem> + <listitem><para><literal>services/networking/pdnsd.nix</literal></para></listitem> <listitem><para><literal>services/web-apps/pump.io.nix</literal></para></listitem> <listitem><para><literal>services/security/haka.nix</literal></para></listitem> + <listitem><para><literal>i18n/inputMethod/default.nix</literal></para></listitem> </itemizedlist> </para> @@ -196,6 +185,68 @@ fileSystems."/example" = { <literal>services.hardware.opengl.extraPackages{,32}</literal> instead. You can also specify VDPAU drivers there.</para> </listitem> + + <listitem> + <para> + <literal>programs.ibus</literal> moved to <literal>i18n.inputMethod.ibus</literal>. + The option <literal>programs.ibus.plugins</literal> changed to <literal>i18n.inputMethod.ibus.engines</literal> + and the option to enable ibus changed from <literal>programs.ibus.enable</literal> to + <literal>i18n.inputMethod.enabled</literal>. + <literal>i18n.inputMethod.enabled</literal> should be set to the used input method name, + <literal>"ibus"</literal> for ibus. + An example of the new style: + +<programlisting> +i18n.inputMethod.enabled = "ibus"; +i18n.inputMethod.ibus.engines = with pkgs.ibus-engines; [ anthy mozc ]; +</programlisting> + +That is equivalent to the old version: + +<programlisting> +programs.ibus.enable = true; +programs.ibus.plugins = with pkgs; [ ibus-anthy mozc ]; +</programlisting> + + </para> + </listitem> + + <listitem> + <para><literal>services.udev.extraRules</literal> option now writes rules + to <filename>99-local.rules</filename> instead of <filename>10-local.rules</filename>. + This makes all the user rules apply after others, so their results wouldn't be + overriden by anything else.</para> + </listitem> + + <listitem> + <para>Large parts of the <literal>services.gitlab</literal> module has been + been rewritten. There are new configuration options available. The + <literal>stateDir</literal> option was renamned to + <literal>statePath</literal> and the <literal>satellitesDir</literal> option + was removed. Please review the currently available options.</para> + </listitem> + + <listitem> + <para> + The option <option>services.nsd.zones.<name>.data</option> no + longer interpret the dollar sign ($) as a shell variable, as such it + should not be escaped anymore. Thus the following zone data: + </para> + <programlisting> +\$ORIGIN example.com. +\$TTL 1800 +@ IN SOA ns1.vpn.nbp.name. admin.example.com. ( + </programlisting> + <para> + Should modified to look like the actual file expected by nsd: + </para> + <programlisting> +$ORIGIN example.com. +$TTL 1800 +@ IN SOA ns1.vpn.nbp.name. admin.example.com. ( + </programlisting> + </listitem> + </itemizedlist> @@ -214,6 +265,12 @@ fileSystems."/example" = { NixOS.</para> </listitem> + <listitem> + <para>Input method support was improved. New NixOS modules (fcitx, nabi and uim), + fcitx engines (chewing, hangul, m17n, mozc and table-other) and ibus engines (hangul and m17n) + have been added.</para> + </listitem> + </itemizedlist></para> </section> diff --git a/nixos/lib/make-iso9660-image.nix b/nixos/lib/make-iso9660-image.nix index b2409c6006b..21c9cca316d 100644 --- a/nixos/lib/make-iso9660-image.nix +++ b/nixos/lib/make-iso9660-image.nix @@ -22,7 +22,7 @@ , # 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). +, # Whether 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. diff --git a/nixos/modules/config/gtk-exe-env.nix b/nixos/modules/config/gtk-exe-env.nix deleted file mode 100644 index b565072e3a7..00000000000 --- a/nixos/modules/config/gtk-exe-env.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ config, pkgs, lib, ... }: - -{ - imports = [ - ]; - - options = { - gtkPlugins = lib.mkOption { - type = lib.types.listOf lib.types.path; - default = []; - description = '' - Plugin packages for GTK+ such as input methods. - ''; - }; - }; - - config = { - environment.variables = if builtins.length config.gtkPlugins > 0 - then - let - paths = [ pkgs.gtk2 pkgs.gtk3 ] ++ config.gtkPlugins; - env = pkgs.buildEnv { - name = "gtk-exe-env"; - - inherit paths; - - postBuild = lib.concatStringsSep "\n" - (map (d: d.gtkExeEnvPostBuild or "") paths); - - ignoreCollisions = true; - }; - in { - GTK_EXE_PREFIX = builtins.toString env; - GTK_PATH = [ - "${env}/lib/gtk-2.0" - "${env}/lib/gtk-3.0" - ]; - } - else {}; - }; -} diff --git a/nixos/modules/config/qt-plugin-env.nix b/nixos/modules/config/qt-plugin-env.nix deleted file mode 100644 index c5986560416..00000000000 --- a/nixos/modules/config/qt-plugin-env.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ config, pkgs, lib, ... }: - -{ - imports = [ - ]; - - options = { - qtPlugins = lib.mkOption { - type = lib.types.listOf lib.types.path; - default = []; - description = '' - Plugin packages for Qt such as input methods. - ''; - }; - }; - - config = { - environment.variables = if builtins.length config.qtPlugins > 0 - then - let - paths = [ pkgs.qt48 ] ++ config.qtPlugins; - env = pkgs.buildEnv { - name = "qt-plugin-env"; - - inherit paths; - - postBuild = lib.concatStringsSep "\n" - (map (d: d.qtPluginEnvPostBuild or "") paths); - - ignoreCollisions = true; - }; - in { - QT_PLUGIN_PATH = [ (builtins.toString env) ]; - } - else {}; - }; -} diff --git a/nixos/modules/config/vpnc.nix b/nixos/modules/config/vpnc.nix index 68d755232eb..c7ac1b3530e 100644 --- a/nixos/modules/config/vpnc.nix +++ b/nixos/modules/config/vpnc.nix @@ -17,16 +17,16 @@ in services = mkOption { type = types.attrsOf types.str; default = {}; - example = { - test = - '' - IPSec gateway 192.168.1.1 - IPSec ID someID - IPSec secret secretKey - Xauth username name - Xauth password pass - ''; - }; + example = literalExample '' + { test = ''' + IPSec gateway 192.168.1.1 + IPSec ID someID + IPSec secret secretKey + Xauth username name + Xauth password pass + '''; + } + ''; description = '' The names of cisco VPNs and their associated definitions diff --git a/nixos/modules/hardware/all-firmware.nix b/nixos/modules/hardware/all-firmware.nix index 1a04baef193..d0d481f72a4 100644 --- a/nixos/modules/hardware/all-firmware.nix +++ b/nixos/modules/hardware/all-firmware.nix @@ -22,7 +22,7 @@ with lib; ###### implementation config = mkIf config.hardware.enableAllFirmware { - hardware.firmware = [ pkgs.firmwareLinuxNonfree ]; + hardware.firmware = [ pkgs.firmwareLinuxNonfree pkgs.intel2200BGFirmware ]; }; } diff --git a/nixos/modules/hardware/network/intel-2200bg.nix b/nixos/modules/hardware/network/intel-2200bg.nix index 1b70057d135..17b973474c9 100644 --- a/nixos/modules/hardware/network/intel-2200bg.nix +++ b/nixos/modules/hardware/network/intel-2200bg.nix @@ -23,7 +23,7 @@ config = lib.mkIf config.networking.enableIntel2200BGFirmware { - hardware.enableAllFirmware = true; + hardware.firmware = [ pkgs.intel2200BGFirmware ]; }; diff --git a/nixos/modules/i18n/inputMethod/default.nix b/nixos/modules/i18n/inputMethod/default.nix new file mode 100644 index 00000000000..7e6a25bfb08 --- /dev/null +++ b/nixos/modules/i18n/inputMethod/default.nix @@ -0,0 +1,29 @@ +{ config, pkgs, lib, ... }: + +with lib; + +{ + options = { + i18n.inputMethod = { + enabled = mkOption { + type = types.nullOr (types.enum [ "ibus" "fcitx" "nabi" "uim" ]); + default = null; + example = "fcitx"; + description = '' + Select the enabled input method. Input methods is a software to input symbols that are not available on standard input devices. + + Input methods are specially used to input Chinese, Japanese and Korean characters. + + Currently the following input methods are available in NixOS: + + <itemizedlist> + <listitem><para>ibus: The intelligent input bus, extra input engines can be added using <literal>i18n.inputMethod.ibus.engines</literal>.</para></listitem> + <listitem><para>fcitx: A customizable lightweight input method, extra input engines can be added using <literal>i18n.inputMethod.fcitx.engines</literal>.</para></listitem> + <listitem><para>nabi: A Korean input method based on XIM. Nabi doesn't support Qt 5.</para></listitem> + <listitem><para>uim: The universal input method, is a library with a XIM bridge. uim mainly support Chinese, Japanese and Korean.</para></listitem> + </itemizedlist> + ''; + }; + }; + }; +} diff --git a/nixos/modules/i18n/inputMethod/fcitx.nix b/nixos/modules/i18n/inputMethod/fcitx.nix new file mode 100644 index 00000000000..8e31743504f --- /dev/null +++ b/nixos/modules/i18n/inputMethod/fcitx.nix @@ -0,0 +1,44 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.i18n.inputMethod.fcitx; + fcitxPackage = pkgs.fcitx-with-plugins.override { plugins = cfg.engines; }; + fcitxEngine = types.package // { + name = "fcitx-engine"; + check = x: (lib.types.package.check x) && (attrByPath ["meta" "isFcitxEngine"] false x); + }; +in +{ + options = { + + i18n.inputMethod.fcitx = { + engines = mkOption { + type = with types; listOf fcitxEngine; + default = []; + example = literalExample "with pkgs.fcitx-engines; [ mozc hangul ]"; + description = + let + engines = + lib.concatStringsSep ", " + (map (name: "<literal>${name}</literal>") + (lib.attrNames pkgs.fcitx-engines)); + in + "Enabled Fcitx engines. Available engines are: ${engines}."; + }; + }; + + }; + + config = mkIf (config.i18n.inputMethod.enabled == "fcitx") { + environment.systemPackages = [ fcitxPackage ]; + + environment.variables = { + GTK_IM_MODULE = "fcitx"; + QT_IM_MODULE = "fcitx"; + XMODIFIERS = "@im=fcitx"; + }; + services.xserver.displayManager.sessionCommands = "${fcitxPackage}/bin/fcitx"; + }; +} diff --git a/nixos/modules/i18n/inputMethod/ibus.nix b/nixos/modules/i18n/inputMethod/ibus.nix new file mode 100644 index 00000000000..bb80f43634d --- /dev/null +++ b/nixos/modules/i18n/inputMethod/ibus.nix @@ -0,0 +1,55 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.i18n.inputMethod.ibus; + ibusPackage = pkgs.ibus-with-plugins.override { plugins = cfg.engines; }; + ibusEngine = types.package // { + name = "ibus-engine"; + check = x: (lib.types.package.check x) && (attrByPath ["meta" "isIbusEngine"] false x); + }; + + ibusAutostart = pkgs.writeTextFile { + name = "autostart-ibus-daemon"; + destination = "/etc/xdg/autostart/ibus-daemon.desktop"; + text = '' + [Desktop Entry] + Name=IBus + Type=Application + Exec=${ibusPackage}/bin/ibus-daemon --daemonize --xim --cache=refresh + ''; + }; +in +{ + options = { + i18n.inputMethod.ibus = { + engines = mkOption { + type = with types; listOf ibusEngine; + default = []; + example = literalExample "with pkgs.ibus-engines; [ mozc hangul ]"; + description = + let + engines = + lib.concatStringsSep ", " + (map (name: "<literal>${name}</literal>") + (lib.attrNames pkgs.ibus-engines)); + in + "Enabled IBus engines. Available engines are: ${engines}."; + }; + }; + }; + + config = mkIf (config.i18n.inputMethod.enabled == "ibus") { + # Without dconf enabled it is impossible to use IBus + environment.systemPackages = with pkgs; [ + ibusPackage ibus-qt gnome3.dconf ibusAutostart + ]; + + environment.variables = { + GTK_IM_MODULE = "ibus"; + QT_IM_MODULE = "ibus"; + XMODIFIERS = "@im=ibus"; + }; + }; +} diff --git a/nixos/modules/i18n/inputMethod/nabi.nix b/nixos/modules/i18n/inputMethod/nabi.nix new file mode 100644 index 00000000000..c6708365eff --- /dev/null +++ b/nixos/modules/i18n/inputMethod/nabi.nix @@ -0,0 +1,16 @@ +{ config, pkgs, lib, ... }: + +with lib; +{ + config = mkIf (config.i18n.inputMethod.enabled == "nabi") { + environment.systemPackages = [ pkgs.nabi ]; + + environment.variables = { + GTK_IM_MODULE = "nabi"; + QT_IM_MODULE = "nabi"; + XMODIFIERS = "@im=nabi"; + }; + + services.xserver.displayManager.sessionCommands = "${pkgs.nabi}/bin/nabi &"; + }; +} diff --git a/nixos/modules/i18n/inputMethod/uim.nix b/nixos/modules/i18n/inputMethod/uim.nix new file mode 100644 index 00000000000..f8a3e560656 --- /dev/null +++ b/nixos/modules/i18n/inputMethod/uim.nix @@ -0,0 +1,37 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.i18n.inputMethod.uim; +in +{ + options = { + + i18n.inputMethod.uim = { + toolbar = mkOption { + type = types.enum [ "gtk" "gtk3" "gtk-systray" "gtk3-systray" "qt4" ]; + default = "gtk"; + example = "gtk-systray"; + description = '' + selected UIM toolbar. + ''; + }; + }; + + }; + + config = mkIf (config.i18n.inputMethod.enabled == "uim") { + environment.systemPackages = [ pkgs.uim ]; + + environment.variables = { + GTK_IM_MODULE = "uim"; + QT_IM_MODULE = "uim"; + XMODIFIERS = "@im=uim"; + }; + services.xserver.displayManager.sessionCommands = '' + ${pkgs.uim}/bin/uim-xim & + ${pkgs.uim}/bin/uim-toolbar-${cfg.toolbar} & + ''; + }; +} diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix new file mode 100644 index 00000000000..5725938465f --- /dev/null +++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix @@ -0,0 +1,78 @@ +# This module defines a NixOS installation CD that contains X11 and +# GNOME 3. + +{ config, lib, pkgs, ... }: + +with lib; + +{ + imports = [ ./installation-cd-base.nix ]; + + services.xserver = { + enable = true; + # GDM doesn't start in virtual machines with ISO + displayManager.slim = { + enable = true; + defaultUser = "root"; + autoLogin = true; + }; + desktopManager.gnome3 = { + enable = true; + extraGSettingsOverrides = '' + [org.gnome.desktop.background] + show-desktop-icons=true + + [org.gnome.nautilus.desktop] + trash-icon-visible=false + volumes-visible=false + home-icon-visible=false + network-icon-visible=false + ''; + + extraGSettingsOverridePackages = [ pkgs.gnome3.nautilus ]; + }; + }; + + environment.systemPackages = + [ # Include gparted for partitioning disks. + pkgs.gparted + + # Include some editors. + pkgs.vim + pkgs.bvi # binary editor + pkgs.joe + + pkgs.glxinfo + ]; + + # Don't start the X server by default. + services.xserver.autorun = mkForce false; + + # Auto-login as root. + services.xserver.displayManager.gdm.autoLogin = { + enable = true; + user = "root"; + }; + + system.activationScripts.installerDesktop = let + # Must be executable + desktopFile = pkgs.writeScript "nixos-manual.desktop" '' + [Desktop Entry] + Version=1.0 + Type=Link + Name=NixOS Manual + URL=${config.system.build.manual.manual}/share/doc/nixos/index.html + Icon=system-help + ''; + + # use cp and chmod +x, we must be sure the apps are in the nix store though + in '' + mkdir -p /root/Desktop + ln -sfT ${desktopFile} /root/Desktop/nixos-manual.desktop + cp ${pkgs.gnome3.gnome_terminal}/share/applications/gnome-terminal.desktop /root/Desktop/gnome-terminal.desktop + chmod a+rx /root/Desktop/gnome-terminal.desktop + cp ${pkgs.gparted}/share/applications/gparted.desktop /root/Desktop/gparted.desktop + chmod a+rx /root/Desktop/gparted.desktop + ''; + +} diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-new-kernel.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde-new-kernel.nix index 506b9292b01..a4bcd7079a4 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-new-kernel.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde-new-kernel.nix @@ -1,7 +1,7 @@ { config, pkgs, ... }: { - imports = [ ./installation-cd-graphical.nix ]; + imports = [ ./installation-cd-graphical-kde.nix ]; boot.kernelPackages = pkgs.linuxPackages_latest; } diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix index d14768bc107..d14768bc107 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-graphical.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix diff --git a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix index 15e22fb50d4..957a8ff9ce6 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix @@ -23,7 +23,7 @@ in boot.loader.generic-extlinux-compatible.enable = true; boot.kernelPackages = pkgs.linuxPackages_latest; - boot.kernelParams = ["console=ttyS0,115200n8" "console=ttyAMA0,115200n8" "console=tty0"]; + boot.kernelParams = ["console=ttyS0,115200n8" "console=ttymxc0,115200n8" "console=ttyAMA0,115200n8" "console=tty0"]; # FIXME: this probably should be in installation-device.nix users.extraUsers.root.initialHashedPassword = ""; diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix index 12b4f304561..9eba542d8c9 100644 --- a/nixos/modules/installer/cd-dvd/sd-image.nix +++ b/nixos/modules/installer/cd-dvd/sd-image.nix @@ -30,7 +30,7 @@ in bootSize = mkOption { type = types.int; - default = 128; + default = 120; description = '' Size of the /boot partition, in megabytes. ''; @@ -66,10 +66,10 @@ in buildInputs = with pkgs; [ dosfstools e2fsprogs mtools libfaketime utillinux ]; buildCommand = '' - # Create the image file sized to fit /boot and /, plus 4M of slack + # Create the image file sized to fit /boot and /, plus 20M of slack rootSizeBlocks=$(du -B 512 --apparent-size ${rootfsImage} | awk '{ print $1 }') bootSizeBlocks=$((${toString config.sdImage.bootSize} * 1024 * 1024 / 512)) - imageSize=$((rootSizeBlocks * 512 + bootSizeBlocks * 512 + 4096 * 1024)) + imageSize=$((rootSizeBlocks * 512 + bootSizeBlocks * 512 + 20 * 1024 * 1024)) truncate -s $imageSize $out # type=b is 'W95 FAT32', type=83 is 'Linux'. @@ -77,8 +77,8 @@ in label: dos label-id: 0x2178694e - start=1M, size=$bootSizeBlocks, type=b, bootable - type=83 + start=8M, size=$bootSizeBlocks, type=b, bootable + start=${toString (8 + config.sdImage.bootSize)}M, type=83 EOF # Copy the rootfs into the SD image diff --git a/nixos/modules/installer/tools/auto-upgrade.nix b/nixos/modules/installer/tools/auto-upgrade.nix index ca51de0fb8c..79ccb5c3d18 100644 --- a/nixos/modules/installer/tools/auto-upgrade.nix +++ b/nixos/modules/installer/tools/auto-upgrade.nix @@ -74,7 +74,7 @@ let cfg = config.system.autoUpgrade; in serviceConfig.Type = "oneshot"; environment = config.nix.envVars // - { inherit (config.environment.sessionVariables) NIX_PATH SSL_CERT_FILE; + { inherit (config.environment.sessionVariables) NIX_PATH; HOME = "/root"; }; diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 064b4cbc4b3..0ab2b8a76fc 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -248,6 +248,12 @@ matrix-synapse = 224; rspamd = 225; rmilter = 226; + cfdyndns = 227; + gammu-smsd = 228; + pdnsd = 229; + octoprint = 230; + avahi-autoipd = 231; + nntp-proxy = 232; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -473,6 +479,9 @@ matrix-synapse = 224; rspamd = 225; rmilter = 226; + cfdyndns = 227; + pdnsd = 229; + octoprint = 230; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/misc/locate.nix b/nixos/modules/misc/locate.nix index 318b81ca07c..5b560cedc62 100644 --- a/nixos/modules/misc/locate.nix +++ b/nixos/modules/misc/locate.nix @@ -67,7 +67,9 @@ in { }; config = { - warnings = let opt = options.services.locate.period; in optional opt.isDefined "The `period` definition in ${showFiles opt.files} has been removed; please replace it with `interval`, using the new systemd.time interval specifier."; + warnings = + let opt = options.services.locate.period; in + optional opt.isDefined "The ‘services.locate.period’ option in ${showFiles opt.files} has been removed; please replace it with ‘services.locate.interval’, using the systemd.time(7) calendar event format."; systemd.services.update-locatedb = { description = "Update Locate Database"; diff --git a/nixos/modules/misc/nixos.nix b/nixos/modules/misc/nixos.nix deleted file mode 100644 index 84365b640a4..00000000000 --- a/nixos/modules/misc/nixos.nix +++ /dev/null @@ -1,82 +0,0 @@ -{ config, options, lib, ... }: - -# This modules is used to inject a different NixOS version as well as its -# argument such that one can pin a specific version with the versionning -# system of the configuration. -let - nixosReentry = import config.nixos.path { - inherit (config.nixos) configuration extraModules; - inherit (config.nixpkgs) system; - reEnter = true; - }; -in - -with lib; - -{ - options = { - nixos.path = mkOption { - default = null; - example = literalExample "./nixpkgs-15.09/nixos"; - type = types.nullOr types.path; - description = '' - This option give the ability to evaluate the current set of modules - with a different version of NixOS. This option can be used version - the version of NixOS with the configuration without relying on the - <literal>NIX_PATH</literal> environment variable. - ''; - }; - - nixos.system = mkOption { - example = "i686-linux"; - type = types.uniq types.str; - description = '' - Name of the system used to compile NixOS. - ''; - }; - - nixos.extraModules = mkOption { - default = []; - example = literalExample "[ ./sshd-config.nix ]"; - type = types.listOf (types.either (types.submodule ({...}:{options={};})) types.path); - description = '' - Define additional modules which would be loaded to evaluate the - configuration. - ''; - }; - - nixos.configuration = mkOption { - type = types.unspecified; - internal = true; - description = '' - Option used by <filename>nixos/default.nix</filename> to re-inject - the same configuration module as the one used for the current - execution. - ''; - }; - - nixos.reflect = mkOption { - default = { inherit config options; }; - type = types.unspecified; - internal = true; - description = '' - Provides <literal>config</literal> and <literal>options</literal> - computed by the module system and given as argument to all - modules. These are used for introspection of options and - configuration by tools such as <literal>nixos-option</literal>. - ''; - }; - }; - - config = mkMerge [ - (mkIf (config.nixos.path != null) (mkForce { - system.build.toplevel = nixosReentry.system; - system.build.vm = nixosReentry.vm; - nixos.reflect = { inherit (nixosReentry) config options; }; - })) - - { meta.maintainers = singleton lib.maintainers.pierron; - meta.doc = ./nixos.xml; - } - ]; -} diff --git a/nixos/modules/misc/nixos.xml b/nixos/modules/misc/nixos.xml deleted file mode 100644 index 064bdd80b3c..00000000000 --- a/nixos/modules/misc/nixos.xml +++ /dev/null @@ -1,84 +0,0 @@ -<chapter xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:xi="http://www.w3.org/2001/XInclude" - version="5.0" - xml:id="module-misc-nixos"> - -<title>NixOS Reentry</title> - -<!-- FIXME: render nicely --> - -<!-- FIXME: source can be added automatically --> -<para><emphasis>Source:</emphasis> <filename>modules/misc/nixos.nix</filename></para> - -<!-- FIXME: more stuff, like maintainer? --> - -<para>NixOS reentry can be used for both pinning the evaluation to a -specific version of NixOS, and to dynamically add additional modules into -the Module evaluation.</para> - -<section><title>NixOS Version Pinning</title> - -<para>To pin a specific version of NixOS, you need a version that you can -either clone localy, or that you can fetch remotely.</para> - -<para>If you already have a cloned version of NixOS in the directory -<filename>/etc/nixos/nixpkgs-16-03</filename>, then you can specify the -<option>nixos.path</option> with either the path or the relative path of -your NixOS clone. For example, you can add the following to your -<filename>/etc/nixos/configuration.nix</filename> file: - -<programlisting> -nixos.path = ./nixpkgs-16-03/nixos; -</programlisting> -</para> - -<para>Another option is to fetch a specific version of NixOS, with either -the <literal>fetchTarball</literal> builtin, or the -<literal>pkgs.fetchFromGitHub</literal> function and use the result as an -input. - -<programlisting> -nixos.path = "${builtins.fetchTarball https://github.com/NixOS/nixpkgs/archive/1f27976e03c15183191d1b4aa1a40d1f14666cd2.tar.gz}/nixos"; -</programlisting> -</para> - -</section> - - -<section><title>Adding Module Dynamically</title> - -<para>To add additional module, the recommended way is to use statically -known modules in the list of imported arguments as described in <xref -linkend="sec-modularity" />. Unfortunately, this recommended method has -limitation, such that the list of imported files cannot be selected based on -the content of the configuration. - -Fortunately, NixOS reentry system can be used as an alternative to register -new imported modules based on the content of the configuration. To do so, -one should define both <option>nixos.path</option> and -<option>nixos.extraModules</option> options. - -<programlisting> -nixos.path = <nixos>; -nixos.extraModules = - if config.networking.hostName == "server" then - [ ./server.nix ] else [ ./client.nix ]; -</programlisting> - -Also note, that the above can be reimplemented in a different way which is -not as expensive, by using <literal>mkIf</literal> at the top each -configuration if both modules are present on the file system (see <xref -linkend="sec-option-definitions" />) and by always inmporting both -modules.</para> - -</section> - -<section><title>Options</title> - -<para>FIXME: auto-generated list of module options.</para> - -</section> - - -</chapter> diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 0011544988d..0105cc3cdf2 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -7,7 +7,6 @@ ./config/fonts/fonts.nix ./config/fonts/ghostscript.nix ./config/gnu.nix - ./config/gtk-exe-env.nix ./config/i18n.nix ./config/krb5.nix ./config/ldap.nix @@ -16,7 +15,6 @@ ./config/nsswitch.nix ./config/power-management.nix ./config/pulseaudio.nix - ./config/qt-plugin-env.nix ./config/shells-environment.nix ./config/swap.nix ./config/sysctl.nix @@ -43,6 +41,11 @@ ./hardware/video/nvidia.nix ./hardware/video/ati.nix ./hardware/video/webcam/facetimehd.nix + ./i18n/inputMethod/default.nix + ./i18n/inputMethod/fcitx.nix + ./i18n/inputMethod/ibus.nix + ./i18n/inputMethod/nabi.nix + ./i18n/inputMethod/uim.nix ./installer/tools/auto-upgrade.nix ./installer/tools/nixos-checkout.nix ./installer/tools/tools.nix @@ -53,7 +56,6 @@ ./misc/lib.nix ./misc/locate.nix ./misc/meta.nix - ./misc/nixos.nix ./misc/nixpkgs.nix ./misc/passthru.nix ./misc/version.nix @@ -66,7 +68,6 @@ ./programs/environment.nix ./programs/freetds.nix ./programs/fish.nix - ./programs/ibus.nix ./programs/kbdlight.nix ./programs/light.nix ./programs/man.nix @@ -76,7 +77,6 @@ ./programs/shell.nix ./programs/ssh.nix ./programs/ssmtp.nix - ./programs/uim.nix ./programs/venus.nix ./programs/wvdial.nix ./programs/xfs_quota.nix @@ -89,6 +89,7 @@ ./security/ca.nix ./security/duosec.nix ./security/grsecurity.nix + ./security/oath.nix ./security/pam.nix ./security/pam_usb.nix ./security/pam_mount.nix @@ -201,6 +202,7 @@ ./services/misc/bepasty.nix ./services/misc/canto-daemon.nix ./services/misc/calibre-server.nix + ./services/misc/cfdyndns.nix ./services/misc/cpuminer-cryptonight.nix ./services/misc/cgminer.nix ./services/misc/confd.nix @@ -211,6 +213,7 @@ ./services/misc/etcd.nix ./services/misc/felix.nix ./services/misc/folding-at-home.nix + ./services/misc/gammu-smsd.nix #./services/misc/gitit.nix ./services/misc/gitlab.nix ./services/misc/gitolite.nix @@ -227,6 +230,7 @@ ./services/misc/nix-gc.nix ./services/misc/nixos-manual.nix ./services/misc/nix-ssh-serve.nix + ./services/misc/octoprint.nix ./services/misc/parsoid.nix ./services/misc/phd.nix ./services/misc/plex.nix @@ -236,6 +240,7 @@ ./services/misc/ripple-data-api.nix ./services/misc/rogue.nix ./services/misc/siproxd.nix + ./services/misc/spice-vdagentd.nix ./services/misc/subsonic.nix ./services/misc/sundtek.nix ./services/misc/svnserve.nix @@ -250,6 +255,7 @@ ./services/monitoring/dd-agent.nix ./services/monitoring/grafana.nix ./services/monitoring/graphite.nix + ./services/monitoring/hdaps.nix ./services/monitoring/heapster.nix ./services/monitoring/longview.nix ./services/monitoring/monit.nix @@ -268,6 +274,7 @@ ./services/monitoring/zabbix-agent.nix ./services/monitoring/zabbix-server.nix ./services/network-filesystems/drbd.nix + ./services/network-filesystems/netatalk.nix ./services/network-filesystems/nfsd.nix ./services/network-filesystems/openafs-client/default.nix ./services/network-filesystems/rsyncd.nix @@ -316,11 +323,11 @@ ./services/networking/hostapd.nix ./services/networking/i2pd.nix ./services/networking/i2p.nix - ./services/networking/ifplugd.nix ./services/networking/iodined.nix ./services/networking/ircd-hybrid/default.nix ./services/networking/kippo.nix ./services/networking/lambdabot.nix + ./services/networking/libreswan.nix ./services/networking/mailpile.nix ./services/networking/minidlna.nix ./services/networking/miniupnpd.nix @@ -331,6 +338,7 @@ ./services/networking/networkmanager.nix ./services/networking/ngircd.nix ./services/networking/nix-serve.nix + ./services/networking/nntp-proxy.nix ./services/networking/nsd.nix ./services/networking/ntopng.nix ./services/networking/ntpd.nix @@ -340,6 +348,7 @@ ./services/networking/openntpd.nix ./services/networking/openvpn.nix ./services/networking/ostinato.nix + ./services/networking/pdnsd.nix ./services/networking/polipo.nix ./services/networking/prayer.nix ./services/networking/privoxy.nix @@ -439,6 +448,7 @@ ./services/x11/display-managers/lightdm.nix ./services/x11/display-managers/sddm.nix ./services/x11/display-managers/slim.nix + ./services/x11/hardware/libinput.nix ./services/x11/hardware/multitouch.nix ./services/x11/hardware/synaptics.nix ./services/x11/hardware/wacom.nix diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix index 20a1f7f1ed8..66b5765a895 100644 --- a/nixos/modules/profiles/base.nix +++ b/nixos/modules/profiles/base.nix @@ -17,6 +17,7 @@ pkgs.ddrescue pkgs.ccrypt pkgs.cryptsetup # needed for dm-crypt volumes + pkgs.which # 88K size # Some networking tools. pkgs.fuse diff --git a/nixos/modules/profiles/qemu-guest.nix b/nixos/modules/profiles/qemu-guest.nix index 759fdb7f8e5..987eb051b98 100644 --- a/nixos/modules/profiles/qemu-guest.nix +++ b/nixos/modules/profiles/qemu-guest.nix @@ -14,4 +14,6 @@ # to the *boot time* of the host). hwclock -s ''; + + security.rngd.enable = false; } diff --git a/nixos/modules/programs/bash/bash.nix b/nixos/modules/programs/bash/bash.nix index 1c3c07a1c21..e4e264ec003 100644 --- a/nixos/modules/programs/bash/bash.nix +++ b/nixos/modules/programs/bash/bash.nix @@ -56,7 +56,7 @@ in */ shellAliases = mkOption { - default = config.environment.shellAliases // { which = "type -P"; }; + default = config.environment.shellAliases; description = '' Set of aliases for bash shell. See <option>environment.shellAliases</option> for an option format description. diff --git a/nixos/modules/programs/freetds.nix b/nixos/modules/programs/freetds.nix index 398fd104363..e0860a242b7 100644 --- a/nixos/modules/programs/freetds.nix +++ b/nixos/modules/programs/freetds.nix @@ -17,14 +17,14 @@ in environment.freetds = mkOption { type = types.attrsOf types.str; default = {}; - example = { - MYDATABASE = - '' - host = 10.0.2.100 - port = 1433 - tds version = 7.2 - ''; - }; + example = literalExample '' + { MYDATABASE = ''' + host = 10.0.2.100 + port = 1433 + tds version = 7.2 + '''; + } + ''; description = '' Configure freetds database entries. Each attribute denotes diff --git a/nixos/modules/programs/ibus.nix b/nixos/modules/programs/ibus.nix deleted file mode 100644 index a42753a292b..00000000000 --- a/nixos/modules/programs/ibus.nix +++ /dev/null @@ -1,51 +0,0 @@ -{ 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 pkgs.gnome3.dconf ]; - - 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/ssh.nix b/nixos/modules/programs/ssh.nix index 169c6a38e75..1ad45f46803 100644 --- a/nixos/modules/programs/ssh.nix +++ b/nixos/modules/programs/ssh.nix @@ -36,6 +36,7 @@ in askPassword = mkOption { type = types.str; + default = "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass"; description = ''Program used by SSH to ask for passwords.''; }; @@ -226,7 +227,5 @@ in environment.variables.SSH_ASKPASS = optionalString config.services.xserver.enable askPassword; - programs.ssh.askPassword = mkDefault "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass"; - }; } diff --git a/nixos/modules/programs/uim.nix b/nixos/modules/programs/uim.nix deleted file mode 100644 index 4bf2f9a1757..00000000000 --- a/nixos/modules/programs/uim.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -let - cfg = config.uim; -in -{ - options = { - - uim = { - enable = mkOption { - type = types.bool; - default = false; - example = true; - description = "Enable UIM input method"; - }; - }; - - }; - - config = mkIf cfg.enable { - environment.systemPackages = [ pkgs.uim ]; - gtkPlugins = [ pkgs.uim ]; - qtPlugins = [ pkgs.uim ]; - environment.variables.GTK_IM_MODULE = "uim"; - environment.variables.QT_IM_MODULE = "uim"; - environment.variables.XMODIFIERS = "@im=uim"; - services.xserver.displayManager.sessionCommands = "uim-xim &"; - }; -} diff --git a/nixos/modules/programs/venus.nix b/nixos/modules/programs/venus.nix index c3756b4838c..731ebed14c7 100644 --- a/nixos/modules/programs/venus.nix +++ b/nixos/modules/programs/venus.nix @@ -99,6 +99,7 @@ in }; outputTheme = mkOption { + default = "${pkgs.venus}/themes/classic_fancy"; type = types.path; description = '' Directory containing a config.ini file which is merged with this one. @@ -165,11 +166,8 @@ in script = "exec venus-planet ${configFile}"; serviceConfig.User = "${cfg.user}"; serviceConfig.Group = "${cfg.group}"; - environment.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; startAt = cfg.dates; }; - services.venus.outputTheme = mkDefault "${pkgs.venus}/themes/classic_fancy"; - }; } diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 6e10b47f03c..85435884b19 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -28,6 +28,9 @@ with lib; (mkRenamedOptionModule [ "services" "subsonic" "host" ] [ "services" "subsonic" "listenAddress" ]) (mkRenamedOptionModule [ "jobs" ] [ "systemd" "services" ]) + (mkRenamedOptionModule [ "services" "gitlab" "stateDir" ] [ "services" "gitlab" "statePath" ]) + (mkRemovedOptionModule [ "services" "gitlab" "satelliteDir" ]) + # Old Grub-related options. (mkRenamedOptionModule [ "boot" "initrd" "extraKernelModules" ] [ "boot" "initrd" "kernelModules" ]) (mkRenamedOptionModule [ "boot" "extraKernelParams" ] [ "boot" "kernelParams" ]) @@ -59,6 +62,9 @@ with lib; # Tarsnap (mkRenamedOptionModule [ "services" "tarsnap" "config" ] [ "services" "tarsnap" "archives" ]) + # ibus + (mkRenamedOptionModule [ "programs" "ibus" "plugins" ] [ "i18n" "inputMethod" "ibus" "engines" ]) + # proxy (mkRenamedOptionModule [ "nix" "proxy" ] [ "networking" "proxy" "default" ]) diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix index 3d25e811e67..c5cd0fb60ee 100644 --- a/nixos/modules/security/acme.nix +++ b/nixos/modules/security/acme.nix @@ -56,7 +56,7 @@ let plugins = mkOption { type = types.listOf (types.enum [ - "cert.der" "cert.pem" "chain.pem" "external_pem.sh" + "cert.der" "cert.pem" "chain.pem" "external.sh" "fullchain.pem" "full.pem" "key.der" "key.pem" "account_key.json" ]); default = [ "fullchain.pem" "key.pem" "account_key.json" ]; diff --git a/nixos/modules/security/ca.nix b/nixos/modules/security/ca.nix index 98d73ed2542..849530238e7 100644 --- a/nixos/modules/security/ca.nix +++ b/nixos/modules/security/ca.nix @@ -35,14 +35,17 @@ in security.pki.certificates = mkOption { type = types.listOf types.str; default = []; - example = singleton '' - NixOS.org - ========= - -----BEGIN CERTIFICATE----- - MIIGUDCCBTigAwIBAgIDD8KWMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ - TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0 - ... - -----END CERTIFICATE----- + example = literalExample '' + [ ''' + NixOS.org + ========= + -----BEGIN CERTIFICATE----- + MIIGUDCCBTigAwIBAgIDD8KWMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ + TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0 + ... + -----END CERTIFICATE----- + ''' + ] ''; description = '' A list of trusted root certificates in PEM format. @@ -64,12 +67,6 @@ in # CentOS/Fedora compatibility. environment.etc."pki/tls/certs/ca-bundle.crt".source = caCertificates; - environment.sessionVariables = - { SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; - # FIXME: unneeded - remove eventually. - GIT_SSL_CAINFO = "/etc/ssl/certs/ca-certificates.crt"; - }; - }; } diff --git a/nixos/modules/security/oath.nix b/nixos/modules/security/oath.nix new file mode 100644 index 00000000000..20f3e2dd9f8 --- /dev/null +++ b/nixos/modules/security/oath.nix @@ -0,0 +1,50 @@ +# This module provides configuration for the OATH PAM modules. + +{ config, lib, pkgs, ... }: + +with lib; + +{ + options = { + + security.pam.oath = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable the OATH (one-time password) PAM module. + ''; + }; + + digits = mkOption { + type = types.enum [ 6 7 8 ]; + default = 6; + description = '' + Specify the length of the one-time password in number of + digits. + ''; + }; + + window = mkOption { + type = types.int; + default = 5; + description = '' + Specify the number of one-time passwords to check in order + to accommodate for situations where the system and the + client are slightly out of sync (iteration for HOTP or time + steps for TOTP). + ''; + }; + + usersFile = mkOption { + type = types.path; + default = "/etc/users.oath"; + description = '' + Set the path to file where the user's credentials are + stored. This file must not be world readable! + ''; + }; + }; + + }; +} diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 2ee8a803d2f..021c561af75 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -75,7 +75,7 @@ let }; oathAuth = mkOption { - default = config.security.pam.enableOATH; + default = config.security.pam.oath.enable; type = types.bool; description = '' If set, the OATH Toolkit will be used. @@ -259,8 +259,8 @@ let "auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth try_first_pass"} ${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"} + ${let oath = config.security.pam.oath; in optionalString cfg.oathAuth + "auth sufficient ${pkgs.oathToolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}"} ${optionalString config.users.ldap.enable "auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass"} ${optionalString config.krb5.enable '' @@ -302,8 +302,6 @@ let "session optional ${pam_krb5}/lib/security/pam_krb5.so"} ${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"} ${optionalString cfg.startSession "session optional ${pkgs.systemd}/lib/security/pam_systemd.so"} ${optionalString cfg.forwardXAuth @@ -405,13 +403,6 @@ in ''; }; - security.pam.enableOATH = mkOption { - default = false; - description = '' - Enable the OATH (one-time password) PAM module. - ''; - }; - security.pam.enableU2F = mkOption { default = false; description = '' @@ -446,7 +437,7 @@ 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.oath.enable [ pkgs.oathToolkit ] ++ optionals config.security.pam.enableU2F [ pkgs.pam_u2f ] ++ optionals config.security.pam.enableEcryptfs [ pkgs.ecryptfs ]; diff --git a/nixos/modules/services/amqp/activemq/default.nix b/nixos/modules/services/amqp/activemq/default.nix index 56ff388f8a9..261f9761766 100644 --- a/nixos/modules/services/amqp/activemq/default.nix +++ b/nixos/modules/services/amqp/activemq/default.nix @@ -32,6 +32,7 @@ in { ''; }; configurationDir = mkOption { + default = "${activemq}/conf"; description = '' The base directory for ActiveMQ's configuration. By default, this directory is searched for a file named activemq.xml, @@ -125,8 +126,6 @@ in { ''; }; - services.activemq.configurationDir = mkDefault "${activemq}/conf"; - }; } diff --git a/nixos/modules/services/computing/slurm/slurm.nix b/nixos/modules/services/computing/slurm/slurm.nix index cf00d894655..ad8836f4009 100644 --- a/nixos/modules/services/computing/slurm/slurm.nix +++ b/nixos/modules/services/computing/slurm/slurm.nix @@ -37,6 +37,7 @@ in package = mkOption { type = types.package; default = pkgs.slurm-llnl; + defaultText = "pkgs.slurm-llnl"; example = literalExample "pkgs.slurm-llnl-full"; description = '' The packge to use for slurm binaries. diff --git a/nixos/modules/services/continuous-integration/jenkins/default.nix b/nixos/modules/services/continuous-integration/jenkins/default.nix index fb77586f689..6fd39e68b1d 100644 --- a/nixos/modules/services/continuous-integration/jenkins/default.nix +++ b/nixos/modules/services/continuous-integration/jenkins/default.nix @@ -92,11 +92,12 @@ in { type = with types; attrsOf str; description = '' Additional environment variables to be passed to the jenkins process. - As a base environment, jenkins receives NIX_PATH, SSL_CERT_FILE and - GIT_SSL_CAINFO from <option>environment.sessionVariables</option>, - NIX_REMOTE is set to "daemon" and JENKINS_HOME is set to - the value of <option>services.jenkins.home</option>. This option has - precedence and can be used to override those mentioned variables. + As a base environment, jenkins receives NIX_PATH from + <option>environment.sessionVariables</option>, NIX_REMOTE is set to + "daemon" and JENKINS_HOME is set to the value of + <option>services.jenkins.home</option>. + This option has precedence and can be used to override those + mentioned variables. ''; }; @@ -136,11 +137,7 @@ in { environment = let selectedSessionVars = - lib.filterAttrs (n: v: builtins.elem n - [ "NIX_PATH" - "SSL_CERT_FILE" - "GIT_SSL_CAINFO" - ]) + lib.filterAttrs (n: v: builtins.elem n [ "NIX_PATH" ]) config.environment.sessionVariables; in selectedSessionVars // diff --git a/nixos/modules/services/hardware/sane.nix b/nixos/modules/services/hardware/sane.nix index 56504cd2361..a3403740312 100644 --- a/nixos/modules/services/hardware/sane.nix +++ b/nixos/modules/services/hardware/sane.nix @@ -21,7 +21,13 @@ in hardware.sane.enable = mkOption { type = types.bool; default = false; - description = "Enable support for SANE scanners."; + description = '' + Enable support for SANE scanners. + + <note><para> + Users in the "scanner" group will gain access to the scanner. + </para></note> + ''; }; hardware.sane.snapshot = mkOption { @@ -33,7 +39,14 @@ in hardware.sane.extraBackends = mkOption { type = types.listOf types.path; default = []; - description = "Packages providing extra SANE backends to enable."; + description = '' + Packages providing extra SANE backends to enable. + + <note><para> + The example contains the package for HP scanners. + </para></note> + ''; + example = literalExample "[ pkgs.hplipWithPlugin ]"; }; hardware.sane.configDir = mkOption { diff --git a/nixos/modules/services/hardware/udev.nix b/nixos/modules/services/hardware/udev.nix index 369a50bd6a8..8e883ed7775 100644 --- a/nixos/modules/services/hardware/udev.nix +++ b/nixos/modules/services/hardware/udev.nix @@ -13,13 +13,13 @@ let extraUdevRules = pkgs.writeTextFile { name = "extra-udev-rules"; text = cfg.extraRules; - destination = "/etc/udev/rules.d/10-local.rules"; + destination = "/etc/udev/rules.d/99-local.rules"; }; extraHwdbFile = pkgs.writeTextFile { name = "extra-hwdb-file"; text = cfg.extraHwdb; - destination = "/etc/udev/hwdb.d/10-local.hwdb"; + destination = "/etc/udev/hwdb.d/99-local.hwdb"; }; nixosRules = '' @@ -212,8 +212,8 @@ in type = types.lines; description = '' Additional <command>udev</command> rules. They'll be written - into file <filename>10-local.rules</filename>. Thus they are - read before all other rules. + into file <filename>99-local.rules</filename>. Thus they are + read and applied after all other rules. ''; }; diff --git a/nixos/modules/services/logging/logstash.nix b/nixos/modules/services/logging/logstash.nix index d27456e59e8..e019e6c3f23 100644 --- a/nixos/modules/services/logging/logstash.nix +++ b/nixos/modules/services/logging/logstash.nix @@ -85,7 +85,7 @@ in type = types.lines; default = ''stdin { type => "example" }''; description = "Logstash input configuration."; - example = literalExample '' + example = '' # Read from journal pipe { command => "''${pkgs.systemd}/bin/journalctl -f -o json" @@ -98,7 +98,7 @@ in type = types.lines; default = ''noop {}''; description = "logstash filter configuration."; - example = literalExample '' + example = '' if [type] == "syslog" { # Keep only relevant systemd fields # http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html @@ -114,7 +114,7 @@ in outputConfig = mkOption { type = types.lines; - default = literalExample ''stdout { debug => true debug_format => "json"}''; + default = ''stdout { debug => true debug_format => "json"}''; description = "Logstash output configuration."; example = '' redis { host => "localhost" data_type => "list" key => "logstash" codec => json } diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix index 333a03315bc..3935c14dc8c 100644 --- a/nixos/modules/services/mail/dovecot.nix +++ b/nixos/modules/services/mail/dovecot.nix @@ -254,7 +254,7 @@ in ${concatStringsSep "\n" (mapAttrsToList (to: from: '' if [ -d '${from}' ]; then mkdir '${stateDir}/sieve/${to}' - cp ${from}/*.sieve '${stateDir}/sieve/${to}' + cp "${from}/"*.sieve '${stateDir}/sieve/${to}' else cp '${from}' '${stateDir}/sieve/${to}' fi diff --git a/nixos/modules/services/mail/dspam.nix b/nixos/modules/services/mail/dspam.nix index 2d8aebe2057..46e6f216b21 100644 --- a/nixos/modules/services/mail/dspam.nix +++ b/nixos/modules/services/mail/dspam.nix @@ -19,7 +19,10 @@ let SystemLog on UserLog on - ${optionalString (cfg.domainSocket != null) ''ServerDomainSocketPath "${cfg.domainSocket}"''} + ${optionalString (cfg.domainSocket != null) '' + ServerDomainSocketPath "${cfg.domainSocket}" + ClientHost "${cfg.domainSocket}" + ''} ${cfg.extraConfig} ''; @@ -108,6 +111,7 @@ in { User = cfg.user; Group = cfg.group; RuntimeDirectory = optional (cfg.domainSocket == defaultSock) "dspam"; + RuntimeDirectoryMode = optional (cfg.domainSocket == defaultSock) "0750"; PermissionsStartOnly = true; # DSPAM segfaults on just about every error Restart = "on-failure"; diff --git a/nixos/modules/services/mail/opendkim.nix b/nixos/modules/services/mail/opendkim.nix index 1cdae9cb654..af996758f41 100644 --- a/nixos/modules/services/mail/opendkim.nix +++ b/nixos/modules/services/mail/opendkim.nix @@ -49,7 +49,12 @@ in { domains = mkOption { type = types.str; - description = "Local domains set; messages from them are signed, not verified."; + default = "csl:${config.networking.hostName}"; + example = "csl:example.com,mydomain.net"; + description = '' + Local domains set (see <literal>opendkim(8)</literal> for more information on datasets). + Messages from them are signed, not verified. + ''; }; keyFile = mkOption { @@ -77,8 +82,6 @@ in { config = mkIf cfg.enable { - services.opendkim.domains = mkDefault "csl:${config.networking.hostName}"; - users.extraUsers = optionalAttrs (cfg.user == "opendkim") (singleton { name = "opendkim"; group = cfg.group; diff --git a/nixos/modules/services/misc/bepasty.nix b/nixos/modules/services/misc/bepasty.nix index 12671cb1b6c..5bda73ab64f 100644 --- a/nixos/modules/services/misc/bepasty.nix +++ b/nixos/modules/services/misc/bepasty.nix @@ -103,9 +103,13 @@ in after = [ "network.target" ]; restartIfChanged = true; - environment = { + environment = let + penv = python.buildEnv.override { + extraLibs = [ bepasty gevent ]; + }; + in { BEPASTY_CONFIG = "${server.workDir}/bepasty-${name}.conf"; - PYTHONPATH= "${bepasty}/lib/${python.libPrefix}/site-packages:${gevent}/lib/${python.libPrefix}/site-packages"; + PYTHONPATH= "${penv}/${python.sitePackages}/"; }; serviceConfig = { diff --git a/nixos/modules/services/misc/cfdyndns.nix b/nixos/modules/services/misc/cfdyndns.nix new file mode 100644 index 00000000000..69a33d0b8c1 --- /dev/null +++ b/nixos/modules/services/misc/cfdyndns.nix @@ -0,0 +1,70 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.cfdyndns; +in +{ + options = { + services.cfdyndns = { + enable = mkEnableOption "Cloudflare Dynamic DNS Client"; + + email = mkOption { + type = types.str; + description = '' + The email address to use to authenticate to CloudFlare. + ''; + }; + + apikey = mkOption { + type = types.str; + description = '' + The API Key to use to authenticate to CloudFlare. + ''; + }; + + records = mkOption { + default = []; + example = [ "host.tld" ]; + type = types.listOf types.str; + description = '' + The records to update in CloudFlare. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.cfdyndns = { + description = "CloudFlare Dynamic DNS Client"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + startAt = "5 minutes"; + serviceConfig = { + Type = "simple"; + User = config.ids.uids.cfdyndns; + Group = config.ids.gids.cfdyndns; + ExecStart = "/bin/sh -c '${pkgs.cfdyndns}/bin/cfdyndns'"; + }; + environment = { + CLOUDFLARE_EMAIL="${cfg.email}"; + CLOUDFLARE_APIKEY="${cfg.apikey}"; + CLOUDFLARE_RECORDS="${concatStringsSep "," cfg.records}"; + }; + }; + + users.extraUsers = { + cfdyndns = { + group = "cfdyndns"; + uid = config.ids.uids.cfdyndns; + }; + }; + + users.extraGroups = { + cfdyndns = { + gid = config.ids.gids.cfdyndns; + }; + }; + }; +} diff --git a/nixos/modules/services/misc/defaultUnicornConfig.rb b/nixos/modules/services/misc/defaultUnicornConfig.rb index 81abaf336dc..84622622db7 100644 --- a/nixos/modules/services/misc/defaultUnicornConfig.rb +++ b/nixos/modules/services/misc/defaultUnicornConfig.rb @@ -187,7 +187,6 @@ working_directory ENV["GITLAB_PATH"] pid ENV["UNICORN_PATH"] + "/tmp/pids/unicorn.pid" listen ENV["UNICORN_PATH"] + "/tmp/sockets/gitlab.socket", :backlog => 1024 -listen "127.0.0.1:8080", :tcp_nopush => true timeout 60 diff --git a/nixos/modules/services/misc/gammu-smsd.nix b/nixos/modules/services/misc/gammu-smsd.nix new file mode 100644 index 00000000000..91047ead436 --- /dev/null +++ b/nixos/modules/services/misc/gammu-smsd.nix @@ -0,0 +1,253 @@ +{ pkgs, lib, config, ... }: + +with lib; +let + cfg = config.services.gammu-smsd; + + configFile = pkgs.writeText "gammu-smsd.conf" '' + [gammu] + Device = ${cfg.device.path} + Connection = ${cfg.device.connection} + SynchronizeTime = ${if cfg.device.synchronizeTime then "yes" else "no"} + LogFormat = ${cfg.log.format} + ${if (cfg.device.pin != null) then "PIN = ${cfg.device.pin}" else ""} + ${cfg.extraConfig.gammu} + + + [smsd] + LogFile = ${cfg.log.file} + Service = ${cfg.backend.service} + + ${optionalString (cfg.backend.service == "files") '' + InboxPath = ${cfg.backend.files.inboxPath} + OutboxPath = ${cfg.backend.files.outboxPath} + SentSMSPath = ${cfg.backend.files.sentSMSPath} + ErrorSMSPath = ${cfg.backend.files.errorSMSPath} + ''} + + ${optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "sqlite") '' + Driver = ${cfg.backend.sql.driver} + DBDir = ${cfg.backend.sql.database} + ''} + + ${optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "native_pgsql") ( + with cfg.backend; '' + Driver = ${sql.driver} + ${if (sql.database!= null) then "Database = ${sql.database}" else ""} + ${if (sql.host != null) then "Host = ${sql.host}" else ""} + ${if (sql.user != null) then "User = ${sql.user}" else ""} + ${if (sql.password != null) then "Password = ${sql.password}" else ""} + '')} + + ${cfg.extraConfig.smsd} + ''; + + initDBDir = "share/doc/gammu/examples/sql"; + + gammuPackage = with cfg.backend; (pkgs.gammu.override { + dbiSupport = (service == "sql" && sql.driver == "sqlite"); + postgresSupport = (service == "sql" && sql.driver == "native_pgsql"); + }); + +in { + options = { + services.gammu-smsd = { + + enable = mkEnableOption "gammu-smsd daemon"; + + user = mkOption { + type = types.str; + default = "smsd"; + description = "User that has access to the device"; + }; + + device = { + path = mkOption { + type = types.path; + description = "Device node or address of the phone"; + example = "/dev/ttyUSB2"; + }; + + group = mkOption { + type = types.str; + default = "root"; + description = "Owner group of the device"; + example = "dialout"; + }; + + connection = mkOption { + type = types.str; + default = "at"; + description = "Protocol which will be used to talk to the phone"; + }; + + synchronizeTime = mkOption { + type = types.bool; + default = true; + description = "Whether to set time from computer to the phone during starting connection"; + }; + + pin = mkOption { + type = types.nullOr types.str; + default = null; + description = "PIN code for the simcard"; + }; + }; + + + log = { + file = mkOption { + type = types.str; + default = "syslog"; + description = "Path to file where information about communication will be stored"; + }; + + format = mkOption { + type = types.enum [ "nothing" "text" "textall" "textalldate" "errors" "errorsdate" "binary" ]; + default = "errors"; + description = "Determines what will be logged to the LogFile"; + }; + }; + + + extraConfig = { + gammu = mkOption { + type = types.lines; + default = ""; + description = "Extra config lines to be added into [gammu] section"; + }; + + + smsd = mkOption { + type = types.lines; + default = ""; + description = "Extra config lines to be added into [smsd] section"; + }; + }; + + + backend = { + service = mkOption { + type = types.enum [ "null" "files" "sql" ]; + default = "null"; + description = "Service to use to store sms data."; + }; + + files = { + inboxPath = mkOption { + type = types.path; + default = "/var/spool/sms/inbox/"; + description = "Where the received SMSes are stored"; + }; + + outboxPath = mkOption { + type = types.path; + default = "/var/spool/sms/outbox/"; + description = "Where SMSes to be sent should be placed"; + }; + + sentSMSPath = mkOption { + type = types.path; + default = "/var/spool/sms/sent/"; + description = "Where the transmitted SMSes are placed"; + }; + + errorSMSPath = mkOption { + type = types.path; + default = "/var/spool/sms/error/"; + description = "Where SMSes with error in transmission is placed"; + }; + }; + + sql = { + driver = mkOption { + type = types.enum [ "native_mysql" "native_pgsql" "odbc" "dbi" ]; + description = "DB driver to use"; + }; + + sqlDialect = mkOption { + type = types.nullOr types.str; + default = null; + description = "SQL dialect to use (odbc driver only)"; + }; + + database = mkOption { + type = types.str; + default = null; + description = "Database name to store sms data"; + }; + + host = mkOption { + type = types.str; + default = "localhost"; + description = "Database server address"; + }; + + user = mkOption { + type = types.nullOr types.str; + default = null; + description = "User name used for connection to the database"; + }; + + password = mkOption { + type = types.nullOr types.str; + default = null; + description = "User password used for connetion to the database"; + }; + }; + }; + }; + }; + + config = mkIf cfg.enable { + users.extraUsers.${cfg.user} = { + description = "gammu-smsd user"; + uid = config.ids.uids.gammu-smsd; + extraGroups = [ "${cfg.device.group}" ]; + }; + + environment.systemPackages = with cfg.backend; [ gammuPackage ] + ++ optionals (service == "sql" && sql.driver == "sqlite") [ pkgs.sqlite ]; + + systemd.services.gammu-smsd = { + description = "gammu-smsd daemon"; + + wantedBy = [ "multi-user.target" ]; + + wants = with cfg.backend; [ ] + ++ optionals (service == "sql" && sql.driver == "native_pgsql") [ "postgresql.service" ]; + + preStart = with cfg.backend; + + optionalString (service == "files") (with files; '' + mkdir -m 755 -p ${inboxPath} ${outboxPath} ${sentSMSPath} ${errorSMSPath} + chown ${cfg.user} -R ${inboxPath} + chown ${cfg.user} -R ${outboxPath} + chown ${cfg.user} -R ${sentSMSPath} + chown ${cfg.user} -R ${errorSMSPath} + '') + + optionalString (service == "sql" && sql.driver == "sqlite") '' + cat "${gammuPackage}/${initDBDir}/sqlite.sql" \ + | ${pkgs.sqlite}/bin/sqlite3 ${sql.database} + '' + + (let execPsql = extraArgs: concatStringsSep " " [ + (optionalString (sql.password != null) "PGPASSWORD=${sql.password}") + "${config.services.postgresql.package}/bin/psql" + (optionalString (sql.host != null) "-h ${sql.host}") + (optionalString (sql.user != null) "-U ${sql.user}") + "$extraArgs" + "${sql.database}" + ]; in optionalString (service == "sql" && sql.driver == "native_pgsql") '' + echo '\i '"${gammuPackage}/${initDBDir}/pgsql.sql" | ${execPsql ""} + ''); + + serviceConfig = { + User = "${cfg.user}"; + Group = "${cfg.device.group}"; + PermissionsStartOnly = true; + ExecStart = "${gammuPackage}/bin/gammu-smsd -c ${configFile}"; + }; + + }; + }; +} diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index 949357ab20f..cc50bfbea53 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -7,10 +7,13 @@ with lib; let cfg = config.services.gitlab; - ruby = pkgs.gitlab.ruby; + ruby = cfg.packages.gitlab.ruby; bundler = pkgs.bundler; - gemHome = "${pkgs.gitlab.env}/${ruby.gemPath}"; + gemHome = "${cfg.packages.gitlab.env}/${ruby.gemPath}"; + + gitlabSocket = "${cfg.statePath}/tmp/sockets/gitlab.socket"; + pathUrlQuote = url: replaceStrings ["/"] ["%2F"] url; databaseYml = '' production: @@ -21,14 +24,15 @@ let username: ${cfg.databaseUsername} encoding: utf8 ''; + gitlabShellYml = '' - user: gitlab - gitlab_url: "http://${cfg.host}:${toString cfg.port}/" + user: ${cfg.user} + gitlab_url: "http+unix://${pathUrlQuote gitlabSocket}" http_settings: self_signed_cert: false - repos_path: "${cfg.stateDir}/repositories" - secret_file: "${cfg.stateDir}/config/gitlab_shell_secret" - log_file: "${cfg.stateDir}/log/gitlab-shell.log" + repos_path: "${cfg.statePath}/repositories" + secret_file: "${cfg.statePath}/config/gitlab_shell_secret" + log_file: "${cfg.statePath}/log/gitlab-shell.log" redis: bin: ${pkgs.redis}/bin/redis-cli host: 127.0.0.1 @@ -37,33 +41,102 @@ let namespace: resque:gitlab ''; + gitlabConfig = { + # These are the default settings from config/gitlab.example.yml + production = flip recursiveUpdate cfg.extraConfig { + gitlab = { + host = cfg.host; + port = cfg.port; + https = cfg.https; + user = cfg.user; + email_enabled = true; + email_display_name = "GitLab"; + email_reply_to = "noreply@localhost"; + default_theme = 2; + default_projects_features = { + issues = true; + merge_requests = true; + wiki = true; + snippets = false; + builds = true; + }; + }; + artifacts = { + enabled = true; + }; + lfs = { + enabled = true; + }; + gravatar = { + enabled = true; + }; + cron_jobs = { + stuck_ci_builds_worker = { + cron = "0 0 * * *"; + }; + }; + gitlab_ci = { + builds_path = "${cfg.statePath}/builds"; + }; + ldap = { + enabled = false; + }; + omniauth = { + enabled = false; + }; + shared = { + path = "${cfg.statePath}/shared"; + }; + backup = { + path = "${cfg.backupPath}"; + }; + gitlab_shell = { + path = "${cfg.packages.gitlab-shell}"; + repos_path = "${cfg.statePath}/repositories"; + hooks_path = "${cfg.statePath}/shell/hooks"; + secret_file = "${cfg.statePath}/config/gitlab_shell_secret"; + upload_pack = true; + receive_pack = true; + }; + git = { + bin_path = "git"; + max_size = 20971520; # 20MB + timeout = 10; + }; + extra = {}; + }; + }; + + gitlabEnv = { + HOME = "${cfg.statePath}/home"; + GEM_HOME = gemHome; + BUNDLE_GEMFILE = "${cfg.packages.gitlab}/share/gitlab/Gemfile"; + UNICORN_PATH = "${cfg.statePath}/"; + GITLAB_PATH = "${cfg.packages.gitlab}/share/gitlab/"; + GITLAB_STATE_PATH = "${cfg.statePath}"; + GITLAB_UPLOADS_PATH = "${cfg.statePath}/uploads"; + GITLAB_LOG_PATH = "${cfg.statePath}/log"; + GITLAB_SHELL_PATH = "${cfg.packages.gitlab-shell}"; + GITLAB_SHELL_CONFIG_PATH = "${cfg.statePath}/shell/config.yml"; + GITLAB_SHELL_SECRET_PATH = "${cfg.statePath}/config/gitlab_shell_secret"; + GITLAB_SHELL_HOOKS_PATH = "${cfg.statePath}/shell/hooks"; + RAILS_ENV = "production"; + }; + unicornConfig = builtins.readFile ./defaultUnicornConfig.rb; gitlab-runner = pkgs.stdenv.mkDerivation rec { name = "gitlab-runner"; - buildInputs = [ pkgs.gitlab pkgs.bundler pkgs.makeWrapper ]; + buildInputs = [ cfg.packages.gitlab bundler pkgs.makeWrapper ]; phases = "installPhase fixupPhase"; buildPhase = ""; installPhase = '' mkdir -p $out/bin - makeWrapper ${bundler}/bin/bundle $out/bin/gitlab-runner\ - --set RAKEOPT '"-f ${pkgs.gitlab}/share/gitlab/Rakefile"'\ - --set GEM_HOME '${gemHome}'\ - --set UNICORN_PATH "${cfg.stateDir}/"\ - --set GITLAB_PATH "${pkgs.gitlab}/share/gitlab/"\ - --set GITLAB_APPLICATION_LOG_PATH "${cfg.stateDir}/log/application.log"\ - --set GITLAB_SATELLITES_PATH "${cfg.stateDir}/satellites"\ - --set GITLAB_SHELL_PATH "${pkgs.gitlab-shell}"\ - --set GITLAB_REPOSITORIES_PATH "${cfg.stateDir}/repositories"\ - --set GITLAB_SHELL_HOOKS_PATH "${cfg.stateDir}/shell/hooks"\ - --set BUNDLE_GEMFILE "${pkgs.gitlab}/share/gitlab/Gemfile"\ - --set GITLAB_EMAIL_FROM "${cfg.emailFrom}"\ - --set GITLAB_SHELL_CONFIG_PATH "${cfg.stateDir}/shell/config.yml"\ - --set GITLAB_SHELL_SECRET_PATH "${cfg.stateDir}/config/gitlab_shell_secret"\ - --set GITLAB_HOST "${cfg.host}"\ - --set GITLAB_PORT "${toString cfg.port}"\ - --set GITLAB_BACKUP_PATH "${cfg.backupPath}"\ - --set RAILS_ENV "production" + makeWrapper ${bundler}/bin/bundle $out/bin/gitlab-runner \ + ${concatStrings (mapAttrsToList (name: value: "--set ${name} '\"${value}\"' ") gitlabEnv)} \ + --set GITLAB_CONFIG_PATH '"${cfg.statePath}/config"' \ + --set PATH '"${pkgs.nodejs}/bin:${pkgs.gzip}/bin:${config.services.postgresql.package}/bin:$PATH"' \ + --set RAKEOPT '"-f ${cfg.packages.gitlab}/share/gitlab/Rakefile"' ''; }; @@ -79,13 +152,25 @@ in { ''; }; - satelliteDir = mkOption { - type = types.str; - default = "/var/gitlab/git-satellites"; - description = "Gitlab directory to store checked out git trees requires for operation."; + packages.gitlab = mkOption { + type = types.package; + default = pkgs.gitlab; + description = "Reference to the gitlab package"; + }; + + packages.gitlab-shell = mkOption { + type = types.package; + default = pkgs.gitlab-shell; + description = "Reference to the gitlab-shell package"; + }; + + packages.gitlab-workhorse = mkOption { + type = types.package; + default = pkgs.gitlab-workhorse; + description = "Reference to the gitlab-workhorse package"; }; - stateDir = mkOption { + statePath = mkOption { type = types.str; default = "/var/gitlab/state"; description = "Gitlab state directory, logs are stored here."; @@ -93,7 +178,7 @@ in { backupPath = mkOption { type = types.str; - default = cfg.stateDir + "/backup"; + default = cfg.statePath + "/backup"; description = "Gitlab path for backups."; }; @@ -136,14 +221,67 @@ in { port = mkOption { type = types.int; default = 8080; - description = "Gitlab server listening port."; + description = '' + Gitlab server port for copy-paste URLs, e.g. 80 or 443 if you're + service over https. + ''; + }; + + https = mkOption { + type = types.bool; + default = false; + description = "Whether gitlab prints URLs with https as scheme."; + }; + + user = mkOption { + type = types.str; + default = "gitlab"; + description = "User to run gitlab and all related services."; + }; + + group = mkOption { + type = types.str; + default = "gitlab"; + description = "Group to run gitlab and all related services."; + }; + + initialRootEmail = mkOption { + type = types.str; + default = "admin@local.host"; + description = '' + Initial email address of the root account if this is a new install. + ''; + }; + + initialRootPassword = mkOption { + type = types.str; + default = "UseNixOS!"; + description = '' + Initial password of the root account if this is a new install. + ''; + }; + + extraConfig = mkOption { + type = types.attrs; + default = {}; + example = { + gitlab = { + default_projects_features = { + builds = false; + }; + }; + }; + description = '' + Extra options to be merged into config/gitlab.yml as nix + attribute set. + ''; }; }; }; config = mkIf cfg.enable { - environment.systemPackages = [ pkgs.git gitlab-runner pkgs.gitlab-shell ]; + environment.systemPackages = [ pkgs.git gitlab-runner cfg.packages.gitlab-shell ]; assertions = [ { assertion = cfg.databasePassword != ""; @@ -159,39 +297,24 @@ in { services.postfix.enable = mkDefault true; users.extraUsers = [ - { name = "gitlab"; - group = "gitlab"; - home = "${cfg.stateDir}/home"; + { name = cfg.user; + group = cfg.group; + home = "${cfg.statePath}/home"; shell = "${pkgs.bash}/bin/bash"; uid = config.ids.uids.gitlab; - } ]; + } + ]; users.extraGroups = [ - { name = "gitlab"; + { name = cfg.group; gid = config.ids.gids.gitlab; - } ]; + } + ]; systemd.services.gitlab-sidekiq = { after = [ "network.target" "redis.service" ]; wantedBy = [ "multi-user.target" ]; - environment.HOME = "${cfg.stateDir}/home"; - environment.GEM_HOME = gemHome; - environment.UNICORN_PATH = "${cfg.stateDir}/"; - environment.GITLAB_PATH = "${pkgs.gitlab}/share/gitlab/"; - environment.GITLAB_APPLICATION_LOG_PATH = "${cfg.stateDir}/log/application.log"; - environment.GITLAB_SATELLITES_PATH = "${cfg.stateDir}/satellites"; - environment.GITLAB_SHELL_PATH = "${pkgs.gitlab-shell}"; - environment.GITLAB_REPOSITORIES_PATH = "${cfg.stateDir}/repositories"; - environment.GITLAB_SHELL_HOOKS_PATH = "${cfg.stateDir}/shell/hooks"; - environment.BUNDLE_GEMFILE = "${pkgs.gitlab}/share/gitlab/Gemfile"; - environment.GITLAB_EMAIL_FROM = "${cfg.emailFrom}"; - environment.GITLAB_SHELL_CONFIG_PATH = "${cfg.stateDir}/shell/config.yml"; - environment.GITLAB_SHELL_SECRET_PATH = "${cfg.stateDir}/config/gitlab_shell_secret"; - environment.GITLAB_HOST = "${cfg.host}"; - environment.GITLAB_PORT = "${toString cfg.port}"; - environment.GITLAB_DATABASE_HOST = "${cfg.databaseHost}"; - environment.GITLAB_DATABASE_PASSWORD = "${cfg.databasePassword}"; - environment.RAILS_ENV = "production"; + environment = gitlabEnv; path = with pkgs; [ config.services.postgresql.package gitAndTools.git @@ -201,116 +324,131 @@ in { ]; serviceConfig = { Type = "simple"; - User = "gitlab"; - Group = "gitlab"; + User = cfg.user; + Group = cfg.group; TimeoutSec = "300"; - WorkingDirectory = "${pkgs.gitlab}/share/gitlab"; - ExecStart="${bundler}/bin/bundle exec \"sidekiq -q post_receive -q mailer -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e production -P ${cfg.stateDir}/tmp/sidekiq.pid\""; + WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab"; + ExecStart="${bundler}/bin/bundle exec \"sidekiq -q post_receive -q mailer -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e production -P ${cfg.statePath}/tmp/sidekiq.pid\""; }; }; - systemd.services.gitlab-git-http-server = { + systemd.services.gitlab-workhorse = { after = [ "network.target" "gitlab.service" ]; wantedBy = [ "multi-user.target" ]; - environment.HOME = "${cfg.stateDir}/home"; + environment.HOME = gitlabEnv.HOME; + environment.GITLAB_SHELL_CONFIG_PATH = gitlabEnv.GITLAB_SHELL_CONFIG_PATH; path = with pkgs; [ gitAndTools.git openssh ]; + preStart = '' + mkdir -p /run/gitlab + chown ${cfg.user}:${cfg.group} /run/gitlab + ''; serviceConfig = { + PermissionsStartOnly = true; # preStart must be run as root Type = "simple"; - User = "gitlab"; - Group = "gitlab"; + User = cfg.user; + Group = cfg.group; TimeoutSec = "300"; - ExecStart = "${pkgs.gitlab-git-http-server}/bin/gitlab-git-http-server -listenUmask 0 -listenNetwork unix -listenAddr ${cfg.stateDir}/tmp/sockets/gitlab-git-http-server.socket -authBackend http://localhost:8080 ${cfg.stateDir}/repositories"; + ExecStart = + "${cfg.packages.gitlab-workhorse}/bin/gitlab-workhorse " + + "-listenUmask 0 " + + "-listenNetwork unix " + + "-listenAddr /run/gitlab/gitlab-workhorse.socket " + + "-authSocket ${gitlabSocket} " + + "-documentRoot ${cfg.packages.gitlab}/share/gitlab/public"; }; }; systemd.services.gitlab = { after = [ "network.target" "postgresql.service" "redis.service" ]; wantedBy = [ "multi-user.target" ]; - environment.HOME = "${cfg.stateDir}/home"; - environment.GEM_HOME = gemHome; - environment.UNICORN_PATH = "${cfg.stateDir}/"; - environment.GITLAB_PATH = "${pkgs.gitlab}/share/gitlab/"; - environment.GITLAB_APPLICATION_LOG_PATH = "${cfg.stateDir}/log/application.log"; - environment.GITLAB_SATELLITES_PATH = "${cfg.stateDir}/satellites"; - environment.GITLAB_SHELL_PATH = "${pkgs.gitlab-shell}"; - environment.GITLAB_SHELL_CONFIG_PATH = "${cfg.stateDir}/shell/config.yml"; - environment.GITLAB_SHELL_SECRET_PATH = "${cfg.stateDir}/config/gitlab_shell_secret"; - environment.GITLAB_REPOSITORIES_PATH = "${cfg.stateDir}/repositories"; - environment.GITLAB_SHELL_HOOKS_PATH = "${cfg.stateDir}/shell/hooks"; - environment.BUNDLE_GEMFILE = "${pkgs.gitlab}/share/gitlab/Gemfile"; - environment.GITLAB_EMAIL_FROM = "${cfg.emailFrom}"; - environment.GITLAB_HOST = "${cfg.host}"; - environment.GITLAB_PORT = "${toString cfg.port}"; - environment.GITLAB_DATABASE_HOST = "${cfg.databaseHost}"; - environment.GITLAB_DATABASE_PASSWORD = "${cfg.databasePassword}"; - environment.RAILS_ENV = "production"; + environment = gitlabEnv; path = with pkgs; [ config.services.postgresql.package gitAndTools.git - ruby openssh nodejs ]; preStart = '' - # TODO: use env vars - mkdir -p ${cfg.stateDir} - mkdir -p ${cfg.stateDir}/log - mkdir -p ${cfg.stateDir}/satellites - mkdir -p ${cfg.stateDir}/repositories - mkdir -p ${cfg.stateDir}/shell/hooks - mkdir -p ${cfg.stateDir}/tmp/pids - mkdir -p ${cfg.stateDir}/tmp/sockets - rm -rf ${cfg.stateDir}/config - mkdir -p ${cfg.stateDir}/config - # TODO: What exactly is gitlab-shell doing with the secret? - tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 20 > ${cfg.stateDir}/config/gitlab_shell_secret - mkdir -p ${cfg.stateDir}/home/.ssh - touch ${cfg.stateDir}/home/.ssh/authorized_keys - - cp -rf ${pkgs.gitlab}/share/gitlab/config ${cfg.stateDir}/ - cp ${pkgs.gitlab}/share/gitlab/VERSION ${cfg.stateDir}/VERSION + mkdir -p ${cfg.backupPath} + mkdir -p ${cfg.statePath}/builds + mkdir -p ${cfg.statePath}/repositories + mkdir -p ${gitlabConfig.production.shared.path}/artifacts + mkdir -p ${gitlabConfig.production.shared.path}/lfs-objects + mkdir -p ${cfg.statePath}/log + mkdir -p ${cfg.statePath}/shell + mkdir -p ${cfg.statePath}/tmp/pids + mkdir -p ${cfg.statePath}/tmp/sockets + + rm -rf ${cfg.statePath}/config ${cfg.statePath}/shell/hooks + mkdir -p ${cfg.statePath}/config ${cfg.statePath}/shell - ln -fs ${pkgs.writeText "database.yml" databaseYml} ${cfg.stateDir}/config/database.yml - ln -fs ${pkgs.writeText "unicorn.rb" unicornConfig} ${cfg.stateDir}/config/unicorn.rb - - chown -R gitlab:gitlab ${cfg.stateDir}/ - chmod -R 755 ${cfg.stateDir}/ + # TODO: What exactly is gitlab-shell doing with the secret? + tr -dc _A-Z-a-z-0-9 < /dev/urandom | head -c 20 > ${cfg.statePath}/config/gitlab_shell_secret + + # The uploads directory is hardcoded somewhere deep in rails. It is + # symlinked in the gitlab package to /run/gitlab/uploads to make it + # configurable + mkdir -p /run/gitlab + mkdir -p ${cfg.statePath}/uploads + ln -sf ${cfg.statePath}/uploads /run/gitlab/uploads + chown -R ${cfg.user}:${cfg.group} /run/gitlab + + # Prepare home directory + mkdir -p ${gitlabEnv.HOME}/.ssh + touch ${gitlabEnv.HOME}/.ssh/authorized_keys + chown -R ${cfg.user}:${cfg.group} ${gitlabEnv.HOME}/ + chmod -R u+rwX,go-rwx+X ${gitlabEnv.HOME}/ + + cp -rf ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config + ln -sf ${cfg.statePath}/config /run/gitlab/config + cp ${cfg.packages.gitlab}/share/gitlab/VERSION ${cfg.statePath}/VERSION + + # JSON is a subset of YAML + ln -fs ${pkgs.writeText "gitlab.yml" (builtins.toJSON gitlabConfig)} ${cfg.statePath}/config/gitlab.yml + ln -fs ${pkgs.writeText "database.yml" databaseYml} ${cfg.statePath}/config/database.yml + ln -fs ${pkgs.writeText "unicorn.rb" unicornConfig} ${cfg.statePath}/config/unicorn.rb + + chown -R ${cfg.user}:${cfg.group} ${cfg.statePath}/ + chmod -R ug+rwX,o-rwx+X ${cfg.statePath}/ + + # Install the shell required to push repositories + ln -fs ${pkgs.writeText "config.yml" gitlabShellYml} "$GITLAB_SHELL_CONFIG_PATH" + ln -fs ${cfg.packages.gitlab-shell}/hooks "$GITLAB_SHELL_HOOKS_PATH" + ${cfg.packages.gitlab-shell}/bin/install if [ "${cfg.databaseHost}" = "127.0.0.1" ]; then - if ! test -e "${cfg.stateDir}/db-created"; then + if ! test -e "${cfg.statePath}/db-created"; then psql postgres -c "CREATE ROLE gitlab WITH LOGIN NOCREATEDB NOCREATEROLE NOCREATEUSER ENCRYPTED PASSWORD '${cfg.databasePassword}'" ${config.services.postgresql.package}/bin/createdb --owner gitlab gitlab || true - touch "${cfg.stateDir}/db-created" + touch "${cfg.statePath}/db-created" - # force=yes disables the manual-interaction yes/no prompt - # which breaks without an stdin. - force=yes ${bundler}/bin/bundle exec rake -f ${pkgs.gitlab}/share/gitlab/Rakefile gitlab:setup RAILS_ENV=production + # The gitlab:setup task is horribly broken somehow, these two tasks will do the same for setting up the initial database + ${gitlab-runner}/bin/gitlab-runner exec rake db:migrate RAILS_ENV=production + ${gitlab-runner}/bin/gitlab-runner exec rake db:seed_fu RAILS_ENV=production \ + GITLAB_ROOT_PASSWORD="${cfg.initialRootPassword}" GITLAB_ROOT_EMAIL="${cfg.initialRootEmail}"; fi fi - ${bundler}/bin/bundle exec rake -f ${pkgs.gitlab}/share/gitlab/Rakefile db:migrate RAILS_ENV=production - # Install the shell required to push repositories - ln -fs ${pkgs.writeText "config.yml" gitlabShellYml} ${cfg.stateDir}/shell/config.yml - export GITLAB_SHELL_CONFIG_PATH=""${cfg.stateDir}/shell/config.yml - ${pkgs.gitlab-shell}/bin/install + # Always do the db migrations just to be sure the database is up-to-date + ${gitlab-runner}/bin/gitlab-runner exec rake db:migrate RAILS_ENV=production - # Change permissions in the last step because some of the - # intermediary scripts like to create directories as root. - chown -R gitlab:gitlab ${cfg.stateDir}/ - chmod -R 755 ${cfg.stateDir}/ + # Change permissions in the last step because some of the + # intermediary scripts like to create directories as root. + chown -R ${cfg.user}:${cfg.group} ${cfg.statePath} + chmod -R u+rwX,go-rwx+X ${cfg.statePath} ''; serviceConfig = { PermissionsStartOnly = true; # preStart must be run as root Type = "simple"; - User = "gitlab"; - Group = "gitlab"; + User = cfg.user; + Group = cfg.group; TimeoutSec = "300"; - WorkingDirectory = "${pkgs.gitlab}/share/gitlab"; - ExecStart="${bundler}/bin/bundle exec \"unicorn -c ${cfg.stateDir}/config/unicorn.rb -E production\""; + WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab"; + ExecStart="${bundler}/bin/bundle exec \"unicorn -c ${cfg.statePath}/config/unicorn.rb -E production\""; }; }; diff --git a/nixos/modules/services/misc/gitlab.xml b/nixos/modules/services/misc/gitlab.xml new file mode 100644 index 00000000000..b630fe42113 --- /dev/null +++ b/nixos/modules/services/misc/gitlab.xml @@ -0,0 +1,103 @@ +<chapter xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xi="http://www.w3.org/2001/XInclude" + version="5.0" + xml:id="module-services-gitlab"> + +<title>Gitlab</title> + +<para>Gitlab is a feature-rich git hosting service.</para> + +<section><title>Prerequisites</title> + +<para>The gitlab service exposes only an Unix socket at +<literal>/run/gitlab/gitlab-workhorse.socket</literal>. You need to configure a +webserver to proxy HTTP requests to the socket.</para> + +<para>For instance, this could be used for Nginx: + +<programlisting> +services.nginx.httpConfig = '' + server { + server_name git.example.com; + listen 443 ssl spdy; + listen [::]:443 ssl spdy; + + ssl_certificate /var/lib/acme/git.example.com/fullchain.pem; + ssl_certificate_key /var/lib/acme/git.example.com/key.pem; + + location / { + proxy_http_version 1.1; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-Ssl on; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_pass http://unix:/run/gitlab/gitlab-workhorse.socket; + } + } +''; +</programlisting> +</para> + +</section> + +<section><title>Configuring</title> + +<para>Gitlab depends on both PostgreSQL and Redis and will automatically enable +both services. In the case of PostgreSQL, a database and a role will be created. +</para> + +<para>The default state dir is /var/gitlab/state. This is where all data like +the repositories and uploads will be stored.</para> + +<para>A basic configuration could look like this: + +<programlisting> +services.gitlab = { + enable = true; + databasePassword = "eXaMpl3"; + initialRootPassword = "UseNixOS!"; + https = true; + host = "git.example.com"; + port = 443; + user = "git"; + group = "git"; + extraConfig = { + gitlab = { + default_projects_features = { builds = false; }; + }; + }; +}; +</programlisting> +</para> + +<para>Refer to <xref linkend="ch-options" /> for all available configuration +options for the <literal>services.gitlab</literal> module.</para> + +</section> + +<section><title>Maintenance</title> + +<para>You can run all Gitlab related commands like rake tasks with +<literal>gitlab-runner</literal> which will be available on the system +when gitlab is enabled. You will have to run the commands as the user that +you configured to run gitlab.</para> + +<para>For instance, to backup a Gitlab instance: + +<programlisting> +$ sudo -u git -H gitlab-runner exec rake gitlab:backup:create +</programlisting> + +A list of all availabe rake tasks can be obtained by running: + +<programlisting> +$ sudo -u git -H gitlab-runner exec rake -T +</programlisting> +</para> + +</section> + +</chapter> diff --git a/nixos/modules/services/misc/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix index 27c5a38e6b8..0ae0516769c 100644 --- a/nixos/modules/services/misc/matrix-synapse.nix +++ b/nixos/modules/services/misc/matrix-synapse.nix @@ -61,6 +61,7 @@ in { package = mkOption { type = types.package; default = pkgs.matrix-synapse; + defaultText = "pkgs.matrix-synapse"; description = '' Overridable attribute of the matrix synapse server package to use. ''; diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix index 24ae515a6b8..b0e4bf106d3 100644 --- a/nixos/modules/services/misc/nix-daemon.nix +++ b/nixos/modules/services/misc/nix-daemon.nix @@ -367,6 +367,8 @@ in // { CURL_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt"; } // config.networking.proxy.envVars; + unitConfig.RequiresMountsFor = "/nix/store"; + serviceConfig = { Nice = cfg.daemonNiceLevel; IOSchedulingPriority = cfg.daemonIONiceLevel; diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix index 3e1f53e79f3..37ea339300d 100644 --- a/nixos/modules/services/misc/nixos-manual.nix +++ b/nixos/modules/services/misc/nixos-manual.nix @@ -17,16 +17,32 @@ let nixpkgs.system = config.nixpkgs.system; }; - eval = evalModules { - modules = [ versionModule ] ++ baseModules; - args = (config._module.args) // { modules = [ ]; }; - }; - + /* For the purpose of generating docs, evaluate options with each derivation + in `pkgs` (recursively) replaced by a fake with path "\${pkgs.attribute.path}". + It isn't perfect, but it seems to cover a vast majority of use cases. + Caveat: even if the package is reached by a different means, + the path above will be shown and not e.g. `${config.services.foo.package}`. */ manual = import ../../../doc/manual { inherit pkgs; version = config.system.nixosVersion; revision = config.system.nixosRevision; - options = eval.options; + options = + let + scrubbedEval = evalModules { + modules = [ versionModule ] ++ baseModules; + args = (config._module.args) // { modules = [ ]; }; + specialArgs = { pkgs = scrubDerivations "pkgs" pkgs; }; + }; + scrubDerivations = namePrefix: pkgSet: mapAttrs + (name: value: + let wholeName = "${namePrefix}.${name}"; in + if isAttrs value then + scrubDerivations wholeName value + // (optionalAttrs (isDerivation value) { outPath = "\${${wholeName}}"; }) + else value + ) + pkgSet; + in scrubbedEval.options; }; entry = "${manual.manual}/share/doc/nixos/index.html"; @@ -72,7 +88,8 @@ in }; services.nixosManual.ttyNumber = mkOption { - default = "8"; + type = types.int; + default = 8; description = '' Virtual console on which to show the manual. ''; @@ -80,6 +97,7 @@ in services.nixosManual.browser = mkOption { type = types.path; + default = "${pkgs.w3m-nox}/bin/w3m"; description = '' Browser used to show the manual. ''; @@ -96,7 +114,7 @@ in [ manual.manual help ] ++ optional config.programs.man.enable manual.manpages; - boot.extraTTYs = mkIf cfg.showManual ["tty${cfg.ttyNumber}"]; + boot.extraTTYs = mkIf cfg.showManual ["tty${toString cfg.ttyNumber}"]; systemd.services = optionalAttrs cfg.showManual { "nixos-manual" = @@ -106,7 +124,7 @@ in { ExecStart = "${cfg.browser} ${entry}"; StandardInput = "tty"; StandardOutput = "tty"; - TTYPath = "/dev/tty${cfg.ttyNumber}"; + TTYPath = "/dev/tty${toString cfg.ttyNumber}"; TTYReset = true; TTYVTDisallocate = true; Restart = "always"; @@ -117,8 +135,6 @@ in services.mingetty.helpLine = mkIf cfg.showManual "\nPress <Alt-F${toString cfg.ttyNumber}> for the NixOS manual."; - services.nixosManual.browser = mkDefault "${pkgs.w3m-nox}/bin/w3m"; - }; } diff --git a/nixos/modules/services/misc/octoprint.nix b/nixos/modules/services/misc/octoprint.nix new file mode 100644 index 00000000000..9cf46345c22 --- /dev/null +++ b/nixos/modules/services/misc/octoprint.nix @@ -0,0 +1,120 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.octoprint; + + cfgUpdate = pkgs.writeText "octoprint-config.yaml" (builtins.toJSON { + plugins.cura.cura_engine = "${pkgs.curaengine}/bin/CuraEngine"; + server.host = cfg.host; + server.port = cfg.port; + webcam.ffmpeg = "${pkgs.ffmpeg}/bin/ffmpeg"; + }); + + pluginsEnv = pkgs.python.buildEnv.override { + extraLibs = cfg.plugins pkgs.octoprint-plugins; + }; + +in +{ + ##### interface + + options = { + + services.octoprint = { + + enable = mkEnableOption "OctoPrint, web interface for 3D printers"; + + host = mkOption { + type = types.str; + default = "0.0.0.0"; + description = '' + Host to bind OctoPrint to. + ''; + }; + + port = mkOption { + type = types.int; + default = 5000; + description = '' + Port to bind OctoPrint to. + ''; + }; + + user = mkOption { + type = types.str; + default = "octoprint"; + description = "User for the daemon."; + }; + + group = mkOption { + type = types.str; + default = "octoprint"; + description = "Group for the daemon."; + }; + + stateDir = mkOption { + type = types.path; + default = "/var/lib/octoprint"; + description = "State directory of the daemon."; + }; + + plugins = mkOption { + #type = types.functionTo (types.listOf types.package); + default = plugins: []; + defaultText = "plugins: []"; + example = literalExample "plugins: [ m3d-fio ]"; + description = "Additional plugins."; + }; + + }; + + }; + + ##### implementation + + config = mkIf cfg.enable { + + users.extraUsers = optionalAttrs (cfg.user == "octoprint") (singleton + { name = "octoprint"; + group = cfg.group; + uid = config.ids.uids.octoprint; + }); + + users.extraGroups = optionalAttrs (cfg.group == "octoprint") (singleton + { name = "octoprint"; + gid = config.ids.gids.octoprint; + }); + + systemd.services.octoprint = { + description = "OctoPrint, web interface for 3D printers"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + path = [ pluginsEnv ]; + environment.PYTHONPATH = makeSearchPath pkgs.python.sitePackages [ pluginsEnv ]; + + preStart = '' + mkdir -p "${cfg.stateDir}" + if [ -e "${cfg.stateDir}/config.yaml" ]; then + ${pkgs.yaml-merge}/bin/yaml-merge "${cfg.stateDir}/config.yaml" "${cfgUpdate}" > "${cfg.stateDir}/config.yaml.tmp" + mv "${cfg.stateDir}/config.yaml.tmp" "${cfg.stateDir}/config.yaml" + else + cp "${cfgUpdate}" "${cfg.stateDir}/config.yaml" + chmod 600 "${cfg.stateDir}/config.yaml" + fi + chown -R ${cfg.user}:${cfg.group} "${cfg.stateDir}" + ''; + + serviceConfig = { + ExecStart = "${pkgs.octoprint}/bin/octoprint -b ${cfg.stateDir}"; + User = cfg.user; + Group = cfg.group; + PermissionsStartOnly = true; + }; + }; + + }; + +} diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix index fb62351365e..875771dfa37 100644 --- a/nixos/modules/services/misc/plex.nix +++ b/nixos/modules/services/misc/plex.nix @@ -58,6 +58,7 @@ in package = mkOption { type = types.package; default = pkgs.plex; + defaultText = "pkgs.plex"; description = '' The Plex package to use. Plex subscribers may wish to use their own package here, pointing to subscriber-only server versions. diff --git a/nixos/modules/services/misc/spice-vdagentd.nix b/nixos/modules/services/misc/spice-vdagentd.nix new file mode 100644 index 00000000000..f8133394ffd --- /dev/null +++ b/nixos/modules/services/misc/spice-vdagentd.nix @@ -0,0 +1,30 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + cfg = config.services.spice-vdagentd; +in +{ + options = { + services.spice-vdagentd = { + enable = mkEnableOption "Spice guest vdagent daemon"; + }; + }; + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.spice-vdagent ]; + + systemd.services.spice-vdagentd = { + description = "spice-vdagent daemon"; + wantedBy = [ "graphical.target" ]; + preStart = '' + mkdir -p "/var/run/spice-vdagentd/" + ''; + serviceConfig = { + Type = "forking"; + ExecStart = "/bin/sh -c '${pkgs.spice-vdagent}/bin/spice-vdagentd'"; + }; + }; + }; +} diff --git a/nixos/modules/services/misc/subsonic.nix b/nixos/modules/services/misc/subsonic.nix index 5a33aa33b26..c1ebe418f72 100644 --- a/nixos/modules/services/misc/subsonic.nix +++ b/nixos/modules/services/misc/subsonic.nix @@ -97,6 +97,7 @@ in transcoders = mkOption { type = types.listOf types.path; + default = [ "${pkgs.ffmpeg.bin}/bin/ffmpeg" ]; description = '' List of paths to transcoder executables that should be accessible from Subsonic. Symlinks will be created to each executable inside @@ -152,8 +153,5 @@ in }; users.extraGroups.subsonic.gid = config.ids.gids.subsonic; - - services.subsonic.transcoders = mkDefault [ "${pkgs.ffmpeg.bin}/bin/ffmpeg" ]; - }; } diff --git a/nixos/modules/services/monitoring/collectd.nix b/nixos/modules/services/monitoring/collectd.nix index 717c2c48168..3c3d83c66ed 100644 --- a/nixos/modules/services/monitoring/collectd.nix +++ b/nixos/modules/services/monitoring/collectd.nix @@ -34,6 +34,15 @@ in { type = bool; }; + package = mkOption { + default = pkgs.collectd; + defaultText = "pkgs.collectd"; + description = '' + Which collectd package to use. + ''; + type = package; + }; + user = mkOption { default = "collectd"; description = '' @@ -91,7 +100,7 @@ in { wantedBy = [ "multi-user.target" ]; serviceConfig = { - ExecStart = "${pkgs.collectd}/sbin/collectd -C ${conf} -P ${cfg.pidFile}"; + ExecStart = "${cfg.package}/sbin/collectd -C ${conf} -P ${cfg.pidFile}"; Type = "forking"; PIDFile = cfg.pidFile; User = optional (cfg.user!="root") cfg.user; diff --git a/nixos/modules/services/monitoring/dd-agent.nix b/nixos/modules/services/monitoring/dd-agent.nix index ed9be73ba65..bd8d9950f77 100644 --- a/nixos/modules/services/monitoring/dd-agent.nix +++ b/nixos/modules/services/monitoring/dd-agent.nix @@ -183,7 +183,6 @@ in { Restart = "always"; RestartSec = 2; }; - environment.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; restartTriggers = [ pkgs.dd-agent ddConf diskConfig networkConfig postgresqlConfig nginxConfig mongoConfig ]; }; diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix index 0b49038dd27..5c6f063b149 100644 --- a/nixos/modules/services/monitoring/grafana.nix +++ b/nixos/modules/services/monitoring/grafana.nix @@ -87,6 +87,7 @@ in { staticRootPath = mkOption { description = "Root path for static assets."; + default = "${cfg.package}/share/grafana/public"; type = types.str; }; @@ -232,8 +233,5 @@ in { home = cfg.dataDir; createHome = true; }; - - services.grafana.staticRootPath = mkDefault "${cfg.package}/share/grafana/public"; - }; } diff --git a/nixos/modules/services/monitoring/hdaps.nix b/nixos/modules/services/monitoring/hdaps.nix new file mode 100644 index 00000000000..be26c44e78d --- /dev/null +++ b/nixos/modules/services/monitoring/hdaps.nix @@ -0,0 +1,22 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.hdapsd; + hdapsd = [ pkgs.hdapsd ]; +in +{ + options = { + services.hdapsd.enable = mkEnableOption + '' + Hard Drive Active Protection System Daemon, + devices are detected and managed automatically by udev and systemd + ''; + }; + + config = mkIf cfg.enable { + services.udev.packages = hdapsd; + systemd.packages = hdapsd; + }; +} diff --git a/nixos/modules/services/network-filesystems/netatalk.nix b/nixos/modules/services/network-filesystems/netatalk.nix new file mode 100644 index 00000000000..bff54406a2b --- /dev/null +++ b/nixos/modules/services/network-filesystems/netatalk.nix @@ -0,0 +1,150 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + + cfg = config.services.netatalk; + + extmapFile = pkgs.writeText "extmap.conf" cfg.extmap; + + afpToString = x: if builtins.typeOf x == "bool" + then (if x then "true" else "false") + else toString x; + + volumeConfig = name: + let vol = getAttr name cfg.volumes; in + "[${name}]\n " + (toString ( + map + (key: "${key} = ${afpToString (getAttr key vol)}\n") + (attrNames vol) + )); + + afpConf = ''[Global] + extmap file = ${extmapFile} + afp port = ${toString cfg.port} + + ${cfg.extraConfig} + + ${if cfg.homes.enable then ''[Homes] + ${optionalString (cfg.homes.path != "") "path = ${cfg.homes.path}"} + basedir regex = ${cfg.homes.basedirRegex} + ${cfg.homes.extraConfig} + '' else ""} + + ${toString (map volumeConfig (attrNames cfg.volumes))} + ''; + + afpConfFile = pkgs.writeText "afp.conf" afpConf; + +in + +{ + options = { + services.netatalk = { + + enable = mkOption { + default = false; + description = "Whether to enable the Netatalk AFP fileserver."; + }; + + port = mkOption { + default = 548; + description = "TCP port to be used for AFP."; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + example = "uam list = uams_guest.so"; + description = '' + Lines of configuration to add to the <literal>[Global]</literal> section. + See <literal>man apf.conf</literal> for more information. + ''; + }; + + homes = { + enable = mkOption { + default = false; + description = "Enable sharing of the UNIX server user home directories."; + }; + + path = mkOption { + default = ""; + example = "afp-data"; + description = "Share not the whole user home but this subdirectory path."; + }; + + basedirRegex = mkOption { + example = "/home"; + description = "Regex which matches the parent directory of the user homes."; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Lines of configuration to add to the <literal>[Homes]</literal> section. + See <literal>man apf.conf</literal> for more information. + ''; + }; + }; + + volumes = mkOption { + default = { }; + type = types.attrsOf (types.attrsOf types.unspecified); + description = + '' + Set of AFP volumes to export. + See <literal>man apf.conf</literal> for more information. + ''; + example = + { srv = + { path = "/srv"; + "read only" = true; + "hosts allow" = "10.1.0.0/16 10.2.1.100 2001:0db8:1234::/48"; + }; + }; + }; + + extmap = mkOption { + type = types.lines; + default = ""; + description = '' + File name extension mappings. + See <literal>man extmap.conf</literal> for more information. + ''; + }; + + }; + }; + + config = mkIf cfg.enable { + + systemd.services.netatalk = { + description = "Netatalk AFP fileserver for Macintosh clients"; + unitConfig.Documentation = "man:afp.conf(5) man:netatalk(8) man:afpd(8) man:cnid_metad(8) man:cnid_dbd(8)"; + after = [ "network.target" "avahi-daemon.service" ]; + wantedBy = [ "multi-user.target" ]; + + path = [ pkgs.netatalk ]; + + serviceConfig = { + Type = "forking"; + GuessMainPID = "no"; + PIDFile = "/run/lock/netatalk"; + ExecStartPre = "${pkgs.coreutils}/bin/mkdir -m 0755 -p /var/lib/netatalk/CNID"; + ExecStart = "${pkgs.netatalk}/sbin/netatalk -F ${afpConfFile}"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + ExecStop = "${pkgs.coreutils}/bin/kill -TERM $MAINPID"; + Restart = "always"; + RestartSec = 1; + }; + + }; + + security.pam.services.netatalk.unixAuth = true; + + }; + +} diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix index 576e5c9e87a..a186982ec9c 100644 --- a/nixos/modules/services/network-filesystems/samba.nix +++ b/nixos/modules/services/network-filesystems/samba.nix @@ -79,6 +79,14 @@ in description = '' Whether to enable Samba, which provides file and print services to Windows clients through the SMB/CIFS protocol. + + <note> + <para>If you use the firewall consider adding the following:</para> + <programlisting> + networking.firewall.allowedTCPPorts = [ 139 445 ]; + networking.firewall.allowedUDPPorts = [ 137 138 ]; + </programlisting> + </note> ''; }; @@ -86,7 +94,7 @@ in type = types.package; default = pkgs.samba; defaultText = "pkgs.samba"; - example = literalExample "pkgs.samba4"; + example = literalExample "pkgs.samba3"; description = '' Defines which package should be used for the samba server. ''; @@ -118,6 +126,10 @@ in description = '' Additional global section and extra section lines go in here. ''; + example = '' + guest account = nobody + map to guest = bad user + ''; }; configText = mkOption { @@ -154,9 +166,11 @@ in ''; type = types.attrsOf (types.attrsOf types.unspecified); example = - { srv = - { path = "/srv"; + { public = + { path = "/srv/public"; "read only" = true; + browseable = "yes"; + "guest ok" = "yes"; comment = "Public samba share."; }; }; diff --git a/nixos/modules/services/networking/bird.nix b/nixos/modules/services/networking/bird.nix index e7e1db19152..e76cdac14ca 100644 --- a/nixos/modules/services/networking/bird.nix +++ b/nixos/modules/services/networking/bird.nix @@ -30,7 +30,7 @@ in user = mkOption { type = types.string; - default = "ircd"; + default = "bird"; description = '' BIRD Internet Routing Daemon user. ''; @@ -38,7 +38,7 @@ in group = mkOption { type = types.string; - default = "ircd"; + default = "bird"; description = '' BIRD Internet Routing Daemon group. ''; diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix index 58dad56014b..2aa101f980d 100644 --- a/nixos/modules/services/networking/consul.nix +++ b/nixos/modules/services/networking/consul.nix @@ -33,6 +33,7 @@ in package = mkOption { type = types.package; default = pkgs.consul; + defaultText = "pkgs.consul"; description = '' The package used for the Consul agent and CLI. ''; diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix index e60520c742b..c5dd1e71c18 100644 --- a/nixos/modules/services/networking/ddclient.nix +++ b/nixos/modules/services/networking/ddclient.nix @@ -127,7 +127,6 @@ in wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - environment.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; serviceConfig = { # Uncomment this if too many problems occur: # Type = "forking"; diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix index 9340be28205..016b6a12cd6 100644 --- a/nixos/modules/services/networking/dnscrypt-proxy.nix +++ b/nixos/modules/services/networking/dnscrypt-proxy.nix @@ -52,7 +52,10 @@ in default = "opendns"; type = types.nullOr types.string; description = '' - The name of the upstream DNSCrypt resolver to use. + The name of the upstream DNSCrypt resolver to use. See + <literal>${resolverListFile}</literal> for alternative resolvers + (e.g., if you are concerned about logging and/or server + location). ''; }; customResolver = mkOption { diff --git a/nixos/modules/services/networking/ejabberd.nix b/nixos/modules/services/networking/ejabberd.nix index 7af11f37a43..8ffce23a4b1 100644 --- a/nixos/modules/services/networking/ejabberd.nix +++ b/nixos/modules/services/networking/ejabberd.nix @@ -32,6 +32,7 @@ in { package = mkOption { type = types.package; default = pkgs.ejabberd; + defaultText = "pkgs.ejabberd"; description = "ejabberd server package to use"; }; diff --git a/nixos/modules/services/networking/ifplugd.nix b/nixos/modules/services/networking/ifplugd.nix deleted file mode 100644 index 00b94fe2284..00000000000 --- a/nixos/modules/services/networking/ifplugd.nix +++ /dev/null @@ -1,82 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - - inherit (pkgs) ifplugd; - - cfg = config.networking.interfaceMonitor; - - # The ifplugd action script, which is called whenever the link - # status changes (i.e., a cable is plugged in or unplugged). - plugScript = pkgs.writeScript "ifplugd.action" - '' - #! ${pkgs.stdenv.shell} - iface="$1" - status="$2" - ${cfg.commands} - ''; - -in - -{ - - ###### interface - - options = { - - networking.interfaceMonitor.enable = mkOption { - type = types.bool; - default = false; - description = '' - If <literal>true</literal>, monitor Ethernet interfaces for - cables being plugged in or unplugged. When this occurs, the - commands specified in - <option>networking.interfaceMonitor.commands</option> are - executed. - ''; - }; - - networking.interfaceMonitor.beep = mkOption { - type = types.bool; - default = false; - description = '' - If <literal>true</literal>, beep when an Ethernet cable is - plugged in or unplugged. - ''; - }; - - networking.interfaceMonitor.commands = mkOption { - type = types.lines; - default = ""; - description = '' - Shell commands to be executed when the link status of an - interface changes. On invocation, the shell variable - <varname>iface</varname> contains the name of the interface, - while the variable <varname>status</varname> contains either - <literal>up</literal> or <literal>down</literal> to indicate - the new status. - ''; - }; - - }; - - - ###### implementation - - config = mkIf cfg.enable { - systemd.services.ifplugd = { - description = "Network interface connectivity monitor"; - after = [ "network-interfaces.target" ]; - wantedBy = [ "multi-user.target" ]; - script = '' - ${ifplugd}/sbin/ifplugd --no-daemon --no-startup --no-shutdown \ - ${if config.networking.interfaceMonitor.beep then "" else "--no-beep"} \ - --run ${plugScript} - ''; - }; - - environment.systemPackages = [ ifplugd ]; - }; -} diff --git a/nixos/modules/services/networking/kippo.nix b/nixos/modules/services/networking/kippo.nix index 7d70a3d05fa..5f3efcd133a 100644 --- a/nixos/modules/services/networking/kippo.nix +++ b/nixos/modules/services/networking/kippo.nix @@ -54,7 +54,7 @@ rec { }; config = mkIf cfg.enable { environment.systemPackages = with pkgs.pythonPackages; [ - python twisted pycrypto pyasn1 ]; + python twisted_11 pycrypto pyasn1 ]; environment.etc."kippo.cfg".text = '' # Automatically generated by NixOS. @@ -84,7 +84,7 @@ rec { description = "Kippo Web Server"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - environment.PYTHONPATH = "${pkgs.kippo}/src/:${pkgs.pythonPackages.pycrypto}/lib/python2.7/site-packages/:${pkgs.pythonPackages.pyasn1}/lib/python2.7/site-packages/:${pkgs.pythonPackages.python}/lib/python2.7/site-packages/:${pkgs.pythonPackages.twisted}/lib/python2.7/site-packages/:."; + environment.PYTHONPATH = "${pkgs.kippo}/src/:${pkgs.pythonPackages.pycrypto}/lib/python2.7/site-packages/:${pkgs.pythonPackages.pyasn1}/lib/python2.7/site-packages/:${pkgs.pythonPackages.python}/lib/python2.7/site-packages/:${pkgs.pythonPackages.twisted_11}/lib/python2.7/site-packages/:."; preStart = '' if [ ! -d ${cfg.varPath}/ ] ; then mkdir -p ${cfg.logPath}/tty @@ -107,7 +107,7 @@ rec { fi ''; - serviceConfig.ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd -y ${pkgs.kippo}/src/kippo.tac --syslog --rundir=${cfg.varPath}/ --pidfile=${cfg.pidPath}/kippo.pid --prefix=kippo -n"; + serviceConfig.ExecStart = "${pkgs.pythonPackages.twisted_11}/bin/twistd -y ${pkgs.kippo}/src/kippo.tac --syslog --rundir=${cfg.varPath}/ --pidfile=${cfg.pidPath}/kippo.pid --prefix=kippo -n"; serviceConfig.PermissionsStartOnly = true; serviceConfig.User = "kippo"; serviceConfig.Group = "kippo"; diff --git a/nixos/modules/services/networking/libreswan.nix b/nixos/modules/services/networking/libreswan.nix new file mode 100644 index 00000000000..3866b216f8e --- /dev/null +++ b/nixos/modules/services/networking/libreswan.nix @@ -0,0 +1,126 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.libreswan; + + libexec = "${pkgs.libreswan}/libexec/ipsec"; + ipsec = "${pkgs.libreswan}/sbin/ipsec"; + + trim = chars: str: let + nonchars = filter (x : !(elem x.value chars)) + (imap (i: v: {ind = (sub i 1); value = v;}) (stringToCharacters str)); + in + if length nonchars == 0 then "" + else substring (head nonchars).ind (add 1 (sub (last nonchars).ind (head nonchars).ind)) str; + indent = str: concatStrings (concatMap (s: [" " (trim [" " "\t"] s) "\n"]) (splitString "\n" str)); + configText = indent (toString cfg.configSetup); + connectionText = concatStrings (mapAttrsToList (n: v: + '' + conn ${n} + ${indent v} + + '') cfg.connections); + configFile = pkgs.writeText "ipsec.conf" + '' + config setup + ${configText} + + ${connectionText} + ''; + +in + +{ + + ###### interface + + options = { + + services.libreswan = { + + enable = mkEnableOption "libreswan ipsec service"; + + configSetup = mkOption { + type = types.lines; + default = '' + protostack=netkey + nat_traversal=yes + virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v4:100.64.0.0/10,%v6:fd00::/8,%v6:fe80::/10 + ''; + example = '' + secretsfile=/root/ipsec.secrets + protostack=netkey + nat_traversal=yes + virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v4:100.64.0.0/10,%v6:fd00::/8,%v6:fe80::/10 + ''; + description = "Options to go in the 'config setup' section of the libreswan ipsec configuration"; + }; + + connections = mkOption { + type = types.attrsOf types.lines; + default = {}; + example = { + myconnection = '' + auto=add + left=%defaultroute + leftid=@user + + right=my.vpn.com + + ikev2=no + ikelifetime=8h + ''; + }; + description = "A set of connections to define for the libreswan ipsec service"; + }; + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.libreswan pkgs.iproute ]; + + systemd.services.ipsec = { + description = "Internet Key Exchange (IKE) Protocol Daemon for IPsec"; + path = [ + "${pkgs.libreswan}" + "${pkgs.iproute}" + "${pkgs.procps}" + ]; + + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "simple"; + Restart = "always"; + EnvironmentFile = "${pkgs.libreswan}/etc/sysconfig/pluto"; + ExecStartPre = [ + "${libexec}/addconn --config ${configFile} --checkconfig" + "${libexec}/_stackmanager start" + "${ipsec} --checknss" + "${ipsec} --checknflog" + ]; + ExecStart = "${libexec}/pluto --config ${configFile} --nofork \$PLUTO_OPTIONS"; + ExecStop = "${libexec}/whack --shutdown"; + ExecStopPost = [ + "${pkgs.iproute}/bin/ip xfrm policy flush" + "${pkgs.iproute}/bin/ip xfrm state flush" + "${ipsec} --stopnflog" + ]; + ExecReload = "${libexec}/whack --listen"; + }; + + }; + + }; + +} diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix index 01c05fb4a24..9912ad9ae3f 100644 --- a/nixos/modules/services/networking/networkmanager.nix +++ b/nixos/modules/services/networking/networkmanager.nix @@ -21,6 +21,9 @@ let [logging] level=WARN + + [connection] + ipv6.ip6-privacy=2 ''; /* @@ -228,6 +231,11 @@ in { users.extraUsers = [{ name = "nm-openvpn"; uid = config.ids.uids.nm-openvpn; + } + { + # to enable link-local connections + name = "avahi-autoipd"; + uid = config.ids.uids.avahi-autoipd; }]; systemd.packages = cfg.packages; diff --git a/nixos/modules/services/networking/nntp-proxy.nix b/nixos/modules/services/networking/nntp-proxy.nix new file mode 100644 index 00000000000..cfa662c7311 --- /dev/null +++ b/nixos/modules/services/networking/nntp-proxy.nix @@ -0,0 +1,235 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + inherit (pkgs) nntp-proxy; + + proxyUser = "nntp-proxy"; + + cfg = config.services.nntp-proxy; + + configBool = b: if b then "TRUE" else "FALSE"; + + confFile = pkgs.writeText "nntp-proxy.conf" '' + nntp_server: + { + # NNTP Server host and port address + server = "${cfg.upstreamServer}"; + port = ${toString cfg.upstreamPort}; + # NNTP username + username = "${cfg.upstreamUser}"; + # NNTP password in clear text + password = "${cfg.upstreamPassword}"; + # Maximum number of connections allowed by the NNTP + max_connections = ${toString cfg.upstreamMaxConnections}; + }; + + proxy: + { + # Local address and port to bind to + bind_ip = "${cfg.listenAddress}"; + bind_port = ${toString cfg.port}; + + # SSL key and cert file + ssl_key = "${cfg.sslKey}"; + ssl_cert = "${cfg.sslCert}"; + + # prohibit users from posting + prohibit_posting = ${configBool cfg.prohibitPosting}; + # Verbose levels: ERROR, WARNING, NOTICE, INFO, DEBUG + verbose = "${toUpper cfg.verbosity}"; + # Password is made with: 'mkpasswd -m sha-512 <password>' + users = (${concatStringsSep ",\n" (mapAttrsToList (username: userConfig: + '' + { + username = "${username}"; + password = "${userConfig.passwordHash}"; + max_connections = ${toString userConfig.maxConnections}; + } + '') cfg.users)}); + }; + ''; + +in + +{ + + ###### interface + + options = { + + services.nntp-proxy = { + enable = mkEnableOption "NNTP-Proxy"; + + upstreamServer = mkOption { + type = types.str; + default = ""; + example = "ssl-eu.astraweb.com"; + description = '' + Upstream server address + ''; + }; + + upstreamPort = mkOption { + type = types.int; + default = 563; + description = '' + Upstream server port + ''; + }; + + upstreamMaxConnections = mkOption { + type = types.int; + default = 20; + description = '' + Upstream server maximum allowed concurrent connections + ''; + }; + + upstreamUser = mkOption { + type = types.str; + default = ""; + description = '' + Upstream server username + ''; + }; + + upstreamPassword = mkOption { + type = types.str; + default = ""; + description = '' + Upstream server password + ''; + }; + + listenAddress = mkOption { + type = types.str; + default = "127.0.0.1"; + example = "[::]"; + description = '' + Proxy listen address (IPv6 literal addresses need to be enclosed in "[" and "]" characters) + ''; + }; + + port = mkOption { + type = types.int; + default = 5555; + description = '' + Proxy listen port + ''; + }; + + sslKey = mkOption { + type = types.str; + default = "key.pem"; + example = "/path/to/your/key.file"; + description = '' + Proxy ssl key path + ''; + }; + + sslCert = mkOption { + type = types.str; + default = "cert.pem"; + example = "/path/to/your/cert.file"; + description = '' + Proxy ssl certificate path + ''; + }; + + prohibitPosting = mkOption { + type = types.bool; + default = true; + description = '' + Whether to prohibit posting to the upstream server + ''; + }; + + verbosity = mkOption { + type = types.str; + default = "info"; + example = "error"; + description = '' + Verbosity level (error, warning, notice, info, debug) + ''; + }; + + users = mkOption { + type = types.attrsOf (types.submodule { + options = { + username = mkOption { + type = types.str; + default = null; + description = '' + Username + ''; + }; + + passwordHash = mkOption { + type = types.str; + default = null; + example = "$6$GtzE7FrpE$wwuVgFYU.TZH4Rz.Snjxk9XGua89IeVwPQ/fEUD8eujr40q5Y021yhn0aNcsQ2Ifw.BLclyzvzgegopgKcneL0"; + description = '' + SHA-512 password hash (can be generated by + <code>mkpasswd -m sha-512 <password></code>) + ''; + }; + + maxConnections = mkOption { + type = types.int; + default = 1; + description = '' + Maximum number of concurrent connections to the proxy for this user + ''; + }; + }; + }); + description = '' + NNTP-Proxy user configuration + ''; + + default = {}; + example = literalExample '' + "user1" = { + passwordHash = "$6$1l0t5Kn2Dk$appzivc./9l/kjq57eg5UCsBKlcfyCr0zNWYNerKoPsI1d7eAwiT0SVsOVx/CTgaBNT/u4fi2vN.iGlPfv1ek0"; + maxConnections = 5; + }; + "anotheruser" = { + passwordHash = "$6$6lwEsWB.TmsS$W7m1riUx4QrA8pKJz8hvff0dnF1NwtZXgdjmGqA1Dx2MDPj07tI9GNcb0SWlMglE.2/hBgynDdAd/XqqtRqVQ0"; + maxConnections = 7; + }; + ''; + }; + }; + + }; + + ###### implementation + + config = mkIf cfg.enable { + + users.extraUsers = singleton + { name = proxyUser; + uid = config.ids.uids.nntp-proxy; + description = "NNTP-Proxy daemon user"; + }; + + systemd.services.nntp-proxy = { + description = "NNTP proxy"; + after = [ "network.target" "nss-lookup.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { User="${proxyUser}"; }; + serviceConfig.ExecStart = "${nntp-proxy}/bin/nntp-proxy ${confFile}"; + preStart = '' + if [ ! \( -f ${cfg.sslCert} -a -f ${cfg.sslKey} \) ]; then + ${pkgs.openssl}/bin/openssl req -subj '/CN=AutoGeneratedCert/O=NixOS Service/C=US' \ + -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout ${cfg.sslKey} -out ${cfg.sslCert}; + fi + ''; + }; + + }; + +} diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix index e85f2681125..333a3378c4c 100644 --- a/nixos/modules/services/networking/nsd.nix +++ b/nixos/modules/services/networking/nsd.nix @@ -7,92 +7,118 @@ let username = "nsd"; stateDir = "/var/lib/nsd"; - pidFile = stateDir + "/var/nsd.pid"; + pidFile = stateDir + "/var/nsd.pid"; + # build nsd with the options needed for the given config nsdPkg = pkgs.nsd.override { bind8Stats = cfg.bind8Stats; - ipv6 = cfg.ipv6; - ratelimit = cfg.ratelimit.enable; + ipv6 = cfg.ipv6; + ratelimit = cfg.ratelimit.enable; rootServer = cfg.rootServer; - zoneStats = length (collect (x: (x.zoneStats or null) != null) cfg.zones) > 0; + zoneStats = length (collect (x: (x.zoneStats or null) != null) cfg.zones) > 0; }; - zoneFiles = pkgs.stdenv.mkDerivation { - preferLocalBuild = true; + + nsdEnv = pkgs.buildEnv { name = "nsd-env"; - buildCommand = concatStringsSep "\n" - [ "mkdir -p $out" - (concatStrings (mapAttrsToList (zoneName: zoneOptions: '' - cat > "$out/${zoneName}" <<_EOF_ - ${zoneOptions.data} - _EOF_ - '') zoneConfigs)) - ]; + + paths = [ configFile ] + ++ mapAttrsToList (name: zone: writeZoneData name zone.data) zoneConfigs; + + postBuild = '' + echo "checking zone files" + cd $out/zones + + for zoneFile in *; do + ${nsdPkg}/sbin/nsd-checkzone "$zoneFile" "$zoneFile" || { + if grep -q \\\\\\$ "$zoneFile"; then + echo zone "$zoneFile" contains escaped dollar signes \\\$ + echo Escaping them is not needed any more. Please make shure \ + to unescape them where they prefix a variable name + fi + + exit 1 + } + done + + echo "checking configuration file" + ${nsdPkg}/sbin/nsd-checkconf $out/nsd.conf + ''; + }; + + writeZoneData = name: text: pkgs.writeTextFile { + inherit name text; + destination = "/zones/${name}"; }; - configFile = pkgs.writeText "nsd.conf" '' + + # options are ordered alphanumerically by the nixos option name + configFile = pkgs.writeTextDir "nsd.conf" '' server: - username: ${username} chroot: "${stateDir}" + username: ${username} # The directory for zonefile: files. The daemon chdirs here. zonesdir: "${stateDir}" # the list of dynamically added zones. - zonelistfile: "${stateDir}/var/zone.list" database: "${stateDir}/var/nsd.db" pidfile: "${pidFile}" xfrdfile: "${stateDir}/var/xfrd.state" xfrdir: "${stateDir}/tmp" + zonelistfile: "${stateDir}/var/zone.list" # interfaces ${forEach " ip-address: " cfg.interfaces} - server-count: ${toString cfg.serverCount} + hide-version: ${yesOrNo cfg.hideVersion} + identity: "${cfg.identity}" ip-transparent: ${yesOrNo cfg.ipTransparent} do-ip4: ${yesOrNo cfg.ipv4} + ipv4-edns-size: ${toString cfg.ipv4EDNSSize} do-ip6: ${yesOrNo cfg.ipv6} - port: ${toString cfg.port} - verbosity: ${toString cfg.verbosity} - hide-version: ${yesOrNo cfg.hideVersion} - identity: "${cfg.identity}" + ipv6-edns-size: ${toString cfg.ipv6EDNSSize} + log-time-ascii: ${yesOrNo cfg.logTimeAscii} ${maybeString "nsid: " cfg.nsid} + port: ${toString cfg.port} + reuseport: ${yesOrNo cfg.reuseport} + round-robin: ${yesOrNo cfg.roundRobin} + server-count: ${toString cfg.serverCount} + ${if cfg.statistics == null then "" else "statistics: ${toString cfg.statistics}"} tcp-count: ${toString cfg.tcpCount} tcp-query-count: ${toString cfg.tcpQueryCount} tcp-timeout: ${toString cfg.tcpTimeout} - ipv4-edns-size: ${toString cfg.ipv4EDNSSize} - ipv6-edns-size: ${toString cfg.ipv6EDNSSize} - ${if cfg.statistics == null then "" else "statistics: ${toString cfg.statistics}"} + verbosity: ${toString cfg.verbosity} + ${maybeString "version: " cfg.version} xfrd-reload-timeout: ${toString cfg.xfrdReloadTimeout} zonefiles-check: ${yesOrNo cfg.zonefilesCheck} - rrl-size: ${toString cfg.ratelimit.size} - rrl-ratelimit: ${toString cfg.ratelimit.ratelimit} - rrl-whitelist-ratelimit: ${toString cfg.ratelimit.whitelistRatelimit} - ${maybeString "rrl-slip: " cfg.ratelimit.slip} ${maybeString "rrl-ipv4-prefix-length: " cfg.ratelimit.ipv4PrefixLength} ${maybeString "rrl-ipv6-prefix-length: " cfg.ratelimit.ipv6PrefixLength} + rrl-ratelimit: ${toString cfg.ratelimit.ratelimit} + ${maybeString "rrl-slip: " cfg.ratelimit.slip} + rrl-size: ${toString cfg.ratelimit.size} + rrl-whitelist-ratelimit: ${toString cfg.ratelimit.whitelistRatelimit} ${keyConfigFile} remote-control: control-enable: ${yesOrNo cfg.remoteControl.enable} + control-key-file: "${cfg.remoteControl.controlKeyFile}" + control-cert-file: "${cfg.remoteControl.controlCertFile}" ${forEach " control-interface: " cfg.remoteControl.interfaces} - control-port: ${toString cfg.port} + control-port: ${toString cfg.remoteControl.port} server-key-file: "${cfg.remoteControl.serverKeyFile}" server-cert-file: "${cfg.remoteControl.serverCertFile}" - control-key-file: "${cfg.remoteControl.controlKeyFile}" - control-cert-file: "${cfg.remoteControl.controlCertFile}" - # zone files reside in "${zoneFiles}" linked to "${stateDir}/zones" ${concatStrings (mapAttrsToList zoneConfigFile zoneConfigs)} ${cfg.extraConfig} ''; - yesOrNo = b: if b then "yes" else "no"; + yesOrNo = b: if b then "yes" else "no"; maybeString = pre: s: if s == null then "" else ''${pre} "${s}"''; - forEach = pre: l: concatMapStrings (x: pre + x + "\n") l; + forEach = pre: l: concatMapStrings (x: pre + x + "\n") l; keyConfigFile = concatStrings (mapAttrsToList (keyName: keyOptions: '' @@ -106,22 +132,23 @@ let secret=$(cat "${keyOptions.keyFile}") dest="${stateDir}/private/${keyName}" echo " secret: \"$secret\"" > "$dest" - ${pkgs.coreutils}/bin/chown ${username}:${username} "$dest" - ${pkgs.coreutils}/bin/chmod 0400 "$dest" + chown ${username}:${username} "$dest" + chmod 0400 "$dest" '') cfg.keys); + # options are ordered alphanumerically by the nixos option name zoneConfigFile = name: zone: '' zone: name: "${name}" zonefile: "${stateDir}/zones/${name}" - ${maybeString "zonestats: " zone.zoneStats} ${maybeString "outgoing-interface: " zone.outgoingInterface} ${forEach " rrl-whitelist: " zone.rrlWhitelist} + ${maybeString "zonestats: " zone.zoneStats} + allow-axfr-fallback: ${yesOrNo zone.allowAXFRFallback} ${forEach " allow-notify: " zone.allowNotify} ${forEach " request-xfr: " zone.requestXFR} - allow-axfr-fallback: ${yesOrNo zone.allowAXFRFallback} ${forEach " notify: " zone.notify} notify-retry: ${toString zone.notifyRetry} @@ -142,7 +169,7 @@ let ); # fighting infinite recursion - zoneOptions = zoneOptionsRaw // childConfig zoneOptions1 true; + zoneOptions = zoneOptionsRaw // childConfig zoneOptions1 true; zoneOptions1 = zoneOptionsRaw // childConfig zoneOptions2 false; zoneOptions2 = zoneOptionsRaw // childConfig zoneOptions3 false; zoneOptions3 = zoneOptionsRaw // childConfig zoneOptions4 false; @@ -152,26 +179,25 @@ let childConfig = x: v: { options.children = { type = types.attrsOf x; visible = v; }; }; + # options are ordered alphanumerically zoneOptionsRaw = types.submodule { options = { - children = mkOption { - default = {}; + + allowAXFRFallback = mkOption { + type = types.bool; + default = true; description = '' - Children zones inherit all options of their parents. Attributes - defined in a child will overwrite the ones of its parent. Only - leaf zones will be actually served. This way it's possible to - define maybe zones which share most attributes without - duplicating everything. This mechanism replaces nsd's patterns - in a save and functional way. + If NSD as secondary server should be allowed to AXFR if the primary + server does not allow IXFR. ''; }; allowNotify = mkOption { - type = types.listOf types.str; - default = [ ]; - example = [ "192.0.2.0/24 NOKEY" "10.0.0.1-10.0.0.5 my_tsig_key_name" - "10.0.3.4&255.255.0.0 BLOCKED" - ]; + type = types.listOf types.str; + default = [ ]; + example = [ "192.0.2.0/24 NOKEY" "10.0.0.1-10.0.0.5 my_tsig_key_name" + "10.0.3.4&255.255.0.0 BLOCKED" + ]; description = '' Listed primary servers are allowed to notify this secondary server. <screen><![CDATA[ @@ -193,28 +219,32 @@ let ''; }; - requestXFR = mkOption { - type = types.listOf types.str; - default = []; - example = []; + children = mkOption { + default = {}; description = '' - Format: <code>[AXFR|UDP] <ip-address> <key-name | NOKEY></code> + Children zones inherit all options of their parents. Attributes + defined in a child will overwrite the ones of its parent. Only + leaf zones will be actually served. This way it's possible to + define maybe zones which share most attributes without + duplicating everything. This mechanism replaces nsd's patterns + in a save and functional way. ''; }; - allowAXFRFallback = mkOption { - type = types.bool; - default = true; + data = mkOption { + type = types.str; + default = ""; + example = ""; description = '' - If NSD as secondary server should be allowed to AXFR if the primary - server does not allow IXFR. + The actual zone data. This is the content of your zone file. + Use imports or pkgs.lib.readFile if you don't want this data in your config file. ''; }; notify = mkOption { - type = types.listOf types.str; - default = []; - example = [ "10.0.0.1@3721 my_key" "::5 NOKEY" ]; + type = types.listOf types.str; + default = []; + example = [ "10.0.0.1@3721 my_key" "::5 NOKEY" ]; description = '' This primary server will notify all given secondary servers about zone changes. @@ -231,38 +261,47 @@ let }; notifyRetry = mkOption { - type = types.int; - default = 5; + type = types.int; + default = 5; description = '' Specifies the number of retries for failed notifies. Set this along with notify. ''; }; + outgoingInterface = mkOption { + type = types.nullOr types.str; + default = null; + example = "2000::1@1234"; + description = '' + This address will be used for zone-transfere requests if configured + as a secondary server or notifications in case of a primary server. + Supply either a plain IPv4 or IPv6 address with an optional port + number (ip@port). + ''; + }; + provideXFR = mkOption { - type = types.listOf types.str; - default = []; - example = [ "192.0.2.0/24 NOKEY" "192.0.2.0/24 my_tsig_key_name" ]; + type = types.listOf types.str; + default = []; + example = [ "192.0.2.0/24 NOKEY" "192.0.2.0/24 my_tsig_key_name" ]; description = '' Allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED address range 192.0.2.0/24, 1.2.3.4&255.255.0.0, 3.0.2.20-3.0.2.40 ''; }; - outgoingInterface = mkOption { - type = types.nullOr types.str; - default = null; - example = "2000::1@1234"; + requestXFR = mkOption { + type = types.listOf types.str; + default = []; + example = []; description = '' - This address will be used for zone-transfere requests if configured - as a secondary server or notifications in case of a primary server. - Supply either a plain IPv4 or IPv6 address with an optional port - number (ip@port). + Format: <code>[AXFR|UDP] <ip-address> <key-name | NOKEY></code> ''; }; rrlWhitelist = mkOption { - type = types.listOf types.str; - default = []; + type = types.listOf types.str; + default = []; description = '' Whitelists the given rrl-types. The RRL classification types are: nxdomain, error, referral, any, @@ -270,20 +309,10 @@ let ''; }; - data = mkOption { - type = types.str; - default = ""; - example = ""; - description = '' - The actual zone data. This is the content of your zone file. - 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"; + 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 @@ -292,419 +321,470 @@ let and stats_noreset. ''; }; + }; }; in { - options = { - services.nsd = { + # options are ordered alphanumerically + options.services.nsd = { - enable = mkEnableOption "NSD authoritative DNS server"; - bind8Stats = mkEnableOption "BIND8 like statistics"; + enable = mkEnableOption "NSD authoritative DNS server"; - rootServer = mkOption { - type = types.bool; - default = false; - description = '' - Wheter if this server will be a root server (a DNS root server, you - usually don't want that). - ''; - }; + bind8Stats = mkEnableOption "BIND8 like statistics"; - interfaces = mkOption { - type = types.listOf types.str; - default = [ "127.0.0.0" "::1" ]; - description = '' - What addresses the server should listen to. - ''; - }; + extraConfig = mkOption { + type = types.str; + default = ""; + description = '' + Extra nsd config. + ''; + }; - serverCount = mkOption { - type = types.int; - default = 1; - description = '' - Number of NSD servers to fork. Put the number of CPUs to use here. - ''; - }; + hideVersion = mkOption { + type = types.bool; + default = true; + description = '' + Whether NSD should answer VERSION.BIND and VERSION.SERVER CHAOS class queries. + ''; + }; - ipTransparent = mkOption { - type = types.bool; - default = false; - description = '' - Allow binding to non local addresses. - ''; - }; + identity = mkOption { + type = types.str; + default = "unidentified server"; + description = '' + Identify the server (CH TXT ID.SERVER entry). + ''; + }; - ipv4 = mkOption { - type = types.bool; - default = true; - description = '' - Wheter to listen on IPv4 connections. - ''; - }; + interfaces = mkOption { + type = types.listOf types.str; + default = [ "127.0.0.0" "::1" ]; + description = '' + What addresses the server should listen to. + ''; + }; - ipv6 = mkOption { - type = types.bool; - default = true; - description = '' - Wheter to listen on IPv6 connections. - ''; - }; + ipTransparent = mkOption { + type = types.bool; + default = false; + description = '' + Allow binding to non local addresses. + ''; + }; - port = mkOption { - type = types.int; - default = 53; - description = '' - Port the service should bind do. - ''; - }; + ipv4 = mkOption { + type = types.bool; + default = true; + description = '' + Whether to listen on IPv4 connections. + ''; + }; - verbosity = mkOption { - type = types.int; - default = 0; - description = '' - Verbosity level. - ''; - }; + ipv4EDNSSize = mkOption { + type = types.int; + default = 4096; + description = '' + Preferred EDNS buffer size for IPv4. + ''; + }; + + ipv6 = mkOption { + type = types.bool; + default = true; + description = '' + Whether to listen on IPv6 connections. + ''; + }; + + ipv6EDNSSize = mkOption { + type = types.int; + default = 4096; + description = '' + Preferred EDNS buffer size for IPv6. + ''; + }; + + logTimeAscii = mkOption { + type = types.bool; + default = true; + description = '' + Log time in ascii, if false then in unix epoch seconds. + ''; + }; + + nsid = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + NSID identity (hex string, or "ascii_somestring"). + ''; + }; + + port = mkOption { + type = types.int; + default = 53; + description = '' + Port the service should bind do. + ''; + }; + + reuseport = mkOption { + type = types.bool; + default = pkgs.stdenv.isLinux; + description = '' + Whether to enable SO_REUSEPORT on all used sockets. This lets multiple + processes bind to the same port. This speeds up operation especially + if the server count is greater than one and makes fast restarts less + prone to fail + ''; + }; + + rootServer = mkOption { + type = types.bool; + default = false; + description = '' + Whether this server will be a root server (a DNS root server, you + usually don't want that). + ''; + }; + + roundRobin = mkEnableOption "round robin rotation of records"; + + serverCount = mkOption { + type = types.int; + default = 1; + description = '' + Number of NSD servers to fork. Put the number of CPUs to use here. + ''; + }; + + statistics = mkOption { + type = types.nullOr types.int; + default = null; + description = '' + Statistics are produced every number of seconds. Prints to log. + If null no statistics are logged. + ''; + }; + + tcpCount = mkOption { + type = types.int; + default = 100; + description = '' + Maximum number of concurrent TCP connections per server. + ''; + }; + + tcpQueryCount = mkOption { + type = types.int; + default = 0; + description = '' + Maximum number of queries served on a single TCP connection. + 0 means no maximum. + ''; + }; + + tcpTimeout = mkOption { + type = types.int; + default = 120; + description = '' + TCP timeout in seconds. + ''; + }; + + verbosity = mkOption { + type = types.int; + default = 0; + description = '' + Verbosity level. + ''; + }; + + version = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + The version string replied for CH TXT version.server and version.bind + queries. Will use the compiled package version on null. + See hideVersion for enabling/disabling this responses. + ''; + }; + + xfrdReloadTimeout = mkOption { + type = types.int; + default = 1; + description = '' + Number of seconds between reloads triggered by xfrd. + ''; + }; + + zonefilesCheck = mkOption { + type = types.bool; + default = true; + description = '' + Whether to check mtime of all zone files on start and sighup. + ''; + }; + + + keys = mkOption { + type = types.attrsOf (types.submodule { + options = { + + algorithm = mkOption { + type = types.str; + default = "hmac-sha256"; + description = '' + Authentication algorithm for this key. + ''; + }; + + keyFile = mkOption { + type = types.path; + description = '' + Path to the file which contains the actual base64 encoded + key. The key will be copied into "${stateDir}/private" before + NSD starts. The copied file is only accessibly by the NSD + user. + ''; + }; + + }; + }); + default = {}; + example = literalExample '' + { "tsig.example.org" = { + algorithm = "hmac-md5"; + keyFile = "/path/to/my/key"; + }; + } + ''; + description = '' + Define your TSIG keys here. + ''; + }; + + + ratelimit = { + + enable = mkEnableOption "ratelimit capabilities"; - hideVersion = mkOption { - type = types.bool; - default = true; + ipv4PrefixLength = mkOption { + type = types.nullOr types.int; + default = null; description = '' - Wheter NSD should answer VERSION.BIND and VERSION.SERVER CHAOS class queries. + IPv4 prefix length. Addresses are grouped by netblock. ''; }; - identity = mkOption { - type = types.str; - default = "unidentified server"; + ipv6PrefixLength = mkOption { + type = types.nullOr types.int; + default = null; description = '' - Identify the server (CH TXT ID.SERVER entry). + IPv6 prefix length. Addresses are grouped by netblock. ''; }; - nsid = mkOption { - type = types.nullOr types.str; - default = null; + ratelimit = mkOption { + type = types.int; + default = 200; description = '' - NSID identity (hex string, or "ascii_somestring"). + Max qps allowed from any query source. + 0 means unlimited. With an verbosity of 2 blocked and + unblocked subnets will be logged. ''; }; - tcpCount = mkOption { - type = types.int; - default = 100; + slip = mkOption { + type = types.nullOr types.int; + default = null; description = '' - Maximum number of concurrent TCP connections per server. + Number of packets that get discarded before replying a SLIP response. + 0 disables SLIP responses. 1 will make every response a SLIP response. ''; }; - tcpQueryCount = mkOption { - type = types.int; - default = 0; + size = mkOption { + type = types.int; + default = 1000000; description = '' - Maximum number of queries served on a single TCP connection. - 0 means no maximum. + Size of the hashtable. More buckets use more memory but lower + the chance of hash hash collisions. ''; }; - tcpTimeout = mkOption { - type = types.int; - default = 120; + whitelistRatelimit = mkOption { + type = types.int; + default = 2000; description = '' - TCP timeout in seconds. + Max qps allowed from whitelisted sources. + 0 means unlimited. Set the rrl-whitelist option for specific + queries to apply this limit instead of the default to them. ''; }; - ipv4EDNSSize = mkOption { - type = types.int; - default = 4096; + }; + + + remoteControl = { + + enable = mkEnableOption "remote control via nsd-control"; + + controlCertFile = mkOption { + type = types.path; + default = "/etc/nsd/nsd_control.pem"; description = '' - Preferred EDNS buffer size for IPv4. + Path to the client certificate signed with the server certificate. + This file is used by nsd-control and generated by nsd-control-setup. ''; }; - ipv6EDNSSize = mkOption { - type = types.int; - default = 4096; + controlKeyFile = mkOption { + type = types.path; + default = "/etc/nsd/nsd_control.key"; description = '' - Preferred EDNS buffer size for IPv6. + Path to the client private key, which is used by nsd-control + but not by the server. This file is generated by nsd-control-setup. ''; }; - statistics = mkOption { - type = types.nullOr types.int; - default = null; + interfaces = mkOption { + type = types.listOf types.str; + default = [ "127.0.0.1" "::1" ]; description = '' - Statistics are produced every number of seconds. Prints to log. - If null no statistics are logged. + Which interfaces NSD should bind to for remote control. ''; }; - xfrdReloadTimeout = mkOption { - type = types.int; - default = 1; + port = mkOption { + type = types.int; + default = 8952; description = '' - Number of seconds between reloads triggered by xfrd. + Port number for remote control operations (uses TLS over TCP). ''; }; - zonefilesCheck = mkOption { - type = types.bool; - default = true; + serverCertFile = mkOption { + type = types.path; + default = "/etc/nsd/nsd_server.pem"; description = '' - Wheter to check mtime of all zone files on start and sighup. + Path to the server self signed certificate, which is used by the server + but and by nsd-control. This file is generated by nsd-control-setup. ''; }; - - extraConfig = mkOption { - type = types.str; - default = ""; + serverKeyFile = mkOption { + type = types.path; + default = "/etc/nsd/nsd_server.key"; description = '' - Extra nsd config. + Path to the server private key, which is used by the server + but not by nsd-control. This file is generated by nsd-control-setup. ''; }; + }; - ratelimit = { - enable = mkEnableOption "ratelimit capabilities"; - - size = mkOption { - type = types.int; - default = 1000000; - description = '' - Size of the hashtable. More buckets use more memory but lower - the chance of hash hash collisions. - ''; - }; - - ratelimit = mkOption { - type = types.int; - default = 200; - description = '' - Max qps allowed from any query source. - 0 means unlimited. With an verbosity of 2 blocked and - unblocked subnets will be logged. - ''; - }; - - whitelistRatelimit = mkOption { - type = types.int; - default = 2000; - description = '' - Max qps allowed from whitelisted sources. - 0 means unlimited. Set the rrl-whitelist option for specific - queries to apply this limit instead of the default to them. - ''; - }; - - slip = mkOption { - type = types.nullOr types.int; - default = null; - description = '' - Number of packets that get discarded before replying a SLIP response. - 0 disables SLIP responses. 1 will make every response a SLIP response. - ''; - }; - - ipv4PrefixLength = mkOption { - type = types.nullOr types.int; - default = null; - description = '' - IPv4 prefix length. Addresses are grouped by netblock. - ''; - }; - - ipv6PrefixLength = mkOption { - type = types.nullOr types.int; - default = null; - description = '' - IPv6 prefix length. Addresses are grouped by netblock. - ''; - }; - }; - - - remoteControl = { - enable = mkEnableOption "remote control via nsd-control"; - - interfaces = mkOption { - type = types.listOf types.str; - default = [ "127.0.0.1" "::1" ]; - description = '' - Which interfaces NSD should bind to for remote control. - ''; - }; - - port = mkOption { - type = types.int; - default = 8952; - description = '' - Port number for remote control operations (uses TLS over TCP). - ''; - }; - - serverKeyFile = mkOption { - type = types.path; - default = "/etc/nsd/nsd_server.key"; - description = '' - Path to the server private key, which is used by the server - but not by nsd-control. This file is generated by nsd-control-setup. - ''; - }; - - serverCertFile = mkOption { - type = types.path; - default = "/etc/nsd/nsd_server.pem"; - description = '' - Path to the server self signed certificate, which is used by the server - but and by nsd-control. This file is generated by nsd-control-setup. - ''; - }; - - controlKeyFile = mkOption { - type = types.path; - default = "/etc/nsd/nsd_control.key"; - description = '' - Path to the client private key, which is used by nsd-control - but not by the server. This file is generated by nsd-control-setup. - ''; - }; - - controlCertFile = mkOption { - type = types.path; - default = "/etc/nsd/nsd_control.pem"; - description = '' - Path to the client certificate signed with the server certificate. - This file is used by nsd-control and generated by nsd-control-setup. - ''; - }; - }; - - - keys = mkOption { - type = types.attrsOf (types.submodule { - options = { - algorithm = mkOption { - type = types.str; - default = "hmac-sha256"; - description = '' - Authentication algorithm for this key. - ''; - }; - - keyFile = mkOption { - type = types.path; - description = '' - Path to the file which contains the actual base64 encoded - key. The key will be copied into "${stateDir}/private" before - NSD starts. The copied file is only accessibly by the NSD - user. - ''; - }; - }; - }); - default = {}; - example = { - "tsig.example.org" = { - algorithm = "hmac-md5"; - secret = "aaaaaabbbbbbccccccdddddd"; - }; - }; - description = '' - Define your TSIG keys here. - ''; - }; - zones = mkOption { - type = types.attrsOf zoneOptions; - default = {}; - example = { - "serverGroup1" = { + zones = mkOption { + type = types.attrsOf zoneOptions; + default = {}; + example = literalExample '' + { "serverGroup1" = { provideXFR = [ "10.1.2.3 NOKEY" ]; children = { "example.com." = { - data = '' + data = ''' $ORIGIN example.com. $TTL 86400 @ IN SOA a.ns.example.com. admin.example.com. ( ... - ''; + '''; }; "example.org." = { - data = '' + data = ''' $ORIGIN example.org. $TTL 86400 @ IN SOA a.ns.example.com. admin.example.com. ( ... - ''; + '''; }; }; }; "example.net." = { provideXFR = [ "10.3.2.1 NOKEY" ]; - data = ''...''; + data = ''' + ... + '''; }; - }; - description = '' - Define your zones here. Zones can cascade other zones and therefore - inherit settings from parent zones. Look at the definition of - children to learn about inheritance and child zones. - The given example will define 3 zones (example.(com|org|net).). Both - example.com. and example.org. inherit their configuration from - serverGroup1. - ''; - }; - + } + ''; + description = '' + Define your zones here. Zones can cascade other zones and therefore + inherit settings from parent zones. Look at the definition of + children to learn about inheritance and child zones. + The given example will define 3 zones (example.(com|org|net).). Both + example.com. and example.org. inherit their configuration from + serverGroup1. + ''; }; + }; config = mkIf cfg.enable { users.extraGroups = singleton { name = username; - gid = config.ids.gids.nsd; + gid = config.ids.gids.nsd; }; users.extraUsers = singleton { - name = username; + name = username; description = "NSD service user"; - home = stateDir; + home = stateDir; createHome = true; - uid = config.ids.uids.nsd; - group = username; + uid = config.ids.uids.nsd; + group = username; }; systemd.services.nsd = { description = "NSD authoritative only domain name service"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; + + after = [ "keys.target" "network.target" ]; + wantedBy = [ "multi-user.target" ]; + wants = [ "keys.target" ]; serviceConfig = { - PIDFile = pidFile; - Restart = "always"; - ExecStart = "${nsdPkg}/sbin/nsd -d -c ${configFile}"; + ExecStart = "${nsdPkg}/sbin/nsd -d -c ${nsdEnv}/nsd.conf"; + PIDFile = pidFile; + Restart = "always"; + RestartSec = "4s"; + StartLimitBurst = 4; + StartLimitInterval = "5min"; }; preStart = '' - ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/private" - ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/tmp" - ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/var" + rm -Rf "${stateDir}/private/" + rm -Rf "${stateDir}/tmp/" - ${pkgs.coreutils}/bin/touch "${stateDir}/don't touch anything in here" + mkdir -m 0700 -p "${stateDir}/private" + mkdir -m 0700 -p "${stateDir}/tmp" + mkdir -m 0700 -p "${stateDir}/var" - ${pkgs.coreutils}/bin/rm -f "${stateDir}/private/"* - ${pkgs.coreutils}/bin/rm -f "${stateDir}/tmp/"* + cat > "${stateDir}/don't touch anything in here" << EOF + Everything in this directory except NSD's state in var is + automatically generated and will be purged and redeployed + by the nsd.service pre-start script. + EOF - ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/private" - ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/tmp" - ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/var" + chown ${username}:${username} -R "${stateDir}/private" + chown ${username}:${username} -R "${stateDir}/tmp" + chown ${username}:${username} -R "${stateDir}/var" - ${pkgs.coreutils}/bin/rm -rf "${stateDir}/zones" - ${pkgs.coreutils}/bin/cp -r "${zoneFiles}" "${stateDir}/zones" + rm -rf "${stateDir}/zones" + cp -rL "${nsdEnv}/zones" "${stateDir}/zones" ${copyKeys} ''; diff --git a/nixos/modules/services/networking/pdnsd.nix b/nixos/modules/services/networking/pdnsd.nix new file mode 100644 index 00000000000..f4467b81895 --- /dev/null +++ b/nixos/modules/services/networking/pdnsd.nix @@ -0,0 +1,93 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.pdnsd; + pdnsd = pkgs.pdnsd; + pdnsdUser = "pdnsd"; + pdnsdGroup = "pdnsd"; + pdnsdConf = pkgs.writeText "pdnsd.conf" + '' + global { + run_as=${pdnsdUser}; + cache_dir="${cfg.cacheDir}"; + ${cfg.globalConfig} + } + + server { + ${cfg.serverConfig} + } + ${cfg.extraConfig} + ''; +in + +{ options = + { services.pdnsd = + { enable = mkEnableOption "pdnsd"; + + cacheDir = mkOption { + type = types.str; + default = "/var/cache/pdnsd"; + description = "Directory holding the pdnsd cache"; + }; + + globalConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Global configuration that should be added to the global directory + of <literal>pdnsd.conf</literal>. + ''; + }; + + serverConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Server configuration that should be added to the server directory + of <literal>pdnsd.conf</literal>. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra configuration directives that should be added to + <literal>pdnsd.conf</literal>. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + users.extraUsers = singleton { + name = pdnsdUser; + uid = config.ids.uids.pdnsd; + group = pdnsdGroup; + description = "pdnsd user"; + }; + + users.extraGroups = singleton { + name = pdnsdGroup; + gid = config.ids.gids.pdnsd; + }; + + systemd.services.pdnsd = + { wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + preStart = + '' + mkdir -p "${cfg.cacheDir}" + touch "${cfg.cacheDir}/pdnsd.cache" + chown -R ${pdnsdUser}:${pdnsdGroup} "${cfg.cacheDir}" + ''; + description = "pdnsd"; + serviceConfig = + { + ExecStart = "${pdnsd}/bin/pdnsd -c ${pdnsdConf}"; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index ba3efc8c0c2..5971a5a250d 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -263,7 +263,7 @@ in serviceConfig = { ExecStart = - "${cfgc.package}/sbin/sshd " + (optionalString cfg.startWhenNeeded "-i ") + + "${cfgc.package}/bin/sshd " + (optionalString cfg.startWhenNeeded "-i ") + "-f ${pkgs.writeText "sshd_config" cfg.extraConfig}"; KillMode = "process"; } // (if cfg.startWhenNeeded then { @@ -304,7 +304,7 @@ in services.openssh.authorizedKeysFiles = [ ".ssh/authorized_keys" ".ssh/authorized_keys2" "/etc/ssh/authorized_keys.d/%u" ]; - services.openssh.extraConfig = + services.openssh.extraConfig = mkOrder 0 '' PidFile /run/sshd.pid diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix index f5d5e1d2556..67b90516b99 100644 --- a/nixos/modules/services/networking/syncthing.nix +++ b/nixos/modules/services/networking/syncthing.nix @@ -33,6 +33,17 @@ in ''; }; + all_proxy = mkOption { + type = types.string; + default = ""; + example = "socks5://address.com:1234"; + description = '' + Overwrites all_proxy environment variable for the syncthing process to + the given value. This is normaly used to let relay client connect + through SOCKS5 proxy server. + ''; + }; + dataDir = mkOption { default = "/var/lib/syncthing"; description = '' @@ -51,7 +62,6 @@ in }; - }; }; @@ -66,8 +76,13 @@ in description = "Syncthing service"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - environment.STNORESTART = "yes"; # do not self-restart - environment.STNOUPGRADE = "yes"; + environment = { + STNORESTART = "yes"; # do not self-restart + STNOUPGRADE = "yes"; + } // + (config.networking.proxy.envVars) // + (if cfg.all_proxy != "" then { all_proxy = cfg.all_proxy; } else {}); + serviceConfig = { User = "${cfg.user}"; PermissionsStartOnly = true; diff --git a/nixos/modules/services/networking/tlsdated.nix b/nixos/modules/services/networking/tlsdated.nix index ff7d0178a81..757cce28760 100644 --- a/nixos/modules/services/networking/tlsdated.nix +++ b/nixos/modules/services/networking/tlsdated.nix @@ -26,6 +26,7 @@ in extraOptions = mkOption { type = types.string; + default = ""; description = '' Additional command line arguments to pass to tlsdated. ''; diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix index 73b10c1d561..89762fe5248 100644 --- a/nixos/modules/services/networking/unbound.nix +++ b/nixos/modules/services/networking/unbound.nix @@ -16,6 +16,11 @@ let "forward-zone:\n name: .\n" + concatMapStrings (x: " forward-addr: ${x}\n") cfg.forwardAddresses; + rootTrustAnchorFile = "${stateDir}/root.key"; + + trustAnchor = optionalString cfg.enableRootTrustAnchor + "auto-trust-anchor-file: ${rootTrustAnchorFile}"; + confFile = pkgs.writeText "unbound.conf" '' server: directory: "${stateDir}" @@ -24,6 +29,7 @@ let pidfile: "" ${interfaces} ${access} + ${trustAnchor} ${cfg.extraConfig} ${forward} ''; @@ -38,28 +44,39 @@ in services.unbound = { enable = mkOption { - default = false; - description = "Whether to enable the Unbound domain name server."; + default = false; + type = types.bool; + description = "Whether to enable the Unbound domain name server."; }; allowedAccess = mkOption { - default = ["127.0.0.0/24"]; - description = "What networks are allowed to use unbound as a resolver."; + default = ["127.0.0.0/24"]; + type = types.listOf types.str; + description = "What networks are allowed to use unbound as a resolver."; }; interfaces = mkOption { - default = [ "127.0.0.1" "::1" ]; - description = "What addresses the server should listen on."; + default = [ "127.0.0.1" "::1" ]; + type = types.listOf types.str; + description = "What addresses the server should listen on."; }; forwardAddresses = mkOption { - default = [ ]; - description = "What servers to forward queries to."; + default = [ ]; + type = types.listOf types.str; + description = "What servers to forward queries to."; + }; + + enableRootTrustAnchor = mkOption { + default = true; + type = types.bool; + description = "Use and update root trust anchor for DNSSEC validation."; }; extraConfig = mkOption { - default = ""; - description = "Extra lines of unbound config."; + default = ""; + type = types.str; + description = "Extra lines of unbound config."; }; }; @@ -88,14 +105,15 @@ in preStart = '' mkdir -m 0755 -p ${stateDir}/dev/ - cp ${confFile} ${stateDir}/unbound.conf - chown unbound ${stateDir} - touch ${stateDir}/dev/random + cp ${confFile} ${stateDir}/unbound.conf + ${pkgs.unbound}/bin/unbound-anchor -a ${rootTrustAnchorFile} + chown unbound ${stateDir} ${rootTrustAnchorFile} + touch ${stateDir}/dev/random ${pkgs.utillinux}/bin/mount --bind -n /dev/random ${stateDir}/dev/random ''; serviceConfig = { - ExecStart = "${pkgs.unbound}/sbin/unbound -d -c ${stateDir}/unbound.conf"; + ExecStart = "${pkgs.unbound}/bin/unbound -d -c ${stateDir}/unbound.conf"; ExecStopPost="${pkgs.utillinux}/bin/umount ${stateDir}/dev/random"; }; }; diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix index 1558c583289..a8f445a2c73 100644 --- a/nixos/modules/services/networking/wpa_supplicant.nix +++ b/nixos/modules/services/networking/wpa_supplicant.nix @@ -78,10 +78,11 @@ in { ''; default = {}; example = literalExample '' - echelon = { - psk = "abcdefgh"; - }; - "free.wifi" = {}; + { echelon = { + psk = "abcdefgh"; + }; + "free.wifi" = {}; + } ''; }; @@ -127,6 +128,7 @@ in { in { description = "WPA Supplicant"; + after = [ "network-interfaces.target" ]; wantedBy = [ "network.target" ]; path = [ pkgs.wpa_supplicant ]; diff --git a/nixos/modules/services/networking/zerotierone.nix b/nixos/modules/services/networking/zerotierone.nix index 886ea18d980..6237f95b127 100644 --- a/nixos/modules/services/networking/zerotierone.nix +++ b/nixos/modules/services/networking/zerotierone.nix @@ -21,10 +21,9 @@ in chown -R root:root /var/lib/zerotier-one ''; serviceConfig = { - Type = "forking"; - User = "root"; - PIDFile = "/var/lib/zerotier-one/zerotier-one.pid"; - ExecStart = "${pkgs.zerotierone}/bin/zerotier-one -d"; + ExecStart = "${pkgs.zerotierone}/bin/zerotier-one"; + Restart = "always"; + KillMode = "process"; }; }; environment.systemPackages = [ pkgs.zerotierone ]; diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix index 9411a225beb..59416560655 100644 --- a/nixos/modules/services/printing/cupsd.nix +++ b/nixos/modules/services/printing/cupsd.nix @@ -310,7 +310,7 @@ in [ ! -e "/var/lib/cups/$i" ] && ln -s "${rootdir}/etc/cups/$i" "/var/lib/cups/$i" done ${optionalString cfg.gutenprint '' - ${gutenprint}/bin/cups-genppdupdate + ${gutenprint}/bin/cups-genppdupdate -p /etc/cups/ppd ''} ''; }; diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix index 548aee29b26..e4e5c1253b7 100644 --- a/nixos/modules/services/security/clamav.nix +++ b/nixos/modules/services/security/clamav.nix @@ -16,6 +16,7 @@ let ${cfg.daemon.extraConfig} ''; + pkg = pkgs.clamav.override { freshclamConf = cfg.updater.config; }; in { options = { @@ -54,7 +55,7 @@ in }; config = mkIf cfg.updater.enable or cfg.daemon.enable { - environment.systemPackages = [ pkgs.clamav ]; + environment.systemPackages = [ pkg ]; users.extraUsers = singleton { name = clamavUser; uid = config.ids.uids.clamav; @@ -76,7 +77,7 @@ in systemd.services.clamd = mkIf cfg.daemon.enable { description = "ClamAV daemon (clamd)"; - path = [ pkgs.clamav ]; + path = [ pkg ]; after = [ "network.target" "freshclam.service" ]; requires = [ "freshclam.service" ]; wantedBy = [ "multi-user.target" ]; @@ -87,7 +88,7 @@ in chown ${clamavUser}:${clamavGroup} ${runDir} ''; serviceConfig = { - ExecStart = "${pkgs.clamav}/bin/clamd --config-file=${clamdConfigFile}"; + ExecStart = "${pkg}/bin/clamd --config-file=${clamdConfigFile}"; Type = "forking"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; Restart = "on-failure"; @@ -100,13 +101,13 @@ in description = "ClamAV updater (freshclam)"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - path = [ pkgs.clamav ]; + path = [ pkg ]; preStart = '' mkdir -m 0755 -p ${stateDir} chown ${clamavUser}:${clamavGroup} ${stateDir} ''; serviceConfig = { - ExecStart = "${pkgs.clamav}/bin/freshclam --daemon --config-file=${pkgs.writeText "freshclam.conf" cfg.updater.config}"; + ExecStart = "${pkg}/bin/freshclam --daemon --config-file=${pkgs.writeText "freshclam.conf" cfg.updater.config}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; Restart = "on-failure"; RestartSec = "10s"; diff --git a/nixos/modules/services/security/fail2ban.nix b/nixos/modules/services/security/fail2ban.nix index 1d3e18dcab2..afbd81be91f 100644 --- a/nixos/modules/services/security/fail2ban.nix +++ b/nixos/modules/services/security/fail2ban.nix @@ -50,20 +50,20 @@ in jails = mkOption { default = { }; - example = - { "apache-nohome-iptables" = - '' - # Block an IP address if it accesses a non-existent - # home directory more than 5 times in 10 minutes, - # since that indicates that it's scanning. - filter = apache-nohome - action = iptables-multiport[name=HTTP, port="http,https"] - logpath = /var/log/httpd/error_log* - findtime = 600 - bantime = 600 - maxretry = 5 - ''; - }; + example = literalExample '' + { apache-nohome-iptables = ''' + # Block an IP address if it accesses a non-existent + # home directory more than 5 times in 10 minutes, + # since that indicates that it's scanning. + filter = apache-nohome + action = iptables-multiport[name=HTTP, port="http,https"] + logpath = /var/log/httpd/error_log* + findtime = 600 + bantime = 600 + maxretry = 5 + '''; + } + ''; type = types.attrsOf types.lines; description = '' diff --git a/nixos/modules/services/security/haka.nix b/nixos/modules/services/security/haka.nix index 4f2bdd29cc4..f48a79b1f7f 100644 --- a/nixos/modules/services/security/haka.nix +++ b/nixos/modules/services/security/haka.nix @@ -59,6 +59,7 @@ in package = mkOption { default = pkgs.haka; + defaultText = "pkgs.haka"; type = types.package; description = " Which Haka derivation to use. diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix index c4dc6512a0d..59ef915af6d 100644 --- a/nixos/modules/services/torrent/transmission.nix +++ b/nixos/modules/services/torrent/transmission.nix @@ -21,7 +21,7 @@ let else toString ''"${x}"''; # for users in group "transmission" to have access to torrents - fullSettings = { download-dir = downloadDir; incomplete-dir = incompleteDir; } // cfg.settings // { umask = 2; }; + fullSettings = { umask = 2; download-dir = downloadDir; incomplete-dir = incompleteDir; } // cfg.settings; in { options = { diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix index 880cd9f39c4..ed66ea9fc87 100644 --- a/nixos/modules/services/web-servers/apache-httpd/default.nix +++ b/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -173,7 +173,8 @@ let SSLRandomSeed connect builtin SSLProtocol All -SSLv2 -SSLv3 - SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!EXP + SSLCipherSuite HIGH:!aNULL:!MD5:!EXP + SSLHonorCipherOrder on ''; diff --git a/nixos/modules/services/web-servers/apache-httpd/moodle.nix b/nixos/modules/services/web-servers/apache-httpd/moodle.nix index 84c8281ecd8..87b1fba5aa1 100644 --- a/nixos/modules/services/web-servers/apache-httpd/moodle.nix +++ b/nixos/modules/services/web-servers/apache-httpd/moodle.nix @@ -46,16 +46,16 @@ let ''; # Unpack Moodle and put the config file in its root directory. moodleRoot = pkgs.stdenv.mkDerivation rec { - name= "moodle-2.8.5"; + name= "moodle-2.8.10"; src = pkgs.fetchurl { url = "https://download.moodle.org/stable28/${name}.tgz"; - sha256 = "1a159a193010cddedce10ee009184502e6f732e4d7c85167d8597fe5dff9e190"; + sha256 = "0c3r5081ipcwc9s6shakllnrkd589y2ln5z5m1q09l4h6a7cy4z2"; }; buildPhase = '' - ''; + ''; installPhase = '' @@ -132,7 +132,7 @@ in cleartext in the Nix store! ''; }; - + dbPrefix = mkOption { default = "mdl_"; example = "my_other_mdl_"; @@ -158,7 +158,7 @@ in type = types.path; }; - + extraConfig = mkOption { default = ""; example = diff --git a/nixos/modules/services/web-servers/apache-httpd/owncloud.nix b/nixos/modules/services/web-servers/apache-httpd/owncloud.nix index 5633f30e4a8..94e85f1f428 100644 --- a/nixos/modules/services/web-servers/apache-httpd/owncloud.nix +++ b/nixos/modules/services/web-servers/apache-httpd/owncloud.nix @@ -370,6 +370,7 @@ rec { package = mkOption { type = types.package; default = pkgs.owncloud70; + defaultText = "pkgs.owncloud70"; example = literalExample "pkgs.owncloud70"; description = '' PostgreSQL package to use. diff --git a/nixos/modules/services/web-servers/phpfpm.nix b/nixos/modules/services/web-servers/phpfpm.nix index bdd41ed702b..6a60000ce19 100644 --- a/nixos/modules/services/web-servers/phpfpm.nix +++ b/nixos/modules/services/web-servers/phpfpm.nix @@ -46,24 +46,26 @@ in { phpIni = mkOption { type = types.path; - description = "PHP configuration file to use."; + default = "${cfg.phpPackage}/etc/php-recommended.ini"; + description = "php.ini file to use."; }; poolConfigs = mkOption { type = types.attrsOf types.lines; default = {}; - example = { - mypool = '' - listen = /run/phpfpm/mypool - user = nobody - pm = dynamic - pm.max_children = 75 - pm.start_servers = 10 - pm.min_spare_servers = 5 - pm.max_spare_servers = 20 - pm.max_requests = 500 - ''; - }; + example = literalExample '' + { mypool = ''' + listen = /run/phpfpm/mypool + user = nobody + pm = dynamic + pm.max_children = 75 + pm.start_servers = 10 + pm.min_spare_servers = 5 + pm.max_spare_servers = 20 + pm.max_requests = 500 + '''; + } + ''; description = '' A mapping between PHP FPM pool names and their configurations. See the documentation on <literal>php-fpm.conf</literal> for @@ -87,7 +89,5 @@ in { }; }; - services.phpfpm.phpIni = mkDefault "${cfg.phpPackage}/etc/php-recommended.ini"; - }; } diff --git a/nixos/modules/services/web-servers/uwsgi.nix b/nixos/modules/services/web-servers/uwsgi.nix index 3e18a6f0e98..e6c25e6215c 100644 --- a/nixos/modules/services/web-servers/uwsgi.nix +++ b/nixos/modules/services/web-servers/uwsgi.nix @@ -5,43 +5,85 @@ with lib; let cfg = config.services.uwsgi; - python2Pkgs = pkgs.python2Packages.override { - python = pkgs.uwsgi.python2; - self = python2Pkgs; + uwsgi = pkgs.uwsgi.override { + plugins = cfg.plugins; }; - python3Pkgs = pkgs.python3Packages.override { - python = pkgs.uwsgi.python3; - self = python3Pkgs; - }; + buildCfg = name: c: + let + plugins = + if any (n: !any (m: m == n) cfg.plugins) (c.plugins or []) + then throw "`plugins` attribute in UWSGI configuration contains plugins not in config.services.uwsgi.plugins" + else c.plugins or cfg.plugins; + + hasPython = v: filter (n: n == "python${v}") plugins != []; + hasPython2 = hasPython "2"; + hasPython3 = hasPython "3"; + + python = + if hasPython2 && hasPython3 then + throw "`plugins` attribute in UWSGI configuration shouldn't contain both python2 and python3" + else if hasPython2 then uwsgi.python2 + else if hasPython3 then uwsgi.python3 + else null; + + pythonPackages = pkgs.pythonPackages.override { + inherit python; + self = pythonPackages; + }; - buildCfg = c: if builtins.typeOf c != "set" then builtins.readFile c else builtins.toJSON { - uwsgi = - if c.type == "normal" - then { - pythonpath = - (if c ? python2Packages - then builtins.map (x: "${x}/${pkgs.uwsgi.python2.sitePackages}") (c.python2Packages python2Pkgs) - else []) - ++ (if c ? python3Packages - then builtins.map (x: "${x}/${pkgs.uwsgi.python3.sitePackages}") (c.python3Packages python3Pkgs) - else []); - plugins = cfg.plugins; - } // removeAttrs c [ "type" "python2Packages" "python3Packages" ] - else if c.type == "emperor" - then { - emperor = if builtins.typeOf c.vassals != "set" then c.vassals - else pkgs.buildEnv { - name = "vassals"; - paths = mapAttrsToList (n: c: pkgs.writeTextDir "${n}.json" (buildCfg c)) c.vassals; - }; - } // removeAttrs c [ "type" "vassals" ] - else abort "type should be either 'normal' or 'emperor'"; - }; + json = builtins.toJSON { + uwsgi = + if c.type == "normal" + then { + inherit plugins; + } // removeAttrs c [ "type" "pythonPackages" ] + // optionalAttrs (python != null) { + pythonpath = "@PYTHONPATH@"; + env = (c.env or {}) // { + PATH = optionalString (c ? env.PATH) "${c.env.PATH}:" + "@PATH@"; + }; + } + else if c.type == "emperor" + then { + emperor = if builtins.typeOf c.vassals != "set" then c.vassals + else pkgs.buildEnv { + name = "vassals"; + paths = mapAttrsToList buildCfg c.vassals; + }; + } // removeAttrs c [ "type" "vassals" ] + else throw "`type` attribute in UWSGI configuration should be either 'normal' or 'emperor'"; + }; - uwsgi = pkgs.uwsgi.override { - plugins = cfg.plugins; - }; + in + if python == null || c.type != "normal" + then pkgs.writeTextDir "${name}.json" json + else pkgs.stdenv.mkDerivation { + name = "uwsgi-config"; + inherit json; + passAsFile = [ "json" ]; + nativeBuildInputs = [ pythonPackages.wrapPython ]; + pythonInputs = (c.pythonPackages or (self: [])) pythonPackages; + + buildCommand = '' + mkdir $out + declare -A pythonPathsSeen=() + program_PYTHONPATH= + program_PATH= + if [ -n "$pythonInputs" ]; then + for i in $pythonInputs; do + _addToPythonPath $i + done + fi + # A hack to replace "@PYTHONPATH@" with a JSON list + if [ -n "$program_PYTHONPATH" ]; then + program_PYTHONPATH="\"''${program_PYTHONPATH//:/\",\"}\"" + fi + substitute $jsonPath $out/${name}.json \ + --replace '"@PYTHONPATH@"' "[$program_PYTHONPATH]" \ + --subst-var-by PATH "$program_PATH" + ''; + }; in { @@ -71,21 +113,24 @@ in { vassals = { moin = { type = "normal"; - python2Packages = self: with self; [ moinmoin ]; + pythonPackages = self: with self; [ moinmoin ]; socket = "${config.services.uwsgi.runDir}/uwsgi.sock"; }; }; } ''; description = '' - uWSGI configuration. This awaits either a path to file or a set which will be made into one. - If given a set, it awaits an attribute <literal>type</literal> which can be either <literal>normal</literal> - or <literal>emperor</literal>. + uWSGI configuration. It awaits an attribute <literal>type</literal> inside which can be either + <literal>normal</literal> or <literal>emperor</literal>. + + For <literal>normal</literal> mode you can specify <literal>pythonPackages</literal> as a function + from libraries set into a list of libraries. <literal>pythonpath</literal> will be set accordingly. - For <literal>normal</literal> mode you can specify <literal>python2Packages</literal> and - <literal>python3Packages</literal> as functions from libraries set into lists of libraries. For <literal>emperor</literal> mode, you should use <literal>vassals</literal> attribute which should be either a set of names and configurations or a path to a directory. + + Other attributes will be used in configuration file as-is. Notice that you can redefine + <literal>plugins</literal> setting here. ''; }; @@ -118,7 +163,7 @@ in { ''; serviceConfig = { Type = "notify"; - ExecStart = "${uwsgi}/bin/uwsgi --uid ${cfg.user} --gid ${cfg.group} --json ${pkgs.writeText "uwsgi.json" (buildCfg cfg.instance)}"; + ExecStart = "${uwsgi}/bin/uwsgi --uid ${cfg.user} --gid ${cfg.group} --json ${buildCfg "server" cfg.instance}/server.json"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID"; NotifyAccess = "main"; diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix index 6cb4f3acba8..b112fc2422a 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -27,19 +27,24 @@ let nixos-gsettings-desktop-schemas = pkgs.stdenv.mkDerivation { name = "nixos-gsettings-desktop-schemas"; - buildInputs = [ pkgs.nixos-artwork ]; buildCommand = '' - mkdir -p $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas - cp -rf ${gnome3.gsettings_desktop_schemas}/share/gsettings-schemas/gsettings-desktop-schemas*/glib-2.0 $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas/ - chmod -R a+w $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas - cat - > $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas/glib-2.0/schemas/nixos-defaults.gschema.override <<- EOF + mkdir -p $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas + cp -rf ${gnome3.gsettings_desktop_schemas}/share/gsettings-schemas/gsettings-desktop-schemas*/glib-2.0/schemas/*.xml $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas + + ${concatMapStrings (pkg: "cp -rf ${pkg}/share/gsettings-schemas/*/glib-2.0/schemas/*.xml $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas\n") cfg.extraGSettingsOverridePackages} + + chmod -R a+w $out/share/gsettings-schemas/nixos-gsettings-overrides + cat - > $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas/nixos-defaults.gschema.override <<- EOF [org.gnome.desktop.background] picture-uri='${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png' [org.gnome.desktop.screensaver] picture-uri='${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png' + + ${cfg.extraGSettingsOverrides} EOF - ${pkgs.glib}/bin/glib-compile-schemas $out/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas/glib-2.0/schemas/ + + ${pkgs.glib}/bin/glib-compile-schemas $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas/ ''; }; @@ -47,19 +52,33 @@ in { options = { - services.xserver.desktopManager.gnome3.enable = mkOption { - default = false; - example = true; - description = "Enable Gnome 3 desktop manager."; - }; + services.xserver.desktopManager.gnome3 = { + enable = mkOption { + default = false; + example = true; + description = "Enable Gnome 3 desktop manager."; + }; - services.xserver.desktopManager.gnome3.sessionPath = mkOption { - default = []; - example = literalExample "[ pkgs.gnome3.gpaste ]"; - description = "Additional list of packages to be added to the session search path. - Useful for gnome shell extensions or gsettings-conditionated autostart."; - apply = list: list ++ [ gnome3.gnome_shell gnome3.gnome-shell-extensions ]; - }; + sessionPath = mkOption { + default = []; + example = literalExample "[ pkgs.gnome3.gpaste ]"; + description = "Additional list of packages to be added to the session search path. + Useful for gnome shell extensions or gsettings-conditionated autostart."; + apply = list: list ++ [ gnome3.gnome_shell gnome3.gnome-shell-extensions ]; + }; + + extraGSettingsOverrides = mkOption { + default = ""; + type = types.lines; + description = "Additional gsettings overrides."; + }; + + extraGSettingsOverridePackages = mkOption { + default = []; + type = types.listOf types.path; + description = "List of packages for which gsettings are overridden."; + }; + }; environment.gnome3.packageSet = mkOption { type = types.nullOr types.package; @@ -130,7 +149,7 @@ in { export XDG_DATA_DIRS=$XDG_DATA_DIRS''${XDG_DATA_DIRS:+:}${mimeAppsList}/share # Override gsettings-desktop-schema - export XDG_DATA_DIRS=${nixos-gsettings-desktop-schemas}/share/nixos-gsettings-schemas/nixos-gsettings-desktop-schemas''${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS + export XDG_DATA_DIRS=${nixos-gsettings-desktop-schemas}/share/gsettings-schemas/nixos-gsettings-overrides''${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS # Let nautilus find extensions export NAUTILUS_EXTENSION_DIR=${config.system.path}/lib/nautilus/extensions-3.0/ diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix index 62e483ae706..2dc03b7fe63 100644 --- a/nixos/modules/services/x11/desktop-managers/kde5.nix +++ b/nixos/modules/services/x11/desktop-managers/kde5.nix @@ -76,8 +76,6 @@ in environment.systemPackages = [ - pkgs.qt4 # qtconfig is the only way to set Qt 4 theme - kde5.frameworkintegration kde5.kinit @@ -103,16 +101,12 @@ in kde5.plasma-workspace kde5.plasma-workspace-wallpapers - kde5.ark kde5.dolphin kde5.dolphin-plugins kde5.ffmpegthumbs - kde5.gwenview - kde5.kate kde5.kdegraphics-thumbnailers kde5.kio-extras kde5.konsole - kde5.okular kde5.print-manager # Oxygen icons moved to KDE Frameworks 5.16 and later. diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix index b93e7db4600..da7be748d8b 100644 --- a/nixos/modules/services/x11/display-managers/default.nix +++ b/nixos/modules/services/x11/display-managers/default.nix @@ -49,18 +49,6 @@ let fi ''} - ${optionalString cfg.displayManager.desktopManagerHandlesLidAndPower '' - # Stop systemd from handling the power button and lid switch, - # since presumably the desktop environment will handle these. - if [ -z "$_INHIBITION_LOCK_TAKEN" ]; then - export _INHIBITION_LOCK_TAKEN=1 - if ! ${config.systemd.package}/bin/loginctl show-session $XDG_SESSION_ID | grep -q '^RemoteHost='; then - exec ${config.systemd.package}/bin/systemd-inhibit --what=handle-lid-switch:handle-power-key --why="Desktop environment handles power events" "$0" "$sessionType" - fi - fi - - ''} - ${optionalString cfg.startGnuPGAgent '' if test -z "$SSH_AUTH_SOCK"; then # Restart this script as a child of the GnuPG agent. @@ -219,17 +207,6 @@ in ''; }; - desktopManagerHandlesLidAndPower = mkOption { - type = types.bool; - default = false; - description = '' - Whether the display manager should prevent systemd from handling - lid and power events. This is normally handled by the desktop - environment's power manager. Turn this off when using a minimal - X11 setup without a full power manager. - ''; - }; - session = mkOption { default = []; example = literalExample @@ -309,9 +286,11 @@ in }; config = { - services.xserver.displayManager.xserverBin = "${xorg.xorgserver.out}/bin/X"; - }; + imports = [ + (mkRemovedOptionModule [ "services" "xserver" "displayManager" "desktopManagerHandlesLidAndPower" ]) + ]; + } diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix index 3949bf01a31..ac7db3d9adc 100644 --- a/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixos/modules/services/x11/display-managers/lightdm.nix @@ -87,6 +87,7 @@ in background = mkOption { type = types.str; + default = "${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png"; description = '' The background image or color to use. ''; @@ -152,9 +153,6 @@ in }; users.extraGroups.lightdm.gid = config.ids.gids.lightdm; - - services.xserver.displayManager.lightdm.background = mkDefault "${pkgs.nixos-artwork}/share/artwork/gnome/Gnome_Dark.png"; - services.xserver.tty = null; # We might start multiple X servers so let the tty increment themselves.. services.xserver.display = null; # We specify our own display (and logfile) in xserver-wrapper up there }; diff --git a/nixos/modules/services/x11/hardware/libinput.nix b/nixos/modules/services/x11/hardware/libinput.nix new file mode 100644 index 00000000000..12cc1e7e646 --- /dev/null +++ b/nixos/modules/services/x11/hardware/libinput.nix @@ -0,0 +1,230 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let cfg = config.services.xserver.libinput; + xorgBool = v: if v then "on" else "off"; +in { + + options = { + + services.xserver.libinput = { + + enable = mkEnableOption "libinput"; + + dev = mkOption { + type = types.nullOr types.str; + default = null; + example = "/dev/input/event0"; + description = + '' + Path for touchpad device. Set to null to apply to any + auto-detected touchpad. + ''; + }; + + accelProfile = mkOption { + type = types.enum [ "flat" "adaptive" ]; + default = "flat"; + example = "adaptive"; + description = + '' + Sets the pointer acceleration profile to the given profile. Permitted values are adaptive, flat. + Not all devices support this option or all profiles. If a profile is unsupported, the default profile + for this is used. For a description on the profiles and their behavior, see the libinput documentation. + ''; + }; + + accelSpeed = mkOption { + type = types.nullOr types.string; + default = null; + description = "Cursor acceleration (how fast speed increases from minSpeed to maxSpeed)."; + }; + + buttonMapping = mkOption { + type = types.nullOr types.string; + default = null; + description = + '' + Sets the logical button mapping for this device, see XSetPointerMapping(3). The string must + be a space-separated list of button mappings in the order of the logical buttons on the + device, starting with button 1. The default mapping is "1 2 3 ... 32". A mapping of 0 deac‐ + tivates the button. Multiple buttons can have the same mapping. Invalid mapping strings are + discarded and the default mapping is used for all buttons. Buttons not specified in the + user's mapping use the default mapping. See section BUTTON MAPPING for more details. + ''; + }; + + calibrationMatrix = mkOption { + type = types.nullOr types.string; + default = null; + description = + '' + A string of 9 space-separated floating point numbers. Sets the calibration matrix to the + 3x3 matrix where the first row is (abc), the second row is (def) and the third row is (ghi). + ''; + }; + + clickMethod = mkOption { + type = types.nullOr (types.enum [ "none" "buttonareas" "clickfinger" ]); + default = null; + example = "none"; + description = + '' + Enables a click method. Permitted values are none, buttonareas, clickfinger. + Not all devices support all methods, if an option is unsupported, + the default click method for this device is used. + ''; + }; + + leftHanded = mkOption { + type = types.bool; + default = false; + example = true; + description = "Enables left-handed button orientation, i.e. swapping left and right buttons."; + }; + + middleEmulation = mkOption { + type = types.bool; + default = true; + example = false; + description = + '' + Enables middle button emulation. When enabled, pressing the left and right buttons + simultaneously produces a middle mouse button click. + ''; + }; + + naturalScrolling = mkOption { + type = types.bool; + default = false; + example = true; + description = "Enables or disables natural scrolling behavior."; + }; + + scrollButton = mkOption { + type = types.nullOr types.int; + default = null; + example = 1; + description = + '' + Designates a button as scroll button. If the ScrollMethod is button and the button is logically + held down, x/y axis movement is converted into scroll events. + ''; + }; + + scrollMethod = mkOption { + type = types.enum [ "twofinger" "edge" "none" ]; + default = "twofinger"; + example = "edge"; + description = + '' + Specify the scrolling method. + ''; + }; + + horizontalScrolling = mkOption { + type = types.bool; + default = true; + example = false; + description = + '' + Disables horizontal scrolling. When disabled, this driver will discard any horizontal scroll + events from libinput. Note that this does not disable horizontal scrolling, it merely + discards the horizontal axis from any scroll events. + ''; + }; + + sendEventsMode = mkOption { + type = types.enum [ "disabled" "enabled" "disabled-on-external-mouse" ]; + default = "enabled"; + example = "disabled"; + description = + '' + Sets the send events mode to disabled, enabled, or "disable when an external mouse is connected". + ''; + }; + + tapping = mkOption { + type = types.bool; + default = true; + example = false; + description = + '' + Enables or disables tap-to-click behavior. + ''; + }; + + tappingDragLock = mkOption { + type = types.bool; + default = true; + example = false; + description = + '' + Enables or disables drag lock during tapping behavior. When enabled, a finger up during tap- + and-drag will not immediately release the button. If the finger is set down again within the + timeout, the draging process continues. + ''; + }; + + disableWhileTyping = mkOption { + type = types.bool; + default = true; + example = false; + description = + '' + Disable input method while typing. + ''; + }; + + additionalOptions = mkOption { + type = types.str; + default = ""; + example = + '' + Option "DragLockButtons" "L1 B1 L2 B2" + ''; + description = "Additional options for libinput touchpad driver."; + }; + + }; + + }; + + + config = mkIf cfg.enable { + + services.xserver.modules = [ pkgs.xorg.xf86inputlibinput ]; + + environment.systemPackages = [ pkgs.xorg.xf86inputlibinput ]; + + services.xserver.config = + '' + # Automatically enable the libinput driver for all touchpads. + Section "InputClass" + Identifier "libinputConfiguration" + MatchIsTouchpad "on" + ${optionalString (cfg.dev != null) ''MatchDevicePath "${cfg.dev}"''} + Driver "libinput" + Option "AccelProfile" "${cfg.accelProfile}" + ${optionalString (cfg.accelSpeed != null) ''Option "AccelSpeed" "${cfg.accelSpeed}"''} + ${optionalString (cfg.buttonMapping != null) ''Option "ButtonMapping" "${cfg.buttonMapping}"''} + ${optionalString (cfg.calibrationMatrix != null) ''Option "CalibrationMatrix" "${cfg.calibrationMatrix}"''} + ${optionalString (cfg.clickMethod != null) ''Option "ClickMethod" "${cfg.clickMethod}"''} + Option "LeftHanded" "${xorgBool cfg.leftHanded}" + Option "MiddleEmulation" "${xorgBool cfg.middleEmulation}" + Option "NaturalScrolling" "${xorgBool cfg.naturalScrolling}" + ${optionalString (cfg.scrollButton != null) ''Option "ScrollButton" "${cfg.scrollButton}"''} + Option "ScrollMethod" "${cfg.scrollMethod}" + Option "HorizontalScrolling" "${xorgBool cfg.horizontalScrolling}" + Option "SendEventsMode" "${cfg.sendEventsMode}" + Option "Tapping" "${xorgBool cfg.tapping}" + Option "TappingDragLock" "${xorgBool cfg.tappingDragLock}" + Option "DisableWhileTyping" "${xorgBool cfg.disableWhileTyping}" + ${cfg.additionalOptions} + EndSection + ''; + + }; + +} diff --git a/nixos/modules/services/x11/window-managers/bspwm.nix b/nixos/modules/services/x11/window-managers/bspwm.nix index 8b4e91d25aa..271b1b6cf5d 100644 --- a/nixos/modules/services/x11/window-managers/bspwm.nix +++ b/nixos/modules/services/x11/window-managers/bspwm.nix @@ -8,16 +8,39 @@ in { options = { - services.xserver.windowManager.bspwm.enable = mkEnableOption "bspwm"; + services.xserver.windowManager.bspwm = { + enable = mkEnableOption "bspwm"; + startThroughSession = mkOption { + type = with types; bool; + default = false; + description = " + Start the window manager through the script defined in + sessionScript. Defaults to the the bspwm-session script + provided by bspwm + "; + }; + sessionScript = mkOption { + default = "${pkgs.bspwm}/bin/bspwm-session"; + defaultText = "(pkgs.bspwm)/bin/bspwm-session"; + description = " + The start-session script to use. Defaults to the + provided bspwm-session script from the bspwm package. + + Does nothing unless `bspwm.startThroughSession` is enabled + "; + }; + }; }; config = mkIf cfg.enable { services.xserver.windowManager.session = singleton { name = "bspwm"; - start = " - ${pkgs.sxhkd}/bin/sxhkd & - ${pkgs.bspwm}/bin/bspwm - "; + start = if cfg.startThroughSession + then cfg.sessionScript + else '' + SXHKD_SHELL=/bin/sh ${pkgs.sxhkd}/bin/sxhkd -f 100 & + ${pkgs.bspwm}/bin/bspwm + ''; }; environment.systemPackages = [ pkgs.bspwm ]; }; diff --git a/nixos/modules/services/x11/window-managers/default.nix b/nixos/modules/services/x11/window-managers/default.nix index 37d3348b8a3..26dfbb1f4e1 100644 --- a/nixos/modules/services/x11/window-managers/default.nix +++ b/nixos/modules/services/x11/window-managers/default.nix @@ -13,6 +13,7 @@ in ./clfswm.nix ./compiz.nix ./dwm.nix + ./exwm.nix ./fluxbox.nix ./herbstluftwm.nix ./i3.nix diff --git a/nixos/modules/services/x11/window-managers/exwm.nix b/nixos/modules/services/x11/window-managers/exwm.nix new file mode 100644 index 00000000000..dbbd8a125d6 --- /dev/null +++ b/nixos/modules/services/x11/window-managers/exwm.nix @@ -0,0 +1,55 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.xserver.windowManager.exwm; + loadScript = pkgs.writeText "emacs-exwm-load" '' + (require 'exwm) + ${optionalString cfg.enableDefaultConfig '' + (require 'exwm-config) + (exwm-config-default) + ''} + ''; + packages = epkgs: cfg.extraPackages epkgs ++ [ epkgs.exwm ]; + exwm-emacs = pkgs.emacsWithPackages packages; +in + +{ + options = { + services.xserver.windowManager.exwm = { + enable = mkEnableOption "exwm"; + enableDefaultConfig = mkOption { + default = true; + example = false; + type = lib.types.bool; + description = "Enable an uncustomised exwm configuration."; + }; + extraPackages = mkOption { + default = self: []; + example = literalExample '' + epkgs: [ + epkgs.emms + epkgs.magit + epkgs.proofgeneral + ] + ''; + description = '' + Extra packages available to Emacs. The value must be a + function which receives the attrset defined in + <varname>emacsPackages</varname> as the sole argument. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + services.xserver.windowManager.session = singleton { + name = "exwm"; + start = '' + ${exwm-emacs}/bin/emacs -l ${loadScript} + ''; + }; + environment.systemPackages = [ exwm-emacs ]; + }; +} diff --git a/nixos/modules/services/x11/window-managers/openbox.nix b/nixos/modules/services/x11/window-managers/openbox.nix index 091b533b28b..07ef77151e9 100644 --- a/nixos/modules/services/x11/window-managers/openbox.nix +++ b/nixos/modules/services/x11/window-managers/openbox.nix @@ -8,7 +8,7 @@ in { options = { - services.xserver.windowManager.openbox.enable = mkEnableOption "oroborus"; + services.xserver.windowManager.openbox.enable = mkEnableOption "openbox"; }; config = mkIf cfg.enable { diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix index 069653d1e45..60b6a97416a 100644 --- a/nixos/modules/services/x11/xserver.nix +++ b/nixos/modules/services/x11/xserver.nix @@ -156,13 +156,16 @@ in inputClassSections = mkOption { type = types.listOf types.lines; default = []; - example = [ '' - Identifier "Trackpoint Wheel Emulation" - MatchProduct "ThinkPad USB Keyboard with TrackPoint" - Option "EmulateWheel" "true - Option "EmulateWheelButton" "2" - Option "Emulate3Buttons" "false" - '' ]; + example = literalExample '' + [ ''' + Identifier "Trackpoint Wheel Emulation" + MatchProduct "ThinkPad USB Keyboard with TrackPoint" + Option "EmulateWheel" "true + Option "EmulateWheelButton" "2" + Option "Emulate3Buttons" "false" + ''' + ] + ''; description = "Content of additional InputClass sections of the X server configuration file."; }; diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix index 72dd9b94a94..9d61d64f755 100644 --- a/nixos/modules/system/activation/activation-script.nix +++ b/nixos/modules/system/activation/activation-script.nix @@ -31,18 +31,19 @@ in system.activationScripts = mkOption { default = {}; - example = { - stdio = { - text = '' - # Needed by some programs. - ln -sfn /proc/self/fd /dev/fd - ln -sfn /proc/self/fd/0 /dev/stdin - ln -sfn /proc/self/fd/1 /dev/stdout - ln -sfn /proc/self/fd/2 /dev/stderr - ''; - deps = []; - }; - }; + example = literalExample '' + { stdio = { + text = ''' + # Needed by some programs. + ln -sfn /proc/self/fd /dev/fd + ln -sfn /proc/self/fd/0 /dev/stdin + ln -sfn /proc/self/fd/1 /dev/stdout + ln -sfn /proc/self/fd/2 /dev/stderr + '''; + deps = []; + }; + } + ''; description = '' A set of shell script fragments that are executed when a NixOS diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl index d9048427801..093b7f1ff22 100644 --- a/nixos/modules/system/activation/switch-to-configuration.pl +++ b/nixos/modules/system/activation/switch-to-configuration.pl @@ -261,12 +261,12 @@ while (my ($unit, $state) = each %{$activePrev}) { sub pathToUnitName { my ($path) = @_; - die unless substr($path, 0, 1) eq "/"; - return "-" if $path eq "/"; - $path = substr($path, 1); - $path =~ s/\//-/g; - # FIXME: handle - and unprintable characters. - return $path; + open my $cmd, "-|", "systemd-escape", "--suffix=mount", "-p", $path + or die "Unable to escape $path!\n"; + my $escaped = join "", <$cmd>; + chomp $escaped; + close $cmd or die; + return $escaped; } sub unique { @@ -290,7 +290,7 @@ my ($newFss, $newSwaps) = parseFstab "$out/etc/fstab"; foreach my $mountPoint (keys %$prevFss) { my $prev = $prevFss->{$mountPoint}; my $new = $newFss->{$mountPoint}; - my $unit = pathToUnitName($mountPoint) . ".mount"; + my $unit = pathToUnitName($mountPoint); if (!defined $new) { # Filesystem entry disappeared, so unmount it. $unitsToStop{$unit} = 1; diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix index d66580b7b9b..2d1b0ffb54c 100644 --- a/nixos/modules/system/activation/top-level.nix +++ b/nixos/modules/system/activation/top-level.nix @@ -178,9 +178,10 @@ in default = false; description = '' If enabled, copies the NixOS configuration file - <literal>$NIXOS_CONFIG</literal> (usually - <filename>/etc/nixos/configuration.nix</filename>) - to the system store path. + (usually <filename>/etc/nixos/configuration.nix</filename>) + and links it from the resulting system + (getting to <filename>/run/current-system/configuration.nix</filename>). + Note that only this single file is copied, even if it imports others. ''; }; @@ -238,7 +239,9 @@ in system.extraSystemBuilderCmds = optionalString config.system.copySystemConfiguration - "cp ${maybeEnv "NIXOS_CONFIG" "/etc/nixos/configuration.nix"} $out"; + ''ln -s '${import ../../../lib/from-env.nix "NIXOS_CONFIG" <nixos-config>}' \ + "$out/configuration.nix" + ''; system.build.toplevel = system; diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index 95df0ace1ca..c0c2b6a9416 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -71,6 +71,23 @@ mount -t devtmpfs -o "size=@devSize@" devtmpfs /dev mkdir -p /run mount -t tmpfs -o "mode=0755,size=@runSize@" tmpfs /run +# Log the script output to /dev/kmsg or /run/log/stage-1-init.log. +mkdir -p /tmp +mkfifo /tmp/stage-1-init.log.fifo +logOutFd=8 && logErrFd=9 +eval "exec $logOutFd>&1 $logErrFd>&2" +if test -w /dev/kmsg; then + tee -i < /tmp/stage-1-init.log.fifo /proc/self/fd/"$logOutFd" | while read -r line; do + if test -n "$line"; then + echo "<7>stage-1-init: $line" > /dev/kmsg + fi + done & +else + mkdir -p /run/log + tee -i < /tmp/stage-1-init.log.fifo /run/log/stage-1-init.log & +fi +exec > /tmp/stage-1-init.log.fifo 2>&1 + # Process the kernel command line. export stage2Init=/init @@ -415,6 +432,14 @@ fi # Stop udevd. udevadm control --exit +# Reset the logging file descriptors. +# Do this just before pkill, which will kill the tee process. +if test -n "@logCommands@" +then + exec 1>&$logOutFd 2>&$logErrFd + eval "exec $logOutFd>&- $logErrFd>&-" +fi + # Kill any remaining processes, just to be sure we're not taking any # with us into stage 2. But keep storage daemons like unionfs-fuse. pkill -9 -v -f '@' diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh index a73070ab332..1b5b22c2005 100644 --- a/nixos/modules/system/boot/stage-2-init.sh +++ b/nixos/modules/system/boot/stage-2-init.sh @@ -155,6 +155,21 @@ mkdir -m 0755 -p /var/setuid-wrappers mount -t tmpfs -o "mode=0755" tmpfs /var/setuid-wrappers +# Log the script output to /dev/kmsg or /run/log/stage-2-init.log. +# Only at this point are all the necessary prerequisites ready for these commands. +exec {logOutFd}>&1 {logErrFd}>&2 +if test -w /dev/kmsg; then + exec > >(tee -i /proc/self/fd/"$logOutFd" | while read -r line; do + if test -n "$line"; then + echo "<7>stage-2-init: $line" > /dev/kmsg + fi + done) 2>&1 +else + mkdir -p /run/log + exec > >(tee -i /run/log/stage-2-init.log) 2>&1 +fi + + # Run the script that performs all configuration activation that does # not have to be done at boot time. echo "running activation script..." @@ -182,6 +197,11 @@ ln -sfn /run/booted-system /nix/var/nix/gcroots/booted-system @shell@ @postBootCommands@ +# Reset the logging file descriptors. +exec 1>&$logOutFd 2>&$logErrFd +exec {logOutFd}>&- {logErrFd}>&- + + # Start systemd. echo "starting systemd..." PATH=/run/current-system/systemd/lib/systemd \ diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index c5ee95f4c9a..a3c83521c35 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -160,6 +160,7 @@ let "systemd-timedated.service" "systemd-localed.service" "systemd-hostnamed.service" + "systemd-binfmt.service" ] ++ cfg.additionalUpstreamSystemUnits; @@ -779,6 +780,7 @@ in systemd.services.systemd-user-sessions.restartIfChanged = false; # Restart kills all active sessions. systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true; systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true; + systemd.services.systemd-binfmt.wants = [ "proc-sys-fs-binfmt_misc.automount" ]; # Don't bother with certain units in containers. systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container"; diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix index c233beb63ca..f0f56b17f20 100644 --- a/nixos/modules/testing/test-instrumentation.nix +++ b/nixos/modules/testing/test-instrumentation.nix @@ -20,7 +20,15 @@ let kernel = config.boot.kernelPackages.kernel; in export USER=root export HOME=/root export DISPLAY=:0.0 + source /etc/profile + + # Don't use a pager when executing backdoor + # actions. Because we use a tty, commands like systemctl + # or nix-store get confused into thinking they're running + # interactively. + export PAGER= + cd /tmp exec < /dev/hvc0 > /dev/hvc0 while ! exec 2> /dev/ttyS0; do sleep 0.1; done @@ -38,11 +46,6 @@ let kernel = config.boot.kernelPackages.kernel; in systemd.services."serial-getty@ttyS0".enable = false; systemd.services."serial-getty@hvc0".enable = false; - # Don't use a pager when executing backdoor actions. Because we - # use a tty, commands like systemctl or nix-store get confused - # into thinking they're running interactively. - environment.variables.PAGER = ""; - boot.initrd.preDeviceCommands = '' echo 600 > /proc/sys/kernel/hung_task_timeout_secs diff --git a/nixos/modules/virtualisation/azure-agent.nix b/nixos/modules/virtualisation/azure-agent.nix index 96418d61ff8..640519758c7 100644 --- a/nixos/modules/virtualisation/azure-agent.nix +++ b/nixos/modules/virtualisation/azure-agent.nix @@ -9,10 +9,10 @@ let waagent = with pkgs; stdenv.mkDerivation rec { name = "waagent-2.0"; src = pkgs.fetchFromGitHub { - owner = "phreedom"; + owner = "Azure"; repo = "WALinuxAgent"; - rev = "1d31fe8cbc7f842993eed9b33a3d3f5410c364e3"; - sha256 = "1s53pfmy3azp0rmympmnphyq96sr9jy07pbsfza6mdzpalx1ripl"; + rev = "1b3a8407a95344d9d12a2a377f64140975f1e8e4"; + sha256 = "10byzvmpgrmr4d5mdn2kq04aapqb3sgr1admk13wjmy5cd6bwd2x"; }; buildInputs = [ makeWrapper python pythonPackages.wrapPython ]; runtimeDeps = [ findutils gnugrep gawk coreutils openssl openssh @@ -157,12 +157,6 @@ in after = [ "ip-up.target" ]; wants = [ "ip-up.target" ]; - environment = { - GIT_SSL_CAINFO = "/etc/ssl/certs/ca-certificates.crt"; - OPENSSL_X509_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; - SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; - }; - path = [ pkgs.e2fsprogs ]; description = "Windows Azure Agent Service"; unitConfig.ConditionPathExists = "/etc/waagent.conf"; diff --git a/nixos/modules/virtualisation/azure-config-user.nix b/nixos/modules/virtualisation/azure-config-user.nix new file mode 100644 index 00000000000..de1b3857923 --- /dev/null +++ b/nixos/modules/virtualisation/azure-config-user.nix @@ -0,0 +1,12 @@ +{ config, pkgs, modulesPath, ... }: + +{ + # To build the configuration or use nix-env, you need to run + # either nixos-rebuild --upgrade or nix-channel --update + # to fetch the nixos channel. + + # This configures everything but bootstrap services, + # which only need to be run once and have already finished + # if you are able to see this comment. + imports = [ "${modulesPath}/virtualisation/azure-common.nix" ]; +} diff --git a/nixos/modules/virtualisation/azure-image.nix b/nixos/modules/virtualisation/azure-image.nix index 08944e641d7..79d1f7d7cc4 100644 --- a/nixos/modules/virtualisation/azure-image.nix +++ b/nixos/modules/virtualisation/azure-image.nix @@ -16,14 +16,14 @@ in cyl=$(((${diskSize}*1024*1024)/(512*63*255))) size=$(($cyl*255*63*512)) roundedsize=$((($size/(1024*1024)+1)*(1024*1024))) - ${pkgs.vmTools.qemu}/bin/qemu-img create -f raw $diskImage $roundedsize + ${pkgs.vmTools.qemu-220}/bin/qemu-img create -f raw $diskImage $roundedsize mv closure xchg/ ''; postVM = '' mkdir -p $out - ${pkgs.vmTools.qemu}/bin/qemu-img convert -f raw -O vpc $diskImage $out/disk.vhd + ${pkgs.vmTools.qemu-220}/bin/qemu-img convert -f raw -O vpc -o subformat=fixed $diskImage $out/disk.vhd rm $diskImage ''; diskImageBase = "nixos-image-${config.system.nixosLabel}-${pkgs.stdenv.system}.raw"; @@ -78,7 +78,7 @@ in echo Install a configuration.nix. mkdir -p /mnt/etc/nixos /mnt/boot/grub - cp ${./azure-config.nix} /mnt/etc/nixos/configuration.nix + cp ${./azure-config-user.nix} /mnt/etc/nixos/configuration.nix echo Generate the GRUB menu. ln -s vda /dev/sda diff --git a/nixos/modules/virtualisation/azure-qemu-220-no-etc-install.patch b/nixos/modules/virtualisation/azure-qemu-220-no-etc-install.patch new file mode 100644 index 00000000000..81d29feea3d --- /dev/null +++ b/nixos/modules/virtualisation/azure-qemu-220-no-etc-install.patch @@ -0,0 +1,14 @@ +diff --git a/Makefile b/Makefile +index d6b9dc1..ce7c493 100644 +--- a/Makefile ++++ b/Makefile +@@ -384,8 +384,7 @@ install-confdir: + install-sysconfig: install-datadir install-confdir + $(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)" + +-install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig \ +-install-datadir install-localstatedir ++install: all $(if $(BUILD_DOCS),install-doc) install-datadir + ifneq ($(TOOLS),) + $(call install-prog,$(TOOLS),$(DESTDIR)$(bindir)) + endif diff --git a/nixos/modules/virtualisation/ec2-data.nix b/nixos/modules/virtualisation/ec2-data.nix index bee26261268..db3dd9949c1 100644 --- a/nixos/modules/virtualisation/ec2-data.nix +++ b/nixos/modules/virtualisation/ec2-data.nix @@ -43,18 +43,20 @@ with lib; mkdir -m 0755 -p /etc/ssh - key="$(sed 's/|/\n/g; s/SSH_HOST_DSA_KEY://; t; d' $userData)" - key_pub="$(sed 's/SSH_HOST_DSA_KEY_PUB://; t; d' $userData)" - if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_dsa_key ]; then - (umask 077; echo "$key" > /etc/ssh/ssh_host_dsa_key) - echo "$key_pub" > /etc/ssh/ssh_host_dsa_key.pub - fi + if [ -s "$userData" ]; then + key="$(sed 's/|/\n/g; s/SSH_HOST_DSA_KEY://; t; d' $userData)" + key_pub="$(sed 's/SSH_HOST_DSA_KEY_PUB://; t; d' $userData)" + if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_dsa_key ]; then + (umask 077; echo "$key" > /etc/ssh/ssh_host_dsa_key) + echo "$key_pub" > /etc/ssh/ssh_host_dsa_key.pub + fi - key="$(sed 's/|/\n/g; s/SSH_HOST_ED25519_KEY://; t; d' $userData)" - key_pub="$(sed 's/SSH_HOST_ED25519_KEY_PUB://; t; d' $userData)" - if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_ed25519_key ]; then - (umask 077; echo "$key" > /etc/ssh/ssh_host_ed25519_key) - echo "$key_pub" > /etc/ssh/ssh_host_ed25519_key.pub + key="$(sed 's/|/\n/g; s/SSH_HOST_ED25519_KEY://; t; d' $userData)" + key_pub="$(sed 's/SSH_HOST_ED25519_KEY_PUB://; t; d' $userData)" + if [ -n "$key" -a -n "$key_pub" -a ! -e /etc/ssh/ssh_host_ed25519_key ]; then + (umask 077; echo "$key" > /etc/ssh/ssh_host_ed25519_key) + echo "$key_pub" > /etc/ssh/ssh_host_ed25519_key.pub + fi fi ''; diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix index 06890b458ef..958e587444d 100644 --- a/nixos/release-combined.nix +++ b/nixos/release-combined.nix @@ -48,7 +48,7 @@ in rec { (all nixos.ova) #(all nixos.tests.containers) - (all nixos.tests.chromium) + (all nixos.tests.chromium.stable) (all nixos.tests.firefox) (all nixos.tests.firewall) nixos.tests.gnome3.x86_64-linux # FIXME: i686-linux @@ -63,7 +63,7 @@ in rec { (all nixos.tests.installer.btrfsSimple) (all nixos.tests.installer.btrfsSubvols) (all nixos.tests.installer.btrfsSubvolDefault) - (all nixos.tests.bootBiosCdrom) + (all nixos.tests.boot.biosCdrom) (all nixos.tests.ipv6) (all nixos.tests.kde4) #(all nixos.tests.lightdm) diff --git a/nixos/release.nix b/nixos/release.nix index d9f3e46b27c..069cf3727de 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -13,7 +13,25 @@ let forAllSystems = genAttrs supportedSystems; - callTest = fn: args: forAllSystems (system: hydraJob (import fn ({ inherit system; } // args))); + importTest = fn: args: system: import fn ({ + inherit system; + } // args); + + callTest = fn: args: forAllSystems (system: hydraJob (importTest fn args system)); + + callSubTests = fn: args: let + discover = attrs: let + subTests = filterAttrs (const (hasAttr "test")) attrs; + in mapAttrs (const (t: hydraJob t.test)) subTests; + + discoverForSystem = system: mapAttrs (_: test: { + ${system} = test; + }) (discover (importTest fn args system)); + + # If the test is only for a particular system, use only the specified + # system instead of generating attributes for all available systems. + in if args ? system then discover (import fn args) + else foldAttrs mergeAttrs {} (map discoverForSystem supportedSystems); pkgs = import nixpkgs { system = "x86_64-linux"; }; @@ -113,7 +131,7 @@ in rec { }); iso_graphical = forAllSystems (system: makeIso { - module = ./modules/installer/cd-dvd/installation-cd-graphical.nix; + module = ./modules/installer/cd-dvd/installation-cd-graphical-kde.nix; type = "graphical"; inherit system; }); @@ -215,8 +233,9 @@ in rec { tests.avahi = callTest tests/avahi.nix {}; tests.bittorrent = callTest tests/bittorrent.nix {}; tests.blivet = callTest tests/blivet.nix {}; + tests.boot = callSubTests tests/boot.nix {}; tests.cadvisor = hydraJob (import tests/cadvisor.nix { system = "x86_64-linux"; }); - tests.chromium = callTest tests/chromium.nix {}; + tests.chromium = callSubTests tests/chromium.nix {}; tests.cjdns = callTest tests/cjdns.nix {}; tests.containers = callTest tests/containers.nix {}; tests.docker = hydraJob (import tests/docker.nix { system = "x86_64-linux"; }); @@ -232,18 +251,7 @@ in rec { tests.gnome3-gdm = callTest tests/gnome3-gdm.nix {}; tests.grsecurity = callTest tests/grsecurity.nix {}; 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.luksroot = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).luksroot.test); - tests.installer.separateBoot = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).separateBoot.test); - tests.installer.separateBootFat = forAllSystems (system: hydraJob (import tests/installer.nix { inherit system; }).separateBootFat.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.installer = callSubTests tests/installer.nix {}; tests.influxdb = callTest tests/influxdb.nix {}; tests.ipv6 = callTest tests/ipv6.nix {}; tests.jenkins = callTest tests/jenkins.nix {}; @@ -262,29 +270,12 @@ in rec { tests.mysqlReplication = callTest tests/mysql-replication.nix {}; tests.nat.firewall = callTest tests/nat.nix { withFirewall = true; }; tests.nat.standalone = callTest tests/nat.nix { withFirewall = false; }; - tests.networking.networkd.loopback = callTest tests/networking.nix { networkd = true; test = "loopback"; }; - tests.networking.networkd.static = callTest tests/networking.nix { networkd = true; test = "static"; }; - tests.networking.networkd.dhcpSimple = callTest tests/networking.nix { networkd = true; test = "dhcpSimple"; }; - tests.networking.networkd.dhcpOneIf = callTest tests/networking.nix { networkd = true; test = "dhcpOneIf"; }; - tests.networking.networkd.bond = callTest tests/networking.nix { networkd = true; test = "bond"; }; - tests.networking.networkd.bridge = callTest tests/networking.nix { networkd = true; test = "bridge"; }; - tests.networking.networkd.macvlan = callTest tests/networking.nix { networkd = true; test = "macvlan"; }; - tests.networking.networkd.sit = callTest tests/networking.nix { networkd = true; test = "sit"; }; - tests.networking.networkd.vlan = callTest tests/networking.nix { networkd = true; test = "vlan"; }; - tests.networking.scripted.loopback = callTest tests/networking.nix { networkd = false; test = "loopback"; }; - tests.networking.scripted.static = callTest tests/networking.nix { networkd = false; test = "static"; }; - tests.networking.scripted.dhcpSimple = callTest tests/networking.nix { networkd = false; test = "dhcpSimple"; }; - tests.networking.scripted.dhcpOneIf = callTest tests/networking.nix { networkd = false; test = "dhcpOneIf"; }; - tests.networking.scripted.bond = callTest tests/networking.nix { networkd = false; test = "bond"; }; - tests.networking.scripted.bridge = callTest tests/networking.nix { networkd = false; test = "bridge"; }; - tests.networking.scripted.macvlan = callTest tests/networking.nix { networkd = false; test = "macvlan"; }; - tests.networking.scripted.sit = callTest tests/networking.nix { networkd = false; test = "sit"; }; - tests.networking.scripted.vlan = callTest tests/networking.nix { networkd = false; test = "vlan"; }; + tests.networking.networkd = callSubTests tests/networking.nix { networkd = true; }; + tests.networking.scripted = callSubTests tests/networking.nix { networkd = false; }; # 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.nixosPinVersion = callTest tests/nixos-pin-version.nix {}; tests.nsd = callTest tests/nsd.nix {}; tests.openssh = callTest tests/openssh.nix {}; tests.panamax = hydraJob (import tests/panamax.nix { system = "x86_64-linux"; }); @@ -300,12 +291,8 @@ in rec { tests.simple = callTest tests/simple.nix {}; tests.tomcat = callTest tests/tomcat.nix {}; tests.udisks2 = callTest tests/udisks2.nix {}; - tests.virtualbox = hydraJob (import tests/virtualbox.nix { system = "x86_64-linux"; }); + tests.virtualbox = callSubTests 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/avahi.nix b/nixos/tests/avahi.nix index a8369a6d1f8..976a770e887 100644 --- a/nixos/tests/avahi.nix +++ b/nixos/tests/avahi.nix @@ -5,18 +5,21 @@ import ./make-test.nix ({ pkgs, ... } : { maintainers = [ eelco chaoflow ]; }; - nodes = { - one = - { config, pkgs, ... }: { - services.avahi.enable = true; - services.avahi.nssmdns = true; - }; - - two = - { config, pkgs, ... }: { - services.avahi.enable = true; - services.avahi.nssmdns = true; + nodes = let + cfg = { config, pkgs, ... }: { + services.avahi = { + enable = true; + nssmdns = true; + publish.addresses = true; + publish.domain = true; + publish.enable = true; + publish.userServices = true; + publish.workstation = true; }; + }; + in { + one = cfg; + two = cfg; }; testScript = diff --git a/nixos/tests/boot.nix b/nixos/tests/boot.nix index 6a1d330155e..905d1645882 100644 --- a/nixos/tests/boot.nix +++ b/nixos/tests/boot.nix @@ -30,17 +30,17 @@ let ''; }; in { - bootBiosCdrom = makeBootTest "bios-cdrom" '' + biosCdrom = makeBootTest "bios-cdrom" '' cdrom => glob("${iso}/iso/*.iso") ''; - bootBiosUsb = makeBootTest "bios-usb" '' + biosUsb = makeBootTest "bios-usb" '' usb => glob("${iso}/iso/*.iso") ''; - bootUefiCdrom = makeBootTest "uefi-cdrom" '' + uefiCdrom = makeBootTest "uefi-cdrom" '' cdrom => glob("${iso}/iso/*.iso"), bios => '${pkgs.OVMF}/FV/OVMF.fd' ''; - bootUefiUsb = makeBootTest "uefi-usb" '' + uefiUsb = 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 6c61087760d..974af6888b6 100644 --- a/nixos/tests/chromium.nix +++ b/nixos/tests/chromium.nix @@ -1,13 +1,10 @@ -import ./make-test.nix ( -{ pkgs -, channelMap ? { - stable = pkgs.chromium; - #beta = pkgs.chromiumBeta; - #dev = pkgs.chromiumDev; - } -, ... -}: rec { - name = "chromium"; +{ system ? builtins.currentSystem }: + +with import ../lib/testing.nix { inherit system; }; +with pkgs.lib; + +mapAttrs (channel: chromiumPkg: makeTest rec { + name = "chromium-${channel}"; meta = with pkgs.stdenv.lib.maintainers; { maintainers = [ aszlig ]; }; @@ -16,6 +13,7 @@ import ./make-test.nix ( machine.imports = [ ./common/x11.nix ]; machine.virtualisation.memorySize = 2047; + machine.environment.systemPackages = [ chromiumPkg ]; startupHTML = pkgs.writeText "chromium-startup.html" '' <!DOCTYPE html> @@ -105,74 +103,65 @@ import ./make-test.nix ( closeWin; } - sub chromiumTest { - my ($channel, $pkg, $code) = @_; - $machine->waitForX; - - my $url = "file://${startupHTML}"; - my $args = "--user-data-dir=/tmp/chromium-$channel"; - $machine->execute( - "ulimit -c unlimited; ". - "$pkg/bin/chromium $args \"$url\" & disown" - ); - $machine->waitForText(qr/Type to search or enter a URL to navigate/); - $machine->waitUntilSucceeds("${xdo "check-startup" '' - search --sync --onlyvisible --name "startup done" - # close first start help popup - key -delay 1000 Escape + $machine->waitForX; + + my $url = "file://${startupHTML}"; + my $args = "--user-data-dir=/tmp/chromium-${channel}"; + $machine->execute( + "ulimit -c unlimited; ". + "chromium $args \"$url\" & disown" + ); + $machine->waitForText(qr/Type to search or enter a URL to navigate/); + $machine->waitUntilSucceeds("${xdo "check-startup" '' + search --sync --onlyvisible --name "startup done" + # close first start help popup + key -delay 1000 Escape + windowfocus --sync + windowactivate --sync + ''}"); + + createAndWaitForNewWin; + $machine->screenshot("empty_windows"); + closeWin; + + $machine->screenshot("startup_done"); + + testNewWin "check sandbox", sub { + $machine->succeed("${xdo "type-url" '' + search --sync --onlyvisible --name "new tab" windowfocus --sync - windowactivate --sync + type --delay 1000 "chrome://sandbox" ''}"); - createAndWaitForNewWin; - $machine->screenshot($channel."_emptywin"); - closeWin; - - $machine->screenshot($channel."_startup_done"); - - subtest("Chromium $channel", $code); - - $machine->shutdown; - } - - for (${let - mkArray = name: pkg: "[\"${name}\", \"${pkg}\"]"; - chanArrays = pkgs.lib.mapAttrsToList mkArray channelMap; - in pkgs.lib.concatStringsSep ", " chanArrays}) { - my ($channel, $pkg) = @$_; - chromiumTest $channel, $pkg, sub { - testNewWin "check sandbox", sub { - $machine->succeed("${xdo "type-url" '' - search --sync --onlyvisible --name "new tab" - windowfocus --sync - type --delay 1000 "chrome://sandbox" - ''}"); + $machine->succeed("${xdo "submit-url" '' + search --sync --onlyvisible --name "new tab" + windowfocus --sync + key --delay 1000 Return + ''}"); - $machine->succeed("${xdo "submit-url" '' - search --sync --onlyvisible --name "new tab" - windowfocus --sync - key --delay 1000 Return - ''}"); + $machine->screenshot("sandbox_info"); - $machine->screenshot($channel."_sandbox"); + $machine->succeed("${xdo "submit-url" '' + search --sync --onlyvisible --name "sandbox status" + windowfocus --sync + ''}"); + $machine->succeed("${xdo "submit-url" '' + key --delay 1000 Ctrl+a Ctrl+c + ''}"); - $machine->succeed("${xdo "submit-url" '' - search --sync --onlyvisible --name "sandbox status" - windowfocus --sync - ''}"); - $machine->succeed("${xdo "submit-url" '' - key --delay 1000 Ctrl+a Ctrl+c - ''}"); + my $clipboard = $machine->succeed("${pkgs.xclip}/bin/xclip -o"); + die "sandbox not working properly: $clipboard" + unless $clipboard =~ /namespace sandbox.*yes/mi + && $clipboard =~ /pid namespaces.*yes/mi + && $clipboard =~ /network namespaces.*yes/mi + && $clipboard =~ /seccomp.*sandbox.*yes/mi + && $clipboard =~ /you are adequately sandboxed/mi; + }; - my $clipboard = $machine->succeed("${pkgs.xclip}/bin/xclip -o"); - die "sandbox not working properly: $clipboard" - unless $clipboard =~ /namespace sandbox.*yes/mi - && $clipboard =~ /pid namespaces.*yes/mi - && $clipboard =~ /network namespaces.*yes/mi - && $clipboard =~ /seccomp.*sandbox.*yes/mi - && $clipboard =~ /you are adequately sandboxed/mi; - }; - }; - } + $machine->shutdown; ''; -}) +}) { + stable = pkgs.chromium; + beta = pkgs.chromiumBeta; + dev = pkgs.chromiumDev; +} diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix index 84fdb027ed8..9e5a6ad04e1 100644 --- a/nixos/tests/installer.nix +++ b/nixos/tests/installer.nix @@ -46,7 +46,7 @@ let , grubIdentifier, preBootCommands, extraConfig }: let - iface = if grubVersion == 1 then "scsi" else "virtio"; + iface = if grubVersion == 1 then "ide" else "virtio"; qemuFlags = (if system == "x86_64-linux" then "-m 768 " else "-m 512 ") + (optionalString (system == "x86_64-linux") "-cpu kvm64 "); diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix index 813d7c2bf51..d5a0a9b798f 100644 --- a/nixos/tests/networking.nix +++ b/nixos/tests/networking.nix @@ -1,406 +1,411 @@ -import ./make-test.nix ({ pkgs, networkd, test, ... }: - let - router = { config, pkgs, ... }: - with pkgs.lib; - let - vlanIfs = range 1 (length config.virtualisation.vlans); - in { - virtualisation.vlans = [ 1 2 3 ]; +{ system ? builtins.currentSystem, networkd }: + +with import ../lib/testing.nix { inherit system; }; +with pkgs.lib; + +let + router = { config, pkgs, ... }: + with pkgs.lib; + let + vlanIfs = range 1 (length config.virtualisation.vlans); + in { + virtualisation.vlans = [ 1 2 3 ]; + networking = { + useDHCP = false; + useNetworkd = networkd; + firewall.allowPing = true; + interfaces = mkOverride 0 (listToAttrs (flip map vlanIfs (n: + nameValuePair "eth${toString n}" { + ipAddress = "192.168.${toString n}.1"; + prefixLength = 24; + }))); + }; + services.dhcpd = { + enable = true; + interfaces = map (n: "eth${toString n}") vlanIfs; + extraConfig = '' + option subnet-mask 255.255.255.0; + '' + flip concatMapStrings vlanIfs (n: '' + subnet 192.168.${toString n}.0 netmask 255.255.255.0 { + option broadcast-address 192.168.${toString n}.255; + option routers 192.168.${toString n}.1; + range 192.168.${toString n}.2 192.168.${toString n}.254; + } + ''); + }; + }; + + testCases = { + loopback = { + name = "Loopback"; + machine.networking.useNetworkd = networkd; + testScript = '' + startAll; + $machine->waitForUnit("network-interfaces.target"); + $machine->waitForUnit("network.target"); + $machine->succeed("ip addr show lo | grep -q 'inet 127.0.0.1/8 '"); + $machine->succeed("ip addr show lo | grep -q 'inet6 ::1/128 '"); + ''; + }; + static = { + name = "Static"; + nodes.router = router; + nodes.client = { config, pkgs, ... }: with pkgs.lib; { + virtualisation.vlans = [ 1 2 ]; networking = { - useDHCP = false; useNetworkd = networkd; firewall.allowPing = true; - interfaces = mkOverride 0 (listToAttrs (flip map vlanIfs (n: - nameValuePair "eth${toString n}" { - ipAddress = "192.168.${toString n}.1"; - prefixLength = 24; - }))); - }; - services.dhcpd = { - enable = true; - interfaces = map (n: "eth${toString n}") vlanIfs; - extraConfig = '' - option subnet-mask 255.255.255.0; - '' + flip concatMapStrings vlanIfs (n: '' - subnet 192.168.${toString n}.0 netmask 255.255.255.0 { - option broadcast-address 192.168.${toString n}.255; - option routers 192.168.${toString n}.1; - range 192.168.${toString n}.2 192.168.${toString n}.254; - } - ''); + useDHCP = false; + defaultGateway = "192.168.1.1"; + interfaces.eth1.ip4 = mkOverride 0 [ + { address = "192.168.1.2"; prefixLength = 24; } + { address = "192.168.1.3"; prefixLength = 32; } + { address = "192.168.1.10"; prefixLength = 32; } + ]; + interfaces.eth2.ip4 = mkOverride 0 [ + { address = "192.168.2.2"; prefixLength = 24; } + ]; }; }; - testCases = { - loopback = { - name = "Loopback"; - machine.networking.useNetworkd = networkd; - testScript = '' + testScript = { nodes, ... }: + '' startAll; - $machine->waitForUnit("network-interfaces.target"); - $machine->waitForUnit("network.target"); - $machine->succeed("ip addr show lo | grep -q 'inet 127.0.0.1/8 '"); - $machine->succeed("ip addr show lo | grep -q 'inet6 ::1/128 '"); + + $client->waitForUnit("network-interfaces.target"); + $client->waitForUnit("network.target"); + $router->waitForUnit("network-interfaces.target"); + $router->waitForUnit("network.target"); + + # Make sure dhcpcd is not started + $client->fail("systemctl status dhcpcd.service"); + + # Test vlan 1 + $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.3"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.10"); + + $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.3"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.10"); + + # Test vlan 2 + $client->waitUntilSucceeds("ping -c 1 192.168.2.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.2.2"); + + $router->waitUntilSucceeds("ping -c 1 192.168.2.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.2.2"); + + # Test default gateway + $router->waitUntilSucceeds("ping -c 1 192.168.3.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.3.1"); ''; - }; - static = { - name = "Static"; - nodes.router = router; - nodes.client = { config, pkgs, ... }: with pkgs.lib; { - virtualisation.vlans = [ 1 2 ]; - networking = { - useNetworkd = networkd; - firewall.allowPing = true; - useDHCP = false; - defaultGateway = "192.168.1.1"; - interfaces.eth1.ip4 = mkOverride 0 [ - { address = "192.168.1.2"; prefixLength = 24; } - { address = "192.168.1.3"; prefixLength = 32; } - { address = "192.168.1.10"; prefixLength = 32; } - ]; - interfaces.eth2.ip4 = mkOverride 0 [ - { address = "192.168.2.2"; prefixLength = 24; } - ]; - }; + }; + dhcpSimple = { + name = "SimpleDHCP"; + nodes.router = router; + nodes.client = { config, pkgs, ... }: with pkgs.lib; { + virtualisation.vlans = [ 1 2 ]; + networking = { + useNetworkd = networkd; + firewall.allowPing = true; + useDHCP = true; + interfaces.eth1.ip4 = mkOverride 0 [ ]; + interfaces.eth2.ip4 = mkOverride 0 [ ]; }; - testScript = { nodes, ... }: - '' - startAll; - - $client->waitForUnit("network-interfaces.target"); - $client->waitForUnit("network.target"); - $router->waitForUnit("network-interfaces.target"); - $router->waitForUnit("network.target"); - - # Make sure dhcpcd is not started - $client->fail("systemctl status dhcpcd.service"); - - # Test vlan 1 - $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); - $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); - $client->waitUntilSucceeds("ping -c 1 192.168.1.3"); - $client->waitUntilSucceeds("ping -c 1 192.168.1.10"); - - $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); - $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); - $router->waitUntilSucceeds("ping -c 1 192.168.1.3"); - $router->waitUntilSucceeds("ping -c 1 192.168.1.10"); - - # Test vlan 2 - $client->waitUntilSucceeds("ping -c 1 192.168.2.1"); - $client->waitUntilSucceeds("ping -c 1 192.168.2.2"); - - $router->waitUntilSucceeds("ping -c 1 192.168.2.1"); - $router->waitUntilSucceeds("ping -c 1 192.168.2.2"); - - # Test default gateway - $router->waitUntilSucceeds("ping -c 1 192.168.3.1"); - $client->waitUntilSucceeds("ping -c 1 192.168.3.1"); - ''; }; - dhcpSimple = { - name = "SimpleDHCP"; - nodes.router = router; - nodes.client = { config, pkgs, ... }: with pkgs.lib; { - virtualisation.vlans = [ 1 2 ]; - networking = { - useNetworkd = networkd; - firewall.allowPing = true; - useDHCP = true; - interfaces.eth1.ip4 = mkOverride 0 [ ]; - interfaces.eth2.ip4 = mkOverride 0 [ ]; - }; - }; - testScript = { nodes, ... }: - '' - startAll; + testScript = { nodes, ... }: + '' + startAll; - $client->waitForUnit("network-interfaces.target"); - $client->waitForUnit("network.target"); - $router->waitForUnit("network-interfaces.target"); - $router->waitForUnit("network.target"); + $client->waitForUnit("network-interfaces.target"); + $client->waitForUnit("network.target"); + $router->waitForUnit("network-interfaces.target"); + $router->waitForUnit("network.target"); - # Wait until we have an ip address on each interface - $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'"); - $client->waitUntilSucceeds("ip addr show dev eth2 | grep -q '192.168.2'"); + # Wait until we have an ip address on each interface + $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'"); + $client->waitUntilSucceeds("ip addr show dev eth2 | grep -q '192.168.2'"); - # Test vlan 1 - $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); - $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); + # Test vlan 1 + $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); - $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); - $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); - # Test vlan 2 - $client->waitUntilSucceeds("ping -c 1 192.168.2.1"); - $client->waitUntilSucceeds("ping -c 1 192.168.2.2"); + # Test vlan 2 + $client->waitUntilSucceeds("ping -c 1 192.168.2.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.2.2"); - $router->waitUntilSucceeds("ping -c 1 192.168.2.1"); - $router->waitUntilSucceeds("ping -c 1 192.168.2.2"); - ''; - }; - dhcpOneIf = { - name = "OneInterfaceDHCP"; - nodes.router = router; - nodes.client = { config, pkgs, ... }: with pkgs.lib; { - virtualisation.vlans = [ 1 2 ]; - networking = { - useNetworkd = networkd; - firewall.allowPing = true; - useDHCP = false; - interfaces.eth1 = { - ip4 = mkOverride 0 [ ]; - useDHCP = true; - }; - interfaces.eth2.ip4 = mkOverride 0 [ ]; + $router->waitUntilSucceeds("ping -c 1 192.168.2.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.2.2"); + ''; + }; + dhcpOneIf = { + name = "OneInterfaceDHCP"; + nodes.router = router; + nodes.client = { config, pkgs, ... }: with pkgs.lib; { + virtualisation.vlans = [ 1 2 ]; + networking = { + useNetworkd = networkd; + firewall.allowPing = true; + useDHCP = false; + interfaces.eth1 = { + ip4 = mkOverride 0 [ ]; + useDHCP = true; }; + interfaces.eth2.ip4 = mkOverride 0 [ ]; }; - testScript = { nodes, ... }: - '' - startAll; + }; + testScript = { nodes, ... }: + '' + startAll; - # Wait for networking to come up - $client->waitForUnit("network-interfaces.target"); - $client->waitForUnit("network.target"); - $router->waitForUnit("network-interfaces.target"); - $router->waitForUnit("network.target"); + # Wait for networking to come up + $client->waitForUnit("network-interfaces.target"); + $client->waitForUnit("network.target"); + $router->waitForUnit("network-interfaces.target"); + $router->waitForUnit("network.target"); - # Wait until we have an ip address on each interface - $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'"); + # Wait until we have an ip address on each interface + $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'"); - # Test vlan 1 - $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); - $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); + # Test vlan 1 + $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); - $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); - $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); - # Test vlan 2 - $client->waitUntilSucceeds("ping -c 1 192.168.2.1"); - $client->fail("ping -c 1 192.168.2.2"); + # Test vlan 2 + $client->waitUntilSucceeds("ping -c 1 192.168.2.1"); + $client->fail("ping -c 1 192.168.2.2"); - $router->waitUntilSucceeds("ping -c 1 192.168.2.1"); - $router->fail("ping -c 1 192.168.2.2"); - ''; - }; - bond = let - node = address: { config, pkgs, ... }: with pkgs.lib; { - virtualisation.vlans = [ 1 2 ]; - networking = { - useNetworkd = networkd; - firewall.allowPing = true; - useDHCP = false; - bonds.bond = { - mode = "balance-rr"; - interfaces = [ "eth1" "eth2" ]; - }; - interfaces.eth1.ip4 = mkOverride 0 [ ]; - interfaces.eth2.ip4 = mkOverride 0 [ ]; - interfaces.bond.ip4 = mkOverride 0 - [ { inherit address; prefixLength = 30; } ]; + $router->waitUntilSucceeds("ping -c 1 192.168.2.1"); + $router->fail("ping -c 1 192.168.2.2"); + ''; + }; + bond = let + node = address: { config, pkgs, ... }: with pkgs.lib; { + virtualisation.vlans = [ 1 2 ]; + networking = { + useNetworkd = networkd; + firewall.allowPing = true; + useDHCP = false; + bonds.bond = { + mode = "balance-rr"; + interfaces = [ "eth1" "eth2" ]; }; + interfaces.eth1.ip4 = mkOverride 0 [ ]; + interfaces.eth2.ip4 = mkOverride 0 [ ]; + interfaces.bond.ip4 = mkOverride 0 + [ { inherit address; prefixLength = 30; } ]; }; - in { - name = "Bond"; - nodes.client1 = node "192.168.1.1"; - nodes.client2 = node "192.168.1.2"; - testScript = { nodes, ... }: - '' - startAll; - - # Wait for networking to come up - $client1->waitForUnit("network-interfaces.target"); - $client1->waitForUnit("network.target"); - $client2->waitForUnit("network-interfaces.target"); - $client2->waitForUnit("network.target"); - - # Test bonding - $client1->waitUntilSucceeds("ping -c 2 192.168.1.1"); - $client1->waitUntilSucceeds("ping -c 2 192.168.1.2"); - - $client2->waitUntilSucceeds("ping -c 2 192.168.1.1"); - $client2->waitUntilSucceeds("ping -c 2 192.168.1.2"); - ''; }; - bridge = let - node = { address, vlan }: { config, pkgs, ... }: with pkgs.lib; { - virtualisation.vlans = [ vlan ]; - networking = { - useNetworkd = networkd; - firewall.allowPing = true; - useDHCP = false; - interfaces.eth1.ip4 = mkOverride 0 - [ { inherit address; prefixLength = 24; } ]; - }; + in { + name = "Bond"; + nodes.client1 = node "192.168.1.1"; + nodes.client2 = node "192.168.1.2"; + testScript = { nodes, ... }: + '' + startAll; + + # Wait for networking to come up + $client1->waitForUnit("network-interfaces.target"); + $client1->waitForUnit("network.target"); + $client2->waitForUnit("network-interfaces.target"); + $client2->waitForUnit("network.target"); + + # Test bonding + $client1->waitUntilSucceeds("ping -c 2 192.168.1.1"); + $client1->waitUntilSucceeds("ping -c 2 192.168.1.2"); + + $client2->waitUntilSucceeds("ping -c 2 192.168.1.1"); + $client2->waitUntilSucceeds("ping -c 2 192.168.1.2"); + ''; + }; + bridge = let + node = { address, vlan }: { config, pkgs, ... }: with pkgs.lib; { + virtualisation.vlans = [ vlan ]; + networking = { + useNetworkd = networkd; + firewall.allowPing = true; + useDHCP = false; + interfaces.eth1.ip4 = mkOverride 0 + [ { inherit address; prefixLength = 24; } ]; }; - in { - name = "Bridge"; - nodes.client1 = node { address = "192.168.1.2"; vlan = 1; }; - nodes.client2 = node { address = "192.168.1.3"; vlan = 2; }; - nodes.router = { config, pkgs, ... }: with pkgs.lib; { - virtualisation.vlans = [ 1 2 ]; - networking = { - useNetworkd = networkd; - firewall.allowPing = true; - useDHCP = false; - bridges.bridge.interfaces = [ "eth1" "eth2" ]; - interfaces.eth1.ip4 = mkOverride 0 [ ]; - interfaces.eth2.ip4 = mkOverride 0 [ ]; - interfaces.bridge.ip4 = mkOverride 0 - [ { address = "192.168.1.1"; prefixLength = 24; } ]; - }; + }; + in { + name = "Bridge"; + nodes.client1 = node { address = "192.168.1.2"; vlan = 1; }; + nodes.client2 = node { address = "192.168.1.3"; vlan = 2; }; + nodes.router = { config, pkgs, ... }: with pkgs.lib; { + virtualisation.vlans = [ 1 2 ]; + networking = { + useNetworkd = networkd; + firewall.allowPing = true; + useDHCP = false; + bridges.bridge.interfaces = [ "eth1" "eth2" ]; + interfaces.eth1.ip4 = mkOverride 0 [ ]; + interfaces.eth2.ip4 = mkOverride 0 [ ]; + interfaces.bridge.ip4 = mkOverride 0 + [ { address = "192.168.1.1"; prefixLength = 24; } ]; }; - testScript = { nodes, ... }: - '' - startAll; - - # Wait for networking to come up - $client1->waitForUnit("network-interfaces.target"); - $client1->waitForUnit("network.target"); - $client2->waitForUnit("network-interfaces.target"); - $client2->waitForUnit("network.target"); - $router->waitForUnit("network-interfaces.target"); - $router->waitForUnit("network.target"); - - # Test bridging - $client1->waitUntilSucceeds("ping -c 1 192.168.1.1"); - $client1->waitUntilSucceeds("ping -c 1 192.168.1.2"); - $client1->waitUntilSucceeds("ping -c 1 192.168.1.3"); - - $client2->waitUntilSucceeds("ping -c 1 192.168.1.1"); - $client2->waitUntilSucceeds("ping -c 1 192.168.1.2"); - $client2->waitUntilSucceeds("ping -c 1 192.168.1.3"); - - $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); - $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); - $router->waitUntilSucceeds("ping -c 1 192.168.1.3"); - ''; }; - macvlan = { - name = "MACVLAN"; - nodes.router = router; - nodes.client = { config, pkgs, ... }: with pkgs.lib; { - virtualisation.vlans = [ 1 ]; - networking = { - useNetworkd = networkd; - firewall.allowPing = true; - useDHCP = true; - macvlans.macvlan.interface = "eth1"; - interfaces.eth1.ip4 = mkOverride 0 [ ]; - }; + testScript = { nodes, ... }: + '' + startAll; + + # Wait for networking to come up + $client1->waitForUnit("network-interfaces.target"); + $client1->waitForUnit("network.target"); + $client2->waitForUnit("network-interfaces.target"); + $client2->waitForUnit("network.target"); + $router->waitForUnit("network-interfaces.target"); + $router->waitForUnit("network.target"); + + # Test bridging + $client1->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $client1->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $client1->waitUntilSucceeds("ping -c 1 192.168.1.3"); + + $client2->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $client2->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $client2->waitUntilSucceeds("ping -c 1 192.168.1.3"); + + $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.3"); + ''; + }; + macvlan = { + name = "MACVLAN"; + nodes.router = router; + nodes.client = { config, pkgs, ... }: with pkgs.lib; { + virtualisation.vlans = [ 1 ]; + networking = { + useNetworkd = networkd; + firewall.allowPing = true; + useDHCP = true; + macvlans.macvlan.interface = "eth1"; + interfaces.eth1.ip4 = mkOverride 0 [ ]; }; - testScript = { nodes, ... }: - '' - startAll; - - # Wait for networking to come up - $client->waitForUnit("network-interfaces.target"); - $client->waitForUnit("network.target"); - $router->waitForUnit("network-interfaces.target"); - $router->waitForUnit("network.target"); - - # Wait until we have an ip address on each interface - $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'"); - $client->waitUntilSucceeds("ip addr show dev macvlan | grep -q '192.168.1'"); - - # Print diagnosting information - $router->succeed("ip addr >&2"); - $client->succeed("ip addr >&2"); - - # Test macvlan creates routable ips - $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); - $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); - $client->waitUntilSucceeds("ping -c 1 192.168.1.3"); - - $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); - $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); - $router->waitUntilSucceeds("ping -c 1 192.168.1.3"); - ''; }; - sit = let - node = { address4, remote, address6 }: { config, pkgs, ... }: with pkgs.lib; { - virtualisation.vlans = [ 1 ]; - networking = { - useNetworkd = networkd; - firewall.enable = false; - useDHCP = false; - sits.sit = { - inherit remote; - local = address4; - dev = "eth1"; - }; - interfaces.eth1.ip4 = mkOverride 0 - [ { address = address4; prefixLength = 24; } ]; - interfaces.sit.ip6 = mkOverride 0 - [ { address = address6; prefixLength = 64; } ]; + testScript = { nodes, ... }: + '' + startAll; + + # Wait for networking to come up + $client->waitForUnit("network-interfaces.target"); + $client->waitForUnit("network.target"); + $router->waitForUnit("network-interfaces.target"); + $router->waitForUnit("network.target"); + + # Wait until we have an ip address on each interface + $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q '192.168.1'"); + $client->waitUntilSucceeds("ip addr show dev macvlan | grep -q '192.168.1'"); + + # Print diagnosting information + $router->succeed("ip addr >&2"); + $client->succeed("ip addr >&2"); + + # Test macvlan creates routable ips + $client->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $client->waitUntilSucceeds("ping -c 1 192.168.1.3"); + + $router->waitUntilSucceeds("ping -c 1 192.168.1.1"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.2"); + $router->waitUntilSucceeds("ping -c 1 192.168.1.3"); + ''; + }; + sit = let + node = { address4, remote, address6 }: { config, pkgs, ... }: with pkgs.lib; { + virtualisation.vlans = [ 1 ]; + networking = { + useNetworkd = networkd; + firewall.enable = false; + useDHCP = false; + sits.sit = { + inherit remote; + local = address4; + dev = "eth1"; }; + interfaces.eth1.ip4 = mkOverride 0 + [ { address = address4; prefixLength = 24; } ]; + interfaces.sit.ip6 = mkOverride 0 + [ { address = address6; prefixLength = 64; } ]; }; - in { - name = "Sit"; - nodes.client1 = node { address4 = "192.168.1.1"; remote = "192.168.1.2"; address6 = "fc00::1"; }; - nodes.client2 = node { address4 = "192.168.1.2"; remote = "192.168.1.1"; address6 = "fc00::2"; }; - testScript = { nodes, ... }: - '' - startAll; - - # Wait for networking to be configured - $client1->waitForUnit("network-interfaces.target"); - $client1->waitForUnit("network.target"); - $client2->waitForUnit("network-interfaces.target"); - $client2->waitForUnit("network.target"); - - # Print diagnostic information - $client1->succeed("ip addr >&2"); - $client2->succeed("ip addr >&2"); - - # Test ipv6 - $client1->waitUntilSucceeds("ping6 -c 1 fc00::1"); - $client1->waitUntilSucceeds("ping6 -c 1 fc00::2"); - - $client2->waitUntilSucceeds("ping6 -c 1 fc00::1"); - $client2->waitUntilSucceeds("ping6 -c 1 fc00::2"); - ''; }; - vlan = let - node = address: { config, pkgs, ... }: with pkgs.lib; { - #virtualisation.vlans = [ 1 ]; - networking = { - useNetworkd = networkd; - firewall.allowPing = true; - useDHCP = false; - vlans.vlan = { - id = 1; - interface = "eth0"; - }; - interfaces.eth0.ip4 = mkOverride 0 [ ]; - interfaces.eth1.ip4 = mkOverride 0 [ ]; - interfaces.vlan.ip4 = mkOverride 0 - [ { inherit address; prefixLength = 24; } ]; + in { + name = "Sit"; + nodes.client1 = node { address4 = "192.168.1.1"; remote = "192.168.1.2"; address6 = "fc00::1"; }; + nodes.client2 = node { address4 = "192.168.1.2"; remote = "192.168.1.1"; address6 = "fc00::2"; }; + testScript = { nodes, ... }: + '' + startAll; + + # Wait for networking to be configured + $client1->waitForUnit("network-interfaces.target"); + $client1->waitForUnit("network.target"); + $client2->waitForUnit("network-interfaces.target"); + $client2->waitForUnit("network.target"); + + # Print diagnostic information + $client1->succeed("ip addr >&2"); + $client2->succeed("ip addr >&2"); + + # Test ipv6 + $client1->waitUntilSucceeds("ping6 -c 1 fc00::1"); + $client1->waitUntilSucceeds("ping6 -c 1 fc00::2"); + + $client2->waitUntilSucceeds("ping6 -c 1 fc00::1"); + $client2->waitUntilSucceeds("ping6 -c 1 fc00::2"); + ''; + }; + vlan = let + node = address: { config, pkgs, ... }: with pkgs.lib; { + #virtualisation.vlans = [ 1 ]; + networking = { + useNetworkd = networkd; + firewall.allowPing = true; + useDHCP = false; + vlans.vlan = { + id = 1; + interface = "eth0"; }; + interfaces.eth0.ip4 = mkOverride 0 [ ]; + interfaces.eth1.ip4 = mkOverride 0 [ ]; + interfaces.vlan.ip4 = mkOverride 0 + [ { inherit address; prefixLength = 24; } ]; }; - in { - name = "vlan"; - nodes.client1 = node "192.168.1.1"; - nodes.client2 = node "192.168.1.2"; - testScript = { nodes, ... }: - '' - startAll; - - # Wait for networking to be configured - $client1->waitForUnit("network-interfaces.target"); - $client1->waitForUnit("network.target"); - $client2->waitForUnit("network-interfaces.target"); - $client2->waitForUnit("network.target"); - - # Test vlan is setup - $client1->succeed("ip addr show dev vlan >&2"); - $client2->succeed("ip addr show dev vlan >&2"); - ''; }; + in { + name = "vlan"; + nodes.client1 = node "192.168.1.1"; + nodes.client2 = node "192.168.1.2"; + testScript = { nodes, ... }: + '' + startAll; + + # Wait for networking to be configured + $client1->waitForUnit("network-interfaces.target"); + $client1->waitForUnit("network.target"); + $client2->waitForUnit("network-interfaces.target"); + $client2->waitForUnit("network.target"); + + # Test vlan is setup + $client1->succeed("ip addr show dev vlan >&2"); + $client2->succeed("ip addr show dev vlan >&2"); + ''; }; - case = testCases.${test}; - in case // { - name = "${case.name}-Networking-${if networkd then "Networkd" else "Scripted"}"; - meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ wkennington ]; - }; - }) + }; + +in mapAttrs (const (attrs: makeTest (attrs // { + name = "${attrs.name}-Networking-${if networkd then "Networkd" else "Scripted"}"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ wkennington ]; + }; +}))) testCases diff --git a/nixos/tests/nixos-pin-version.nix b/nixos/tests/nixos-pin-version.nix deleted file mode 100644 index 91fba2e759d..00000000000 --- a/nixos/tests/nixos-pin-version.nix +++ /dev/null @@ -1,57 +0,0 @@ -{ system ? builtins.currentSystem }: - -with import ../lib/testing.nix { inherit system; }; -let -in - -pkgs.stdenv.mkDerivation rec { - name = "nixos-pin-version"; - src = ../..; - buildInputs = with pkgs; [ nix gnugrep ]; - - withoutPath = pkgs.writeText "configuration.nix" '' - { - nixos.extraModules = [ ({lib, ...}: { system.nixosRevision = lib.mkForce "ABCDEF"; }) ]; - } - ''; - - withPath = pkgs.writeText "configuration.nix" '' - { - nixos.path = ${src}/nixos ; - nixos.extraModules = [ ({lib, ...}: { system.nixosRevision = lib.mkForce "ABCDEF"; }) ]; - } - ''; - - phases = "buildPhase"; - buildPhase = '' - datadir="${pkgs.nix}/share" - export TEST_ROOT=$(pwd)/test-tmp - export NIX_STORE_DIR=$TEST_ROOT/store - export NIX_LOCALSTATE_DIR=$TEST_ROOT/var - export NIX_LOG_DIR=$TEST_ROOT/var/log/nix - export NIX_STATE_DIR=$TEST_ROOT/var/nix - export NIX_DB_DIR=$TEST_ROOT/db - export NIX_CONF_DIR=$TEST_ROOT/etc - export NIX_MANIFESTS_DIR=$TEST_ROOT/var/nix/manifests - export NIX_BUILD_HOOK= - export PAGER=cat - cacheDir=$TEST_ROOT/binary-cache - nix-store --init - - export NIX_PATH="nixpkgs=$src:nixos=$src/nixos:nixos-config=${withoutPath}" ; - if test $(nix-instantiate $src/nixos -A config.system.nixosRevision --eval-only) != '"ABCDEF"' ; then :; - else - echo "Unexpected re-entry without the nixos.path option defined."; - exit 1; - fi; - - export NIX_PATH="nixpkgs=$src:nixos=$src/nixos:nixos-config=${withPath}" ; - if test $(nix-instantiate $src/nixos -A config.system.nixosRevision --eval-only) = '"ABCDEF"' ; then :; - else - echo "Expected a re-entry when the nixos.path option is defined."; - exit 1; - fi; - - touch $out; - ''; -} diff --git a/nixos/tests/printing.nix b/nixos/tests/printing.nix index 02980cee2fb..10d69b446cd 100644 --- a/nixos/tests/printing.nix +++ b/nixos/tests/printing.nix @@ -78,7 +78,7 @@ import ./make-test.nix ({pkgs, ... }: { # (showing that the right filters have been applied). Of # course, since there is no actual USB printer attached, the # file will stay in the queue forever. - $server->waitForFile("/var/spool/cups/d00001-001"); + $server->waitForFile("/var/spool/cups/d*-001"); $server->sleep(10); $server->succeed("lpq -a") =~ /$fn/ or die; @@ -90,6 +90,9 @@ import ./make-test.nix ({pkgs, ... }: { Machine::retry sub { return 1 if $server->succeed("lpq -a") =~ /no entries/; }; + # The queue is empty already, so this should be safe. + # Otherwise, pairs of "c*"-"d*-001" files might persist. + $server->execute("rm /var/spool/cups/*"); }; } ''; diff --git a/nixos/tests/virtualbox.nix b/nixos/tests/virtualbox.nix index 01fcd15fd8b..da4c0bddc34 100644 --- a/nixos/tests/virtualbox.nix +++ b/nixos/tests/virtualbox.nix @@ -1,7 +1,9 @@ -{ debug ? false, ... } @ args: +{ system ? builtins.currentSystem, debug ? false }: -import ./make-test.nix ({ pkgs, ... }: with pkgs.lib; let +with import ../lib/testing.nix { inherit system; }; +with pkgs.lib; +let testVMConfig = vmName: attrs: { config, pkgs, ... }: let guestAdditions = pkgs.linuxPackages.virtualboxGuestAdditions; @@ -314,138 +316,140 @@ import ./make-test.nix ({ pkgs, ... }: with pkgs.lib; let test2.vmScript = dhcpScript; }; -in { - name = "virtualbox"; - meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ aszlig wkennington ]; - }; + mkVBoxTest = name: testScript: makeTest { + name = "virtualbox-${name}"; + + machine = { lib, config, ... }: { + imports = let + mkVMConf = name: val: val.machine // { key = "${name}-config"; }; + vmConfigs = mapAttrsToList mkVMConf vboxVMs; + in [ ./common/user-account.nix ./common/x11.nix ] ++ vmConfigs; + virtualisation.memorySize = 2048; + virtualisation.virtualbox.host.enable = true; + users.extraUsers.alice.extraGroups = let + inherit (config.virtualisation.virtualbox.host) enableHardening; + in lib.mkIf enableHardening (lib.singleton "vboxusers"); + }; - machine = { pkgs, lib, config, ... }: { - imports = let - mkVMConf = name: val: val.machine // { key = "${name}-config"; }; - vmConfigs = mapAttrsToList mkVMConf vboxVMs; - in [ ./common/user-account.nix ./common/x11.nix ] ++ vmConfigs; - virtualisation.memorySize = 2048; - virtualisation.virtualbox.host.enable = true; - users.extraUsers.alice.extraGroups = let - inherit (config.virtualisation.virtualbox.host) enableHardening; - in lib.mkIf enableHardening (lib.singleton "vboxusers"); - }; + testScript = '' + sub ru ($) { + my $esc = $_[0] =~ s/'/'\\${"'"}'/gr; + return "su - alice -c '$esc'"; + } - testScript = '' - sub ru ($) { - my $esc = $_[0] =~ s/'/'\\${"'"}'/gr; - return "su - alice -c '$esc'"; - } + sub vbm { + $machine->succeed(ru("VBoxManage ".$_[0])); + }; - sub vbm { - $machine->succeed(ru("VBoxManage ".$_[0])); - }; + sub removeUUIDs { + return join("\n", grep { $_ !~ /^UUID:/ } split(/\n/, $_[0]))."\n"; + } - ${concatStrings (mapAttrsToList (_: getAttr "testSubs") vboxVMs)} + ${concatStrings (mapAttrsToList (_: getAttr "testSubs") vboxVMs)} - $machine->waitForX; + $machine->waitForX; - ${mkLog "$HOME/.config/VirtualBox/VBoxSVC.log" "HOST-SVC"} + ${mkLog "$HOME/.config/VirtualBox/VBoxSVC.log" "HOST-SVC"} - createVM_simple; + ${testScript} + ''; - subtest "simple-gui", sub { - $machine->succeed(ru "VirtualBox &"); - $machine->waitForWindow(qr/Oracle VM VirtualBox Manager/); - $machine->sleep(5); - $machine->screenshot("gui_manager_started"); - $machine->sendKeys("ret"); - $machine->screenshot("gui_manager_sent_startup"); - waitForStartup_simple (sub { - $machine->sendKeys("ret"); - }); - $machine->screenshot("gui_started"); - waitForVMBoot_simple; - $machine->screenshot("gui_booted"); - shutdownVM_simple; - $machine->sleep(5); - $machine->screenshot("gui_stopped"); - $machine->sendKeys("ctrl-q"); - $machine->sleep(5); - $machine->screenshot("gui_manager_stopped"); + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ aszlig wkennington ]; }; + }; - cleanup_simple; +in mapAttrs mkVBoxTest { + simple-gui = '' + createVM_simple; + $machine->succeed(ru "VirtualBox &"); + $machine->waitForWindow(qr/Oracle VM VirtualBox Manager/); + $machine->sleep(5); + $machine->screenshot("gui_manager_started"); + $machine->sendKeys("ret"); + $machine->screenshot("gui_manager_sent_startup"); + waitForStartup_simple (sub { + $machine->sendKeys("ret"); + }); + $machine->screenshot("gui_started"); + waitForVMBoot_simple; + $machine->screenshot("gui_booted"); + shutdownVM_simple; + $machine->sleep(5); + $machine->screenshot("gui_stopped"); + $machine->sendKeys("ctrl-q"); + $machine->sleep(5); + $machine->screenshot("gui_manager_stopped"); + ''; - subtest "simple-cli", sub { - vbm("startvm simple"); - waitForStartup_simple; - $machine->screenshot("cli_started"); - waitForVMBoot_simple; - $machine->screenshot("cli_booted"); - shutdownVM_simple; - }; + simple-cli = '' + createVM_simple; + vbm("startvm simple"); + waitForStartup_simple; + $machine->screenshot("cli_started"); + waitForVMBoot_simple; + $machine->screenshot("cli_booted"); - subtest "privilege-escalation", sub { + $machine->nest("Checking for privilege escalation", sub { $machine->fail("test -e '/root/VirtualBox VMs'"); $machine->fail("test -e '/root/.config/VirtualBox'"); $machine->succeed("test -e '/home/alice/VirtualBox VMs'"); - }; - - destroyVM_simple; + }); - sub removeUUIDs { - return join("\n", grep { $_ !~ /^UUID:/ } split(/\n/, $_[0]))."\n"; - } + shutdownVM_simple; + ''; - subtest "host-usb-permissions", sub { - my $userUSB = removeUUIDs vbm("list usbhost"); - print STDERR $userUSB; - my $rootUSB = removeUUIDs $machine->succeed("VBoxManage list usbhost"); - print STDERR $rootUSB; + host-usb-permissions = '' + my $userUSB = removeUUIDs vbm("list usbhost"); + print STDERR $userUSB; + my $rootUSB = removeUUIDs $machine->succeed("VBoxManage list usbhost"); + print STDERR $rootUSB; - die "USB host devices differ for root and normal user" - if $userUSB ne $rootUSB; - die "No USB host devices found" if $userUSB =~ /<none>/; - }; + die "USB host devices differ for root and normal user" + if $userUSB ne $rootUSB; + die "No USB host devices found" if $userUSB =~ /<none>/; + ''; - subtest "systemd-detect-virt", sub { - createVM_detectvirt; - vbm("startvm detectvirt"); - waitForStartup_detectvirt; - waitForVMBoot_detectvirt; - shutdownVM_detectvirt; - my $result = $machine->succeed("cat '$detectvirt_sharepath/result'"); - chomp $result; - destroyVM_detectvirt; - die "systemd-detect-virt returned \"$result\" instead of \"oracle\"" - if $result ne "oracle"; - }; + systemd-detect-virt = '' + createVM_detectvirt; + vbm("startvm detectvirt"); + waitForStartup_detectvirt; + waitForVMBoot_detectvirt; + shutdownVM_detectvirt; + my $result = $machine->succeed("cat '$detectvirt_sharepath/result'"); + chomp $result; + destroyVM_detectvirt; + die "systemd-detect-virt returned \"$result\" instead of \"oracle\"" + if $result ne "oracle"; + ''; - subtest "net-hostonlyif", sub { - createVM_test1; - createVM_test2; + net-hostonlyif = '' + createVM_test1; + createVM_test2; - vbm("startvm test1"); - waitForStartup_test1; - waitForVMBoot_test1; + vbm("startvm test1"); + waitForStartup_test1; + waitForVMBoot_test1; - vbm("startvm test2"); - waitForStartup_test2; - waitForVMBoot_test2; + vbm("startvm test2"); + waitForStartup_test2; + waitForVMBoot_test2; - $machine->screenshot("net_booted"); + $machine->screenshot("net_booted"); - my $test1IP = waitForIP_test1 1; - my $test2IP = waitForIP_test2 1; + my $test1IP = waitForIP_test1 1; + my $test2IP = waitForIP_test2 1; - $machine->succeed("echo '$test2IP' | netcat -c '$test1IP' 1234"); - $machine->succeed("echo '$test1IP' | netcat -c '$test2IP' 1234"); + $machine->succeed("echo '$test2IP' | netcat -c '$test1IP' 1234"); + $machine->succeed("echo '$test1IP' | netcat -c '$test2IP' 1234"); - $machine->waitUntilSucceeds("netcat -c '$test1IP' 5678 >&2"); - $machine->waitUntilSucceeds("netcat -c '$test2IP' 5678 >&2"); + $machine->waitUntilSucceeds("netcat -c '$test1IP' 5678 >&2"); + $machine->waitUntilSucceeds("netcat -c '$test2IP' 5678 >&2"); - shutdownVM_test1; - shutdownVM_test2; + shutdownVM_test1; + shutdownVM_test2; - destroyVM_test1; - destroyVM_test2; - }; + destroyVM_test1; + destroyVM_test2; ''; -}) args +} |