diff options
Diffstat (limited to 'nixos')
137 files changed, 3597 insertions, 649 deletions
diff --git a/nixos/default.nix b/nixos/default.nix index 0e45a1cd75e2..45da78e9261c 100644 --- a/nixos/default.nix +++ b/nixos/default.nix @@ -9,8 +9,6 @@ let modules = [ configuration ]; }; - inherit (eval) pkgs; - # This is for `nixos-rebuild build-vm'. vmConfig = (import ./lib/eval-config.nix { inherit system; @@ -30,7 +28,7 @@ let in { - inherit (eval) config options; + inherit (eval) pkgs config options; system = eval.config.system.build.toplevel; diff --git a/nixos/doc/manual/configuration/ipv4-config.xml b/nixos/doc/manual/configuration/ipv4-config.xml index 053501b1736d..68238b547d60 100644 --- a/nixos/doc/manual/configuration/ipv4-config.xml +++ b/nixos/doc/manual/configuration/ipv4-config.xml @@ -12,7 +12,7 @@ interfaces. However, you can configure an interface manually as follows: <programlisting> -networking.interfaces.eth0.ip4 = [ { address = "192.168.1.2"; prefixLength = 24; } ]; +networking.interfaces.eth0.ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ]; </programlisting> Typically you’ll also want to set a default gateway and set of name diff --git a/nixos/doc/manual/configuration/ipv6-config.xml b/nixos/doc/manual/configuration/ipv6-config.xml index 6d9e0a164e9e..74a21e18ec3f 100644 --- a/nixos/doc/manual/configuration/ipv6-config.xml +++ b/nixos/doc/manual/configuration/ipv6-config.xml @@ -26,7 +26,7 @@ boot.kernel.sysctl."net.ipv6.conf.eth0.disable_ipv6" = true; DHCPv6. You can configure an interface manually: <programlisting> -networking.interfaces.eth0.ip6 = [ { address = "fe00:aa:bb:cc::2"; prefixLength = 64; } ]; +networking.interfaces.eth0.ipv6.addresses = [ { address = "fe00:aa:bb:cc::2"; prefixLength = 64; } ]; </programlisting> </para> diff --git a/nixos/doc/manual/configuration/xfce.xml b/nixos/doc/manual/configuration/xfce.xml index 21c7a85e19cc..18804d2c08be 100644 --- a/nixos/doc/manual/configuration/xfce.xml +++ b/nixos/doc/manual/configuration/xfce.xml @@ -35,18 +35,7 @@ services.compton = { To install them manually (system wide), put them into your <literal>environment.systemPackages</literal>. </para> - - <para> - NixOS’s default <emphasis>display manager</emphasis> is SLiM. - (DM is the program that provides a graphical login prompt - and manages the X server.) - You can, for example, select KDE’s - <command>sddm</command> instead: - <programlisting> -services.xserver.displayManager.sddm.enable = true; - </programlisting> - </para> - + <simplesect> <title>Thunar Volume Support</title> diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix index 8079a2feb29f..6098b057a370 100644 --- a/nixos/doc/manual/default.nix +++ b/nixos/doc/manual/default.nix @@ -6,7 +6,7 @@ let lib = pkgs.lib; # Remove invisible and internal options. - optionsList = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options); + optionsListVisible = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options); # Replace functions by the string <function> substFunction = x: @@ -15,13 +15,43 @@ let else if lib.isFunction x then "<function>" else x; - # Clean up declaration sites to not refer to the NixOS source tree. - optionsList' = lib.flip map optionsList (opt: opt // { + # Generate DocBook documentation for a list of packages. This is + # what `relatedPackages` option of `mkOption` from + # ../../../lib/options.nix influences. + # + # Each element of `relatedPackages` can be either + # - a string: that will be interpreted as an attribute name from `pkgs`, + # - a list: that will be interpreted as an attribute path from `pkgs`, + # - an attrset: that can specify `name`, `path`, `package`, `comment` + # (either of `name`, `path` is required, the rest are optional). + genRelatedPackages = packages: + let + unpack = p: if lib.isString p then { name = p; } + else if lib.isList p then { path = p; } + else p; + describe = args: + let + name = args.name or (lib.concatStringsSep "." args.path); + path = args.path or [ args.name ]; + package = args.package or (lib.attrByPath path (throw "Invalid package attribute path `${toString path}'") pkgs); + in "<listitem>" + + "<para><literal>pkgs.${name} (${package.meta.name})</literal>" + + lib.optionalString (!package.meta.available) " <emphasis>[UNAVAILABLE]</emphasis>" + + ": ${package.meta.description or "???"}.</para>" + + lib.optionalString (args ? comment) "\n<para>${args.comment}</para>" + # Lots of `longDescription's break DocBook, so we just wrap them into <programlisting> + + lib.optionalString (package.meta ? longDescription) "\n<programlisting>${package.meta.longDescription}</programlisting>" + + "</listitem>"; + in "<itemizedlist>${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}</itemizedlist>"; + + optionsListDesc = lib.flip map optionsListVisible (opt: opt // { + # Clean up declaration sites to not refer to the NixOS source tree. declarations = map stripAnyPrefixes opt.declarations; } // lib.optionalAttrs (opt ? example) { example = substFunction opt.example; } // lib.optionalAttrs (opt ? default) { default = substFunction opt.default; } - // lib.optionalAttrs (opt ? type) { type = substFunction opt.type; }); + // lib.optionalAttrs (opt ? type) { type = substFunction opt.type; } + // lib.optionalAttrs (opt ? relatedPackages) { relatedPackages = genRelatedPackages opt.relatedPackages; }); # We need to strip references to /nix/store/* from options, # including any `extraSources` if some modules came from elsewhere, @@ -32,8 +62,21 @@ let prefixesToStrip = map (p: "${toString p}/") ([ ../../.. ] ++ extraSources); stripAnyPrefixes = lib.flip (lib.fold lib.removePrefix) prefixesToStrip; + # Custom "less" that pushes up all the things ending in ".enable*" + # and ".package*" + optionLess = a: b: + let + ise = lib.hasPrefix "enable"; + isp = lib.hasPrefix "package"; + cmp = lib.splitByAndCompare ise lib.compare + (lib.splitByAndCompare isp lib.compare lib.compare); + in lib.compareLists cmp a.loc b.loc < 0; + + # Customly sort option list for the man page. + optionsList = lib.sort optionLess optionsListDesc; + # Convert the list of options into an XML file. - optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList'); + optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsList); optionsDocBook = runCommand "options-db.xml" {} '' optionsXML=${optionsXML} @@ -191,7 +234,7 @@ in rec { mkdir -p $dst cp ${builtins.toFile "options.json" (builtins.unsafeDiscardStringContext (builtins.toJSON - (builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList')))) + (builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList)))) } $dst/options.json mkdir -p $out/nix-support diff --git a/nixos/doc/manual/installation/changing-config.xml b/nixos/doc/manual/installation/changing-config.xml index 75df307a1b7c..4db9020b9606 100644 --- a/nixos/doc/manual/installation/changing-config.xml +++ b/nixos/doc/manual/installation/changing-config.xml @@ -70,9 +70,21 @@ $ ./result/bin/run-*-vm </screen> The VM does not have any data from your host system, so your existing -user accounts and home directories will not be available. You can -forward ports on the host to the guest. For instance, the following -will forward host port 2222 to guest port 22 (SSH): +user accounts and home directories will not be available unless you +have set <literal>mutableUsers = false</literal>. Another way is to +temporarily add the following to your configuration: + +<screen> +users.extraUsers.your-user.initialPassword = "test" +</screen> + +<emphasis>Important:</emphasis> delete the $hostname.qcow2 file if you +have started the virtual machine at least once without the right +users, otherwise the changes will not get picked up. + +You can forward ports on the host to the guest. For +instance, the following will forward host port 2222 to guest port 22 +(SSH): <screen> $ QEMU_NET_OPTS="hostfwd=tcp::2222-:22" ./result/bin/run-*-vm diff --git a/nixos/doc/manual/installation/installing.xml b/nixos/doc/manual/installation/installing.xml index d4746f2eb3a8..2a5d1fc3ce8d 100644 --- a/nixos/doc/manual/installation/installing.xml +++ b/nixos/doc/manual/installation/installing.xml @@ -275,11 +275,20 @@ Enter new UNIX password: *** Retype new UNIX password: *** </screen> + <note> + <para> + To prevent the password prompt, set <code>users.mutableUsers = false;</code> in + <filename>configuration.nix</filename>, which allows unattended installation + necessary in automation. + </para> + </note> + </para> </listitem> - <listitem><para>If everything went well: + <listitem> + <para>If everything went well: <screen> # reboot</screen> diff --git a/nixos/doc/manual/options-to-docbook.xsl b/nixos/doc/manual/options-to-docbook.xsl index 5387546b5982..7b45b233ab2a 100644 --- a/nixos/doc/manual/options-to-docbook.xsl +++ b/nixos/doc/manual/options-to-docbook.xsl @@ -70,6 +70,15 @@ </para> </xsl:if> + <xsl:if test="attr[@name = 'relatedPackages']"> + <para> + <emphasis>Related packages:</emphasis> + <xsl:text> </xsl:text> + <xsl:value-of disable-output-escaping="yes" + select="attr[@name = 'relatedPackages']/string/@value" /> + </para> + </xsl:if> + <xsl:if test="count(attr[@name = 'declarations']/list/*) != 0"> <para> <emphasis>Declared by:</emphasis> diff --git a/nixos/doc/manual/release-notes/rl-1803.xml b/nixos/doc/manual/release-notes/rl-1803.xml index 8391c550afab..ce58c4dc95b0 100644 --- a/nixos/doc/manual/release-notes/rl-1803.xml +++ b/nixos/doc/manual/release-notes/rl-1803.xml @@ -38,6 +38,16 @@ has the following highlights: </para> </itemizedlist> </para> </listitem> + + <listitem> + <para> + The GNOME version is now 3.26. + </para> + </listitem> + + <listitem> + <para>PHP now defaults to PHP 7.2</para> + </listitem> </itemizedlist> </section> @@ -135,6 +145,17 @@ following incompatible changes:</para> </listitem> <listitem> <para> + The <literal>openssh</literal> package + now includes Kerberos support by default; + the <literal>openssh_with_kerberos</literal> package + is now a deprecated alias. + If you do not want Kerberos support, + you can do <literal>openssh.override { withKerboros = false; }</literal>. + Note, this also applies to the <literal>openssh_hpn</literal> package. + </para> + </listitem> + <listitem> + <para> <literal>cc-wrapper</literal> has been split in two; there is now also a <literal>bintools-wrapper</literal>. The most commonly used files in <filename>nix-support</filename> are now split between the two wrappers. Some commonly used ones, like <filename>nix-support/dynamic-linker</filename>, are duplicated for backwards compatability, even though they rightly belong only in <literal>bintools-wrapper</literal>. @@ -196,6 +217,28 @@ following incompatible changes:</para> </listitem> </itemizedlist> </listitem> + <listitem> + <para> + The <literal>jid</literal> package has been removed, due to maintenance + overhead of a go package having non-versioned dependencies. + </para> + </listitem> + <listitem> + <para> + When using <option>services.xserver.libinput</option> (enabled by default in GNOME), + it now handles all input devices, not just touchpads. As a result, you might need to + re-evaluate any custom Xorg configuration. In particular, + <literal>Option "XkbRules" "base"</literal> may result in broken keyboard layout. + </para> + </listitem> + <listitem> + <para> + The <literal>attic</literal> package was removed. A maintained fork called + <link xlink:href="https://www.borgbackup.org/">Borg</link> should be used instead. + Migration instructions can be found + <link xlink:href="http://borgbackup.readthedocs.io/en/stable/usage/upgrade.html#attic-and-borg-0-xx-to-borg-1-x">here</link>. + </para> + </listitem> </itemizedlist> </section> @@ -226,10 +269,42 @@ following incompatible changes:</para> </listitem> <listitem> <para> - The option <option>services.xserver.desktopManager.default</option> is now <literal>none</literal> by default. - An assertion failure is thrown if WM's and DM's default are <literal>none</literal>. - To explicitly run a plain X session without and DM or WM, the newly introduced option <option>services.xserver.plainX</option> - must be set to true. + In the module <option>networking.interfaces.<name></option> the + following options have been removed: + <itemizedlist> + <listitem> + <para><option>ipAddress</option></para> + </listitem> + <listitem> + <para><option>ipv6Address</option></para> + </listitem> + <listitem> + <para><option>prefixLength</option></para> + </listitem> + <listitem> + <para><option>ipv6PrefixLength</option></para> + </listitem> + <listitem> + <para><option>subnetMask</option></para> + </listitem> + </itemizedlist> + To assign static addresses to an interface the options + <option>ipv4.addresses</option> and <option>ipv6.addresses</option> + should be used instead. + The options <option>ip4</option> and <option>ip6</option> have been + renamed to <option>ipv4.addresses</option> <option>ipv6.addresses</option> + respectively. + The new options <option>ipv4.routes</option> and <option>ipv6.routes</option> + have been added to set up static routing. + </para> + </listitem> + <listitem> + <para> + The option <option>services.xserver.desktopManager.default</option> is now + <literal>none</literal> by default. An assertion failure is thrown if WM's + and DM's default are <literal>none</literal>. + To explicitly run a plain X session without and DM or WM, the newly + introduced option <option>services.xserver.plainX</option> must be set to true. </para> </listitem> <listitem> diff --git a/nixos/lib/build-vms.nix b/nixos/lib/build-vms.nix index 4685fe6914a2..e14105f5f011 100644 --- a/nixos/lib/build-vms.nix +++ b/nixos/lib/build-vms.nix @@ -51,7 +51,7 @@ rec { let interfacesNumbered = zipLists config.virtualisation.vlans (range 1 255); interfaces = flip map interfacesNumbered ({ fst, snd }: - nameValuePair "eth${toString snd}" { ip4 = + nameValuePair "eth${toString snd}" { ipv4.addresses = [ { address = "192.168.${toString fst}.${toString m.snd}"; prefixLength = 24; } ]; @@ -64,7 +64,7 @@ rec { networking.interfaces = listToAttrs interfaces; networking.primaryIPAddress = - optionalString (interfaces != []) (head (head interfaces).value.ip4).address; + optionalString (interfaces != []) (head (head interfaces).value.ipv4.addresses).address; # Put the IP addresses of all VMs in this machine's # /etc/hosts file. If a machine has multiple diff --git a/nixos/lib/make-disk-image.nix b/nixos/lib/make-disk-image.nix index 6269e4279380..4da863469032 100644 --- a/nixos/lib/make-disk-image.nix +++ b/nixos/lib/make-disk-image.nix @@ -85,7 +85,7 @@ let format' = format; in let nixpkgs = cleanSource pkgs.path; # FIXME: merge with channel.nix / make-channel.nix. - channelSources = pkgs.runCommand "nixos-${config.system.nixosVersion}" {} '' + channelSources = pkgs.runCommand "nixos-${config.system.nixos.version}" {} '' mkdir -p $out cp -prd ${nixpkgs} $out/nixos chmod -R u+w $out/nixos @@ -93,7 +93,7 @@ let format' = format; in let ln -s . $out/nixos/nixpkgs fi rm -rf $out/nixos/.git - echo -n ${config.system.nixosVersionSuffix} > $out/nixos/.version-suffix + echo -n ${config.system.nixos.versionSuffix} > $out/nixos/.version-suffix ''; binPath = with pkgs; makeBinPath ( diff --git a/nixos/lib/testing.nix b/nixos/lib/testing.nix index cf213d906f58..efcafbaa5554 100644 --- a/nixos/lib/testing.nix +++ b/nixos/lib/testing.nix @@ -29,7 +29,7 @@ rec { cp ${./test-driver/Logger.pm} $libDir/Logger.pm wrapProgram $out/bin/nixos-test-driver \ - --prefix PATH : "${lib.makeBinPath [ qemu vde2 netpbm coreutils ]}" \ + --prefix PATH : "${lib.makeBinPath [ qemu_test vde2 netpbm coreutils ]}" \ --prefix PERL5LIB : "${with perlPackages; lib.makePerlPath [ TermReadLineGnu XMLWriter IOTty FileSlurp ]}:$out/lib/perl5/site_perl" ''; }; @@ -78,7 +78,19 @@ rec { } @ t: let - testDriverName = "nixos-test-driver-${name}"; + # A standard store path to the vm monitor is built like this: + # /tmp/nix-build-vm-test-run-$name.drv-0/vm-state-machine/monitor + # The max filename length of a unix domain socket is 108 bytes. + # This means $name can at most be 50 bytes long. + maxTestNameLen = 50; + testNameLen = builtins.stringLength name; + + testDriverName = with builtins; + if testNameLen > maxTestNameLen then + abort ("The name of the test '${name}' must not be longer than ${toString maxTestNameLen} " + + "it's currently ${toString testNameLen} characters long.") + else + "nixos-test-driver-${name}"; nodes = buildVirtualNetwork ( t.nodes or (if t ? machine then { machine = t.machine; } else { })); diff --git a/nixos/modules/installer/cd-dvd/channel.nix b/nixos/modules/installer/cd-dvd/channel.nix index ddb00f174d1a..4a1983167957 100644 --- a/nixos/modules/installer/cd-dvd/channel.nix +++ b/nixos/modules/installer/cd-dvd/channel.nix @@ -12,7 +12,7 @@ let # CD. These are installed into the "nixos" channel of the root # user, as expected by nixos-rebuild/nixos-install. FIXME: merge # with make-channel.nix. - channelSources = pkgs.runCommand "nixos-${config.system.nixosVersion}" + channelSources = pkgs.runCommand "nixos-${config.system.nixos.version}" { } '' mkdir -p $out @@ -21,7 +21,7 @@ let if [ ! -e $out/nixos/nixpkgs ]; then ln -s . $out/nixos/nixpkgs fi - echo -n ${config.system.nixosVersionSuffix} > $out/nixos/.version-suffix + echo -n ${config.system.nixos.versionSuffix} > $out/nixos/.version-suffix ''; in diff --git a/nixos/modules/installer/cd-dvd/installation-cd-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-base.nix index 2569860a098f..756c8751d00e 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-base.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-base.nix @@ -16,7 +16,7 @@ with lib; ]; # ISO naming. - isoImage.isoName = "${config.isoImage.isoBaseName}-${config.system.nixosLabel}-${pkgs.stdenv.system}.iso"; + isoImage.isoName = "${config.isoImage.isoBaseName}-${config.system.nixos.label}-${pkgs.stdenv.system}.iso"; isoImage.volumeID = substring 0 11 "NIXOS_ISO"; diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index bf9db8249f13..e7cbf415a223 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -39,31 +39,31 @@ let DEFAULT boot LABEL boot - MENU LABEL NixOS ${config.system.nixosLabel}${config.isoImage.appendToMenuLabel} - LINUX /boot/bzImage + MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} + LINUX /boot/${config.system.boot.loader.kernelFile} APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} - INITRD /boot/initrd + INITRD /boot/${config.system.boot.loader.initrdFile} # A variant to boot with 'nomodeset' LABEL boot-nomodeset - MENU LABEL NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} (nomodeset) - LINUX /boot/bzImage + MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (nomodeset) + LINUX /boot/${config.system.boot.loader.kernelFile} APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} nomodeset - INITRD /boot/initrd + INITRD /boot/${config.system.boot.loader.initrdFile} # A variant to boot with 'copytoram' LABEL boot-copytoram - MENU LABEL NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} (copytoram) - LINUX /boot/bzImage + MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (copytoram) + LINUX /boot/${config.system.boot.loader.kernelFile} APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} copytoram - INITRD /boot/initrd + INITRD /boot/${config.system.boot.loader.initrdFile} # A variant to boot with verbose logging to the console LABEL boot-nomodeset - MENU LABEL NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} (debug) - LINUX /boot/bzImage + MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (debug) + LINUX /boot/${config.system.boot.loader.kernelFile} APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} loglevel=7 - INITRD /boot/initrd + INITRD /boot/${config.system.boot.loader.initrdFile} ''; isolinuxMemtest86Entry = '' @@ -82,35 +82,35 @@ let mkdir -p $out/loader/entries cat << EOF > $out/loader/entries/nixos-iso.conf - title NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} - linux /boot/bzImage - initrd /boot/initrd + title NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} + linux /boot/${config.system.boot.loader.kernelFile} + initrd /boot/${config.system.boot.loader.initrdFile} options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} EOF # A variant to boot with 'nomodeset' cat << EOF > $out/loader/entries/nixos-iso-nomodeset.conf - title NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} + title NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} version nomodeset - linux /boot/bzImage - initrd /boot/initrd + linux /boot/${config.system.boot.loader.kernelFile} + initrd /boot/${config.system.boot.loader.initrdFile} options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} nomodeset EOF # A variant to boot with 'copytoram' cat << EOF > $out/loader/entries/nixos-iso-copytoram.conf - title NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} + title NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} version copytoram - linux /boot/bzImage - initrd /boot/initrd + linux /boot/${config.system.boot.loader.kernelFile} + initrd /boot/${config.system.boot.loader.initrdFile} options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} copytoram EOF # A variant to boot with verbose logging to the console cat << EOF > $out/loader/entries/nixos-iso-debug.conf - title NixOS ${config.system.nixosVersion}${config.isoImage.appendToMenuLabel} (debug) - linux /boot/bzImage - initrd /boot/initrd + title NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (debug) + linux /boot/${config.system.boot.loader.kernelFile} + initrd /boot/${config.system.boot.loader.initrdFile} options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} loglevel=7 EOF @@ -127,8 +127,8 @@ let mkdir ./contents && cd ./contents cp -rp "${efiDir}"/* . mkdir ./boot - cp -p "${config.boot.kernelPackages.kernel}/bzImage" \ - "${config.system.build.initialRamdisk}/initrd" ./boot/ + cp -p "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}" \ + "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}" ./boot/ touch --date=@0 ./* usage_size=$(du -sb --apparent-size . | tr -cd '[:digit:]') @@ -345,11 +345,11 @@ in }; target = "/isolinux/isolinux.cfg"; } - { source = config.boot.kernelPackages.kernel + "/bzImage"; - target = "/boot/bzImage"; + { source = config.boot.kernelPackages.kernel + "/" + config.system.boot.loader.kernelFile; + target = "/boot/" + config.system.boot.loader.kernelFile; } - { source = config.system.build.initialRamdisk + "/initrd"; - target = "/boot/initrd"; + { source = config.system.build.initialRamdisk + "/" + config.system.boot.loader.initrdFile; + target = "/boot/" + config.system.boot.loader.initrdFile; } { source = config.system.build.squashfsStore; target = "/nix-store.squashfs"; @@ -360,7 +360,7 @@ in { source = config.isoImage.splashImage; target = "/isolinux/background.png"; } - { source = pkgs.writeText "version" config.system.nixosVersion; + { source = pkgs.writeText "version" config.system.nixos.label; target = "/version.txt"; } ] ++ optionals config.isoImage.makeEfiBootable [ diff --git a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix index f23275bc16d5..08903ba397a1 100644 --- a/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix +++ b/nixos/modules/installer/cd-dvd/sd-image-armv7l-multiplatform.nix @@ -43,11 +43,18 @@ in sdImage = { populateBootCommands = let configTxt = pkgs.writeText "config.txt" '' + # Prevent the firmware from smashing the framebuffer setup done by the mainline kernel + # when attempting to show low-voltage or overtemperature warnings. + avoid_warnings=1 + [pi2] kernel=u-boot-rpi2.bin [pi3] kernel=u-boot-rpi3.bin + + # U-Boot used to need this to work, regardless of whether UART is actually used or not. + # TODO: check when/if this can be removed. enable_uart=1 ''; in '' diff --git a/nixos/modules/installer/cd-dvd/system-tarball.nix b/nixos/modules/installer/cd-dvd/system-tarball.nix index 1962a1959ead..e72d4a5b4910 100644 --- a/nixos/modules/installer/cd-dvd/system-tarball.nix +++ b/nixos/modules/installer/cd-dvd/system-tarball.nix @@ -8,7 +8,7 @@ with lib; let - versionFile = pkgs.writeText "nixos-version" config.system.nixosVersion; + versionFile = pkgs.writeText "nixos-label" config.system.nixos.label; in @@ -58,8 +58,8 @@ in # Individual files to be included on the CD, outside of the Nix # store on the CD. tarball.contents = - [ { source = config.system.build.initialRamdisk + "/initrd"; - target = "/boot/initrd"; + [ { source = config.system.build.initialRamdisk + "/" + config.system.boot.loader.initrdFile; + target = "/boot/" + config.system.boot.loader.initrdFile; } { source = versionFile; target = "/nixos-version.txt"; diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl index 7c737e84de0a..a82ee63fd0cd 100644 --- a/nixos/modules/installer/tools/nixos-generate-config.pl +++ b/nixos/modules/installer/tools/nixos-generate-config.pl @@ -625,7 +625,7 @@ $bootLoaderConfig # compatible, in order to avoid breaking some software such as database # servers. You should change this only after NixOS release notes say you # should. - system.stateVersion = "${\(qw(@nixosRelease@))}"; # Did you read the comment? + system.stateVersion = "${\(qw(@release@))}"; # Did you read the comment? } EOF diff --git a/nixos/modules/installer/tools/nixos-version.sh b/nixos/modules/installer/tools/nixos-version.sh index 77a1b458a342..190c49a33ec6 100644 --- a/nixos/modules/installer/tools/nixos-version.sh +++ b/nixos/modules/installer/tools/nixos-version.sh @@ -6,9 +6,9 @@ case "$1" in exit 1 ;; --hash|--revision) - echo "@nixosRevision@" + echo "@revision@" ;; *) - echo "@nixosVersion@ (@nixosCodeName@)" + echo "@version@ (@codeName@)" ;; esac diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix index cdd561b68403..beac9e29d59c 100644 --- a/nixos/modules/installer/tools/tools.nix +++ b/nixos/modules/installer/tools/tools.nix @@ -40,7 +40,7 @@ let src = ./nixos-generate-config.pl; path = [ pkgs.btrfs-progs ]; perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl"; - inherit (config.system) nixosRelease; + inherit (config.system.nixos) release; }; nixos-option = makeProg { @@ -51,7 +51,7 @@ let nixos-version = makeProg { name = "nixos-version"; src = ./nixos-version.sh; - inherit (config.system) nixosVersion nixosCodeName nixosRevision; + inherit (config.system.nixos) version codeName revision; }; nixos-enter = makeProg { diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 28ed10a5ece6..c0c6a6ef9244 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -303,6 +303,7 @@ restya-board = 284; mighttpd2 = 285; hass = 286; + monero = 287; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -574,6 +575,7 @@ restya-board = 284; mighttpd2 = 285; hass = 286; + monero = 287; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/misc/label.nix b/nixos/modules/misc/label.nix new file mode 100644 index 000000000000..250914e8f82e --- /dev/null +++ b/nixos/modules/misc/label.nix @@ -0,0 +1,72 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.system.nixos; +in + +{ + + options.system = { + + nixos.label = mkOption { + type = types.str; + description = '' + NixOS version name to be used in the names of generated + outputs and boot labels. + + If you ever wanted to influence the labels in your GRUB menu, + this is the option for you. + + The default is <option>system.nixos.tags</option> separated by + "-" + "-" + <envar>NIXOS_LABEL_VERSION</envar> environment + variable (defaults to the value of + <option>system.nixos.version</option>). + + Can be overriden by setting <envar>NIXOS_LABEL</envar>. + + Useful for not loosing track of configurations built from different + nixos branches/revisions, e.g.: + + <screen> + #!/bin/sh + today=`date +%Y%m%d` + branch=`(cd nixpkgs ; git branch 2>/dev/null | sed -n '/^\* / { s|^\* ||; p; }')` + revision=`(cd nixpkgs ; git rev-parse HEAD)` + export NIXOS_LABEL_VERSION="$today.$branch-''${revision:0:7}" + nixos-rebuild switch</screen> + ''; + }; + + nixos.tags = mkOption { + type = types.listOf types.str; + default = []; + example = [ "with-xen" ]; + description = '' + Strings to prefix to the default + <option>system.nixos.label</option>. + + Useful for not loosing track of configurations built with + different options, e.g.: + + <screen> + { + system.nixos.tags = [ "with-xen" ]; + virtualisation.xen.enable = true; + } + </screen> + ''; + }; + + }; + + config = { + # This is set here rather than up there so that changing it would + # not rebuild the manual + system.nixos.label = mkDefault (maybeEnv "NIXOS_LABEL" + (concatStringsSep "-" (sort (x: y: x < y) cfg.tags) + + "-" + maybeEnv "NIXOS_LABEL_VERSION" cfg.version)); + }; + +} diff --git a/nixos/modules/misc/nixpkgs.nix b/nixos/modules/misc/nixpkgs.nix index c3e7ab9a666a..e747fbc6755c 100644 --- a/nixos/modules/misc/nixpkgs.nix +++ b/nixos/modules/misc/nixpkgs.nix @@ -3,6 +3,8 @@ with lib; let + cfg = config.nixpkgs; + isConfig = x: builtins.isAttrs x || lib.isFunction x; @@ -42,12 +44,51 @@ let merge = lib.mergeOneOption; }; - _pkgs = import ../../.. config.nixpkgs; + pkgsType = mkOptionType { + name = "nixpkgs"; + description = "An evaluation of Nixpkgs; the top level attribute set of packages"; + check = builtins.isAttrs; + }; in { options.nixpkgs = { + + pkgs = mkOption { + defaultText = literalExample + ''import "''${nixos}/.." { + inherit (config.nixpkgs) config overlays system; + } + ''; + default = import ../../.. { inherit (cfg) config overlays system; }; + type = pkgsType; + example = literalExample ''import <nixpkgs> {}''; + description = '' + This is the evaluation of Nixpkgs that will be provided to + all NixOS modules. Defining this option has the effect of + ignoring the other options that would otherwise be used to + evaluate Nixpkgs, because those are arguments to the default + value. The default value imports the Nixpkgs source files + relative to the location of this NixOS module, because + NixOS and Nixpkgs are distributed together for consistency, + so the <code>nixos</code> in the default value is in fact a + relative path. The <code>config</code>, <code>overlays</code> + and <code>system</code> come from this option's siblings. + + This option can be used by applications like NixOps to increase + the performance of evaluation, or to create packages that depend + on a container that should be built with the exact same evaluation + of Nixpkgs, for example. Applications like this should set + their default value using <code>lib.mkDefault</code>, so + user-provided configuration can override it without using + <code>lib</code>. + + Note that using a distinct version of Nixpkgs with NixOS may + be an unexpected source of problems. Use this option with care. + ''; + }; + config = mkOption { default = {}; example = literalExample @@ -59,6 +100,8 @@ in The configuration of the Nix Packages collection. (For details, see the Nixpkgs documentation.) It allows you to set package configuration options. + + Ignored when <code>nixpkgs.pkgs</code> is set. ''; }; @@ -82,6 +125,8 @@ in takes as an argument the <emphasis>original</emphasis> Nixpkgs. The first argument should be used for finding dependencies, and the second should be used for overriding recipes. + + Ignored when <code>nixpkgs.pkgs</code> is set. ''; }; @@ -93,14 +138,16 @@ in If unset, it defaults to the platform type of your host system. Specifying this option is useful when doing distributed multi-platform deployment, or when building virtual machines. + + Ignored when <code>nixpkgs.pkgs</code> is set. ''; }; }; config = { _module.args = { - pkgs = _pkgs; - pkgs_i686 = _pkgs.pkgsi686Linux; + pkgs = cfg.pkgs; + pkgs_i686 = cfg.pkgs.pkgsi686Linux; }; }; } diff --git a/nixos/modules/misc/version.nix b/nixos/modules/misc/version.nix index 48cde2ebbc8a..6af584250a70 100644 --- a/nixos/modules/misc/version.nix +++ b/nixos/modules/misc/version.nix @@ -3,7 +3,7 @@ with lib; let - cfg = config.system; + cfg = config.system.nixos; releaseFile = "${toString pkgs.path}/.version"; suffixFile = "${toString pkgs.path}/.version-suffix"; @@ -16,51 +16,27 @@ in options.system = { - stateVersion = mkOption { - type = types.str; - default = cfg.nixosRelease; - description = '' - Every once in a while, a new NixOS release may change - configuration defaults in a way incompatible with stateful - data. For instance, if the default version of PostgreSQL - changes, the new version will probably be unable to read your - existing databases. To prevent such breakage, you can set the - value of this option to the NixOS release with which you want - to be compatible. The effect is that NixOS will option - defaults corresponding to the specified release (such as using - an older version of PostgreSQL). - ''; - }; - - nixosLabel = mkOption { - type = types.str; - description = '' - Label to be used in the names of generated outputs and boot - labels. - ''; - }; - - nixosVersion = mkOption { + nixos.version = mkOption { internal = true; type = types.str; description = "The full NixOS version (e.g. <literal>16.03.1160.f2d4ee1</literal>)."; }; - nixosRelease = mkOption { + nixos.release = mkOption { readOnly = true; type = types.str; default = fileContents releaseFile; description = "The NixOS release (e.g. <literal>16.03</literal>)."; }; - nixosVersionSuffix = mkOption { + nixos.versionSuffix = mkOption { internal = true; type = types.str; default = if pathExists suffixFile then fileContents suffixFile else "pre-git"; description = "The NixOS version suffix (e.g. <literal>1160.f2d4ee1</literal>)."; }; - nixosRevision = mkOption { + nixos.revision = mkOption { internal = true; type = types.str; default = if pathIsDirectory gitRepo then commitIdFromGitRepo gitRepo @@ -69,12 +45,28 @@ in description = "The Git revision from which this NixOS configuration was built."; }; - nixosCodeName = mkOption { + nixos.codeName = mkOption { readOnly = true; type = types.str; description = "The NixOS release code name (e.g. <literal>Emu</literal>)."; }; + stateVersion = mkOption { + type = types.str; + default = cfg.release; + description = '' + Every once in a while, a new NixOS release may change + configuration defaults in a way incompatible with stateful + data. For instance, if the default version of PostgreSQL + changes, the new version will probably be unable to read your + existing databases. To prevent such breakage, you can set the + value of this option to the NixOS release with which you want + to be compatible. The effect is that NixOS will option + defaults corresponding to the specified release (such as using + an older version of PostgreSQL). + ''; + }; + defaultChannel = mkOption { internal = true; type = types.str; @@ -86,16 +78,15 @@ in config = { - system = { + system.nixos = { # These defaults are set here rather than up there so that # changing them would not rebuild the manual - nixosLabel = mkDefault cfg.nixosVersion; - nixosVersion = mkDefault (cfg.nixosRelease + cfg.nixosVersionSuffix); - nixosRevision = mkIf (pathIsDirectory gitRepo) (mkDefault gitCommitId); - nixosVersionSuffix = mkIf (pathIsDirectory gitRepo) (mkDefault (".git." + gitCommitId)); + version = mkDefault (cfg.release + cfg.versionSuffix); + revision = mkIf (pathIsDirectory gitRepo) (mkDefault gitCommitId); + versionSuffix = mkIf (pathIsDirectory gitRepo) (mkDefault (".git." + gitCommitId)); # Note: code names must only increase in alphabetical order. - nixosCodeName = "Impala"; + codeName = "Impala"; }; # Generate /etc/os-release. See @@ -105,10 +96,10 @@ in '' NAME=NixOS ID=nixos - VERSION="${config.system.nixosVersion} (${config.system.nixosCodeName})" - VERSION_CODENAME=${toLower config.system.nixosCodeName} - VERSION_ID="${config.system.nixosVersion}" - PRETTY_NAME="NixOS ${config.system.nixosVersion} (${config.system.nixosCodeName})" + VERSION="${cfg.version} (${cfg.codeName})" + VERSION_CODENAME=${toLower cfg.codeName} + VERSION_ID="${cfg.version}" + PRETTY_NAME="NixOS ${cfg.version} (${cfg.codeName})" HOME_URL="https://nixos.org/" SUPPORT_URL="https://nixos.org/nixos/support.html" BUG_REPORT_URL="https://github.com/NixOS/nixpkgs/issues" diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 2ec8b28c3fc4..098fac7a0c2d 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -60,6 +60,7 @@ ./misc/extra-arguments.nix ./misc/ids.nix ./misc/lib.nix + ./misc/label.nix ./misc/locate.nix ./misc/meta.nix ./misc/nixpkgs.nix @@ -75,6 +76,7 @@ ./programs/cdemu.nix ./programs/chromium.nix ./programs/command-not-found/command-not-found.nix + ./programs/criu.nix ./programs/dconf.nix ./programs/environment.nix ./programs/fish.nix @@ -92,6 +94,7 @@ ./programs/nano.nix ./programs/npm.nix ./programs/oblogout.nix + ./programs/plotinus.nix ./programs/qt5ct.nix ./programs/rootston.nix ./programs/screen.nix @@ -102,6 +105,7 @@ ./programs/ssh.nix ./programs/ssmtp.nix ./programs/sysdig.nix + ./programs/systemtap.nix ./programs/sway.nix ./programs/thefuck.nix ./programs/tmux.nix @@ -111,8 +115,10 @@ ./programs/wireshark.nix ./programs/xfs_quota.nix ./programs/xonsh.nix + ./programs/yabar.nix ./programs/zsh/oh-my-zsh.nix ./programs/zsh/zsh.nix + ./programs/zsh/zsh-autoenv.nix ./programs/zsh/zsh-syntax-highlighting.nix ./rename.nix ./security/acme.nix @@ -151,6 +157,7 @@ ./services/backup/almir.nix ./services/backup/bacula.nix ./services/backup/crashplan.nix + ./services/backup/crashplan-small-business.nix ./services/backup/mysql-backup.nix ./services/backup/postgresql-backup.nix ./services/backup/rsnapshot.nix @@ -200,6 +207,7 @@ ./services/desktops/dleyna-renderer.nix ./services/desktops/dleyna-server.nix ./services/desktops/geoclue2.nix + ./services/desktops/pipewire.nix ./services/desktops/gnome3/at-spi2-core.nix ./services/desktops/gnome3/chrome-gnome-shell.nix ./services/desktops/gnome3/evolution-data-server.nix @@ -238,6 +246,7 @@ ./services/hardware/pcscd.nix ./services/hardware/pommed.nix ./services/hardware/sane.nix + ./services/hardware/sane_extra_backends/brscan4.nix ./services/hardware/tcsd.nix ./services/hardware/tlp.nix ./services/hardware/thinkfan.nix @@ -334,6 +343,7 @@ ./services/misc/nix-optimise.nix ./services/misc/nixos-manual.nix ./services/misc/nix-ssh-serve.nix + ./services/misc/novacomd.nix ./services/misc/nzbget.nix ./services/misc/octoprint.nix ./services/misc/osrm.nix @@ -417,7 +427,8 @@ ./services/network-filesystems/ipfs.nix ./services/network-filesystems/netatalk.nix ./services/network-filesystems/nfsd.nix - ./services/network-filesystems/openafs-client/default.nix + ./services/network-filesystems/openafs/client.nix + ./services/network-filesystems/openafs/server.nix ./services/network-filesystems/rsyncd.nix ./services/network-filesystems/samba.nix ./services/network-filesystems/tahoe.nix @@ -491,6 +502,7 @@ ./services/networking/minidlna.nix ./services/networking/miniupnpd.nix ./services/networking/mosquitto.nix + ./services/networking/monero.nix ./services/networking/miredo.nix ./services/networking/mstpd.nix ./services/networking/murmur.nix @@ -501,6 +513,7 @@ ./services/networking/ngircd.nix ./services/networking/nghttpx/default.nix ./services/networking/nix-serve.nix + ./services/networking/nixops-dns.nix ./services/networking/nntp-proxy.nix ./services/networking/nsd.nix ./services/networking/ntopng.nix @@ -528,6 +541,7 @@ ./services/networking/redsocks.nix ./services/networking/resilio.nix ./services/networking/rpcbind.nix + ./services/networking/rxe.nix ./services/networking/sabnzbd.nix ./services/networking/searx.nix ./services/networking/seeks.nix @@ -685,6 +699,7 @@ ./services/x11/xserver.nix ./system/activation/activation-script.nix ./system/activation/top-level.nix + ./system/boot/binfmt.nix ./system/boot/coredump.nix ./system/boot/emergency-mode.nix ./system/boot/grow-partition.nix diff --git a/nixos/modules/programs/adb.nix b/nixos/modules/programs/adb.nix index 18290555b79d..f648d70bd9fa 100644 --- a/nixos/modules/programs/adb.nix +++ b/nixos/modules/programs/adb.nix @@ -16,6 +16,7 @@ with lib; To grant access to a user, it must be part of adbusers group: <code>users.extraUsers.alice.extraGroups = ["adbusers"];</code> ''; + relatedPackages = [ ["androidenv" "platformTools"] ]; }; }; }; diff --git a/nixos/modules/programs/criu.nix b/nixos/modules/programs/criu.nix new file mode 100644 index 000000000000..48cf5c88a9fc --- /dev/null +++ b/nixos/modules/programs/criu.nix @@ -0,0 +1,26 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let cfg = config.programs.criu; +in { + + options = { + programs.criu = { + enable = mkOption { + default = false; + description = '' + Install <command>criu</command> along with necessary kernel options. + ''; + }; + }; + }; + config = mkIf cfg.enable { + system.requiredKernelConfig = with config.lib.kernelConfig; [ + (isYes "CHECKPOINT_RESTORE") + ]; + boot.kernel.features.criu = true; + environment.systemPackages = [ pkgs.criu ]; + }; + +} diff --git a/nixos/modules/programs/plotinus.nix b/nixos/modules/programs/plotinus.nix new file mode 100644 index 000000000000..065e72d6c374 --- /dev/null +++ b/nixos/modules/programs/plotinus.nix @@ -0,0 +1,36 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.plotinus; +in +{ + meta = { + maintainers = pkgs.plotinus.meta.maintainers; + doc = ./plotinus.xml; + }; + + ###### interface + + options = { + programs.plotinus = { + enable = mkOption { + default = false; + description = '' + Whether to enable the Plotinus GTK+3 plugin. Plotinus provides a + popup (triggered by Ctrl-Shift-P) to search the menus of a + compatible application. + ''; + type = types.bool; + }; + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + environment.variables.XDG_DATA_DIRS = [ "${pkgs.plotinus}/share/gsettings-schemas/${pkgs.plotinus.name}" ]; + environment.variables.GTK3_MODULES = [ "${pkgs.plotinus}/lib/libplotinus.so" ]; + }; +} diff --git a/nixos/modules/programs/plotinus.xml b/nixos/modules/programs/plotinus.xml new file mode 100644 index 000000000000..85b0e023e6c1 --- /dev/null +++ b/nixos/modules/programs/plotinus.xml @@ -0,0 +1,25 @@ +<chapter xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xi="http://www.w3.org/2001/XInclude" + version="5.0" + xml:id="module-program-plotinus"> + +<title>Plotinus</title> + +<para><emphasis>Source:</emphasis> <filename>modules/programs/plotinus.nix</filename></para> + +<para><emphasis>Upstream documentation:</emphasis> <link xlink:href="https://github.com/p-e-w/plotinus"/></para> + +<para>Plotinus is a searchable command palette in every modern GTK+ application.</para> + +<para>When in a GTK+3 application and Plotinus is enabled, you can press <literal>Ctrl+Shift+P</literal> to open the command palette. The command palette provides a searchable list of of all menu items in the application.</para> + +<para>To enable Plotinus, add the following to your <filename>configuration.nix</filename>: + +<programlisting> +programs.plotinus.enable = true; +</programlisting> + +</para> + +</chapter> diff --git a/nixos/modules/programs/systemtap.nix b/nixos/modules/programs/systemtap.nix new file mode 100644 index 000000000000..fd84732cd412 --- /dev/null +++ b/nixos/modules/programs/systemtap.nix @@ -0,0 +1,28 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let cfg = config.programs.systemtap; +in { + + options = { + programs.systemtap = { + enable = mkOption { + default = false; + description = '' + Install <command>systemtap</command> along with necessary kernel options. + ''; + }; + }; + }; + config = mkIf cfg.enable { + system.requiredKernelConfig = with config.lib.kernelConfig; [ + (isYes "DEBUG") + ]; + boot.kernel.features.debug = true; + environment.systemPackages = [ + config.boot.kernelPackages.systemtap + ]; + }; + +} diff --git a/nixos/modules/programs/tmux.nix b/nixos/modules/programs/tmux.nix index 1eb6fa6bf2fa..4a60403a2827 100644 --- a/nixos/modules/programs/tmux.nix +++ b/nixos/modules/programs/tmux.nix @@ -61,7 +61,12 @@ in { options = { programs.tmux = { - enable = mkEnableOption "<command>tmux</command> - a <command>screen</command> replacement."; + enable = mkOption { + type = types.bool; + default = false; + description = "Whenever to configure <command>tmux</command> system-wide."; + relatedPackages = [ "tmux" ]; + }; aggressiveResize = mkOption { default = false; diff --git a/nixos/modules/programs/yabar.nix b/nixos/modules/programs/yabar.nix new file mode 100644 index 000000000000..a01083c3ace9 --- /dev/null +++ b/nixos/modules/programs/yabar.nix @@ -0,0 +1,149 @@ +{ lib, pkgs, config, ... }: + +with lib; + +let + cfg = config.programs.yabar; + + mapExtra = v: lib.concatStringsSep "\n" (mapAttrsToList ( + key: val: "${key} = ${if (isString val) then "\"${val}\"" else "${builtins.toString val}"};" + ) v); + + listKeys = r: concatStringsSep "," (map (n: "\"${n}\"") (attrNames r)); + + configFile = let + bars = mapAttrsToList ( + name: cfg: '' + ${name}: { + font: "${cfg.font}"; + position: "${cfg.position}"; + + ${mapExtra cfg.extra} + + block-list: [${listKeys cfg.indicators}] + + ${concatStringsSep "\n" (mapAttrsToList ( + name: cfg: '' + ${name}: { + exec: "${cfg.exec}"; + align: "${cfg.align}"; + ${mapExtra cfg.extra} + }; + '' + ) cfg.indicators)} + }; + '' + ) cfg.bars; + in pkgs.writeText "yabar.conf" '' + bar-list = [${listKeys cfg.bars}]; + ${concatStringsSep "\n" bars} + ''; +in + { + options.programs.yabar = { + enable = mkEnableOption "yabar"; + + package = mkOption { + default = pkgs.yabar; + example = literalExample "pkgs.yabar-unstable"; + type = types.package; + + description = '' + The package which contains the `yabar` binary. + + Nixpkgs provides the `yabar` and `yabar-unstable` + derivations since 18.03, so it's possible to choose. + ''; + }; + + bars = mkOption { + default = {}; + type = types.attrsOf(types.submodule { + options = { + font = mkOption { + default = "sans bold 9"; + example = "Droid Sans, FontAwesome Bold 9"; + type = types.string; + + description = '' + The font that will be used to draw the status bar. + ''; + }; + + position = mkOption { + default = "top"; + example = "bottom"; + type = types.enum [ "top" "bottom" ]; + + description = '' + The position where the bar will be rendered. + ''; + }; + + extra = mkOption { + default = {}; + type = types.attrsOf types.string; + + description = '' + An attribute set which contains further attributes of a bar. + ''; + }; + + indicators = mkOption { + default = {}; + type = types.attrsOf(types.submodule { + options.exec = mkOption { + example = "YABAR_DATE"; + type = types.string; + description = '' + The type of the indicator to be executed. + ''; + }; + + options.align = mkOption { + default = "left"; + example = "right"; + type = types.enum [ "left" "center" "right" ]; + + description = '' + Whether to align the indicator at the left or right of the bar. + ''; + }; + + options.extra = mkOption { + default = {}; + type = types.attrsOf (types.either types.string types.int); + + description = '' + An attribute set which contains further attributes of a indicator. + ''; + }; + }); + + description = '' + Indicators that should be rendered by yabar. + ''; + }; + }; + }); + + description = '' + List of bars that should be rendered by yabar. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.user.services.yabar = { + description = "yabar service"; + wantedBy = [ "graphical-session.target" ]; + partOf = [ "graphical-session.target" ]; + + script = '' + ${cfg.package}/bin/yabar -c ${configFile} + ''; + + serviceConfig.Restart = "always"; + }; + }; + } diff --git a/nixos/modules/programs/zsh/zsh-autoenv.nix b/nixos/modules/programs/zsh/zsh-autoenv.nix new file mode 100644 index 000000000000..630114bcda9f --- /dev/null +++ b/nixos/modules/programs/zsh/zsh-autoenv.nix @@ -0,0 +1,28 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.zsh.zsh-autoenv; +in { + options = { + programs.zsh.zsh-autoenv = { + enable = mkEnableOption "zsh-autoenv"; + package = mkOption { + default = pkgs.zsh-autoenv; + defaultText = "pkgs.zsh-autoenv"; + description = '' + Package to install for `zsh-autoenv` usage. + ''; + + type = types.package; + }; + }; + }; + + config = mkIf cfg.enable { + programs.zsh.interactiveShellInit = '' + source ${cfg.package}/share/zsh-autoenv/autoenv.zsh + ''; + }; +} diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 562be13a3f64..da83baed3719 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -189,6 +189,14 @@ with lib; # Profile splitting (mkRenamedOptionModule [ "virtualization" "growPartition" ] [ "boot" "growPartition" ]) + # misc/version.nix + (mkRenamedOptionModule [ "config" "system" "nixosVersion" ] [ "config" "system" "nixos" "version" ]) + (mkRenamedOptionModule [ "config" "system" "nixosRelease" ] [ "config" "system" "nixos" "release" ]) + (mkRenamedOptionModule [ "config" "system" "nixosVersionSuffix" ] [ "config" "system" "nixos" "versionSuffix" ]) + (mkRenamedOptionModule [ "config" "system" "nixosRevision" ] [ "config" "system" "nixos" "revision" ]) + (mkRenamedOptionModule [ "config" "system" "nixosCodeName" ] [ "config" "system" "nixos" "codeName" ]) + (mkRenamedOptionModule [ "config" "system" "nixosLabel" ] [ "config" "system" "nixos" "label" ]) + # Options that are obsolete and have no replacement. (mkRemovedOptionModule [ "boot" "initrd" "luks" "enable" ] "") (mkRemovedOptionModule [ "programs" "bash" "enable" ] "") @@ -205,11 +213,14 @@ with lib; "See the 16.09 release notes for more information.") (mkRemovedOptionModule [ "services" "phpfpm" "phpIni" ] "") (mkRemovedOptionModule [ "services" "dovecot2" "package" ] "") + (mkRemovedOptionModule [ "services" "firefox" "syncserver" "user" ] "") + (mkRemovedOptionModule [ "services" "firefox" "syncserver" "group" ] "") (mkRemovedOptionModule [ "fonts" "fontconfig" "hinting" "style" ] "") (mkRemovedOptionModule [ "services" "xserver" "displayManager" "sddm" "themes" ] "Set the option `services.xserver.displayManager.sddm.package' instead.") (mkRemovedOptionModule [ "fonts" "fontconfig" "forceAutohint" ] "") (mkRemovedOptionModule [ "fonts" "fontconfig" "renderMonoTTFAsBitmap" ] "") + (mkRemovedOptionModule [ "virtualisation" "xen" "qemu" ] "You don't need this option anymore, it will work without it.") # ZSH (mkRenamedOptionModule [ "programs" "zsh" "enableSyntaxHighlighting" ] [ "programs" "zsh" "syntaxHighlighting" "enable" ]) @@ -220,5 +231,8 @@ with lib; (mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "theme" ] [ "programs" "zsh" "ohMyZsh" "theme" ]) (mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "custom" ] [ "programs" "zsh" "ohMyZsh" "custom" ]) (mkRenamedOptionModule [ "programs" "zsh" "oh-my-zsh" "plugins" ] [ "programs" "zsh" "ohMyZsh" "plugins" ]) + + # Xen + (mkRenamedOptionModule [ "virtualisation" "xen" "qemu-package" ] [ "virtualisation" "xen" "package-qemu" ]) ]; } diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix index 5940f471883c..0736239ed2cf 100644 --- a/nixos/modules/security/acme.nix +++ b/nixos/modules/security/acme.nix @@ -6,10 +6,11 @@ let cfg = config.security.acme; - certOpts = { ... }: { + certOpts = { name, ... }: { options = { webroot = mkOption { type = types.str; + example = "/var/lib/acme/acme-challenges"; description = '' Where the webroot of the HTTP vhost is located. <filename>.well-known/acme-challenge/</filename> directory @@ -20,8 +21,8 @@ let }; domain = mkOption { - type = types.nullOr types.str; - default = null; + type = types.str; + default = name; description = "Domain to fetch certificate for (defaults to the entry name)"; }; @@ -48,7 +49,7 @@ let default = false; description = '' Give read permissions to the specified group - (<option>security.acme.group</option>) to read SSL private certificates. + (<option>security.acme.cert.<name>.group</option>) to read SSL private certificates. ''; }; @@ -87,7 +88,7 @@ let } ''; description = '' - Extra domain names for which certificates are to be issued, with their + A list of extra domain names, which are included in the one certificate to be issued, with their own server roots if needed. ''; }; @@ -193,10 +194,9 @@ in servicesLists = mapAttrsToList certToServices cfg.certs; certToServices = cert: data: let - domain = if data.domain != null then data.domain else cert; cpath = "${cfg.directory}/${cert}"; rights = if data.allowKeysForGroup then "750" else "700"; - cmdline = [ "-v" "-d" domain "--default_root" data.webroot "--valid_min" cfg.validMin "--tos_sha256" cfg.tosHash ] + cmdline = [ "-v" "-d" data.domain "--default_root" data.webroot "--valid_min" cfg.validMin "--tos_sha256" cfg.tosHash ] ++ optionals (data.email != null) [ "--email" data.email ] ++ concatMap (p: [ "-f" p ]) data.plugins ++ concatLists (mapAttrsToList (name: root: [ "-d" (if root == null then name else "${name}:${root}")]) data.extraDomains) diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 3fff9e78aa19..f39f64033ca7 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -46,6 +46,18 @@ let ''; }; + googleAuthenticator = { + enable = mkOption { + default = false; + type = types.bool; + description = '' + If set, users with enabled Google Authenticator (created + <filename>~/.google_authenticator</filename>) will be required + to provide Google Authenticator token to log in. + ''; + }; + }; + usbAuth = mkOption { default = config.security.pam.usb.enable; type = types.bool; @@ -284,7 +296,12 @@ let # prompts the user for password so we run it once with 'required' at an # earlier point and it will run again with 'sufficient' further down. # We use try_first_pass the second time to avoid prompting password twice - (optionalString (cfg.unixAuth && (config.security.pam.enableEcryptfs || cfg.pamMount || cfg.enableKwallet || cfg.enableGnomeKeyring)) '' + (optionalString (cfg.unixAuth && + (config.security.pam.enableEcryptfs + || cfg.pamMount + || cfg.enableKwallet + || cfg.enableGnomeKeyring + || cfg.googleAuthenticator.enable)) '' auth required pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth ${optionalString config.security.pam.enableEcryptfs "auth optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap"} @@ -295,6 +312,8 @@ let " kwalletd=${pkgs.libsForQt5.kwallet.bin}/bin/kwalletd5")} ${optionalString cfg.enableGnomeKeyring ("auth optional ${pkgs.gnome3.gnome_keyring}/lib/security/pam_gnome_keyring.so")} + ${optionalString cfg.googleAuthenticator.enable + "auth required ${pkgs.googleAuthenticator}/lib/security/pam_google_authenticator.so no_increment_hotp"} '') + '' ${optionalString cfg.unixAuth "auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} likeauth try_first_pass"} diff --git a/nixos/modules/services/backup/crashplan-small-business.nix b/nixos/modules/services/backup/crashplan-small-business.nix new file mode 100644 index 000000000000..9497d8c18bb7 --- /dev/null +++ b/nixos/modules/services/backup/crashplan-small-business.nix @@ -0,0 +1,74 @@ +{ config, pkgs, lib, ... }: + +let + cfg = config.services.crashplansb; + crashplansb = pkgs.crashplansb.override { maxRam = cfg.maxRam; }; + varDir = "/var/lib/crashplan"; +in + +with lib; + +{ + options = { + services.crashplansb = { + enable = mkOption { + default = false; + type = types.bool; + description = '' + Starts crashplan for small business background service. + ''; + }; + maxRam = mkOption { + default = "1024m"; + example = "2G"; + type = types.str; + description = '' + Maximum amount of ram that the crashplan engine should use. + ''; + }; + openPorts = mkOption { + description = "Open ports in the firewall for crashplan."; + default = true; + type = types.bool; + }; + ports = mkOption { + # https://support.code42.com/Administrator/6/Planning_and_installing/TCP_and_UDP_ports_used_by_the_Code42_platform + # used ports can also be checked in the desktop app console using the command connection.info + description = "which ports to open."; + default = [ 4242 4243 4244 4247 ]; + type = types.listOf types.int; + }; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ crashplansb ]; + networking.firewall.allowedTCPPorts = mkIf cfg.openPorts cfg.ports; + + systemd.services.crashplansb = { + description = "CrashPlan Backup Engine"; + + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "local-fs.target" ]; + + preStart = '' + install -d -m 755 ${crashplansb.vardir} + install -d -m 700 ${crashplansb.vardir}/conf + install -d -m 700 ${crashplansb.manifestdir} + install -d -m 700 ${crashplansb.vardir}/cache + install -d -m 700 ${crashplansb.vardir}/backupArchives + install -d -m 777 ${crashplansb.vardir}/log + cp -avn ${crashplansb}/conf.template/* ${crashplansb.vardir}/conf + ''; + + serviceConfig = { + Type = "forking"; + EnvironmentFile = "${crashplansb}/bin/run.conf"; + ExecStart = "${crashplansb}/bin/CrashPlanEngine start"; + ExecStop = "${crashplansb}/bin/CrashPlanEngine stop"; + PIDFile = "${crashplansb.vardir}/CrashPlanEngine.pid"; + WorkingDirectory = crashplansb; + }; + }; + }; +} diff --git a/nixos/modules/services/cluster/kubernetes/dashboard.nix b/nixos/modules/services/cluster/kubernetes/dashboard.nix index 75d71fccfda4..e331889b9dd5 100644 --- a/nixos/modules/services/cluster/kubernetes/dashboard.nix +++ b/nixos/modules/services/cluster/kubernetes/dashboard.nix @@ -6,12 +6,12 @@ let cfg = config.services.kubernetes.addons.dashboard; name = "gcr.io/google_containers/kubernetes-dashboard-amd64"; - version = "v1.6.3"; + version = "v1.8.2"; image = pkgs.dockerTools.pullImage { imageName = name; imageTag = version; - sha256 = "1sf54d96nkgic9hir9c6p14gw24ns1k5d5a0r1sg414kjrvic0b4"; + sha256 = "11h0fz3wxp0f10fsyqaxjm7l2qg7xws50dv5iwlck5gb1fjmajad"; }; in { options.services.kubernetes.addons.dashboard = { diff --git a/nixos/modules/services/cluster/kubernetes/default.nix b/nixos/modules/services/cluster/kubernetes/default.nix index 077953e4d4f8..4a2c6f0833eb 100644 --- a/nixos/modules/services/cluster/kubernetes/default.nix +++ b/nixos/modules/services/cluster/kubernetes/default.nix @@ -301,8 +301,8 @@ in { Kubernetes apiserver authorization mode (AlwaysAllow/AlwaysDeny/ABAC/RBAC). See <link xlink:href="http://kubernetes.io/docs/admin/authorization.html"/> ''; - default = ["RBAC"]; - type = types.listOf (types.enum ["AlwaysAllow" "AlwaysDeny" "ABAC" "RBAC"]); + default = ["RBAC" "Node"]; + type = types.listOf (types.enum ["AlwaysAllow" "AlwaysDeny" "ABAC" "RBAC" "Node"]); }; authorizationPolicy = mkOption { @@ -344,7 +344,7 @@ in { Kubernetes admission control plugins to use. See <link xlink:href="http://kubernetes.io/docs/admin/admission-controllers/"/> ''; - default = ["NamespaceLifecycle" "LimitRanger" "ServiceAccount" "ResourceQuota" "DefaultStorageClass" "DefaultTolerationSeconds"]; + default = ["NamespaceLifecycle" "LimitRanger" "ServiceAccount" "ResourceQuota" "DefaultStorageClass" "DefaultTolerationSeconds" "NodeRestriction"]; example = [ "NamespaceLifecycle" "NamespaceExists" "LimitRanger" "SecurityContextDeny" "ServiceAccount" "ResourceQuota" diff --git a/nixos/modules/services/computing/slurm/slurm.nix b/nixos/modules/services/computing/slurm/slurm.nix index fb91a29a4000..45d34f5b76f5 100644 --- a/nixos/modules/services/computing/slurm/slurm.nix +++ b/nixos/modules/services/computing/slurm/slurm.nix @@ -6,14 +6,20 @@ let cfg = config.services.slurm; # configuration file can be generated by http://slurm.schedmd.com/configurator.html - configFile = pkgs.writeText "slurm.conf" + configFile = pkgs.writeText "slurm.conf" '' ${optionalString (cfg.controlMachine != null) ''controlMachine=${cfg.controlMachine}''} ${optionalString (cfg.controlAddr != null) ''controlAddr=${cfg.controlAddr}''} ${optionalString (cfg.nodeName != null) ''nodeName=${cfg.nodeName}''} ${optionalString (cfg.partitionName != null) ''partitionName=${cfg.partitionName}''} + PlugStackConfig=${plugStackConfig} ${cfg.extraConfig} ''; + + plugStackConfig = pkgs.writeText "plugstack.conf" + '' + ${optionalString cfg.enableSrunX11 ''optional ${pkgs.slurm-spank-x11}/lib/x11.so''} + ''; in { @@ -28,7 +34,7 @@ in enable = mkEnableOption "slurm control daemon"; }; - + client = { enable = mkEnableOption "slurm rlient daemon"; @@ -86,8 +92,19 @@ in ''; }; + enableSrunX11 = mkOption { + default = false; + type = types.bool; + description = '' + If enabled srun will accept the option "--x11" to allow for X11 forwarding + from within an interactive session or a batch job. This activates the + slurm-spank-x11 module. Note that this requires 'services.openssh.forwardX11' + to be enabled on the compute nodes. + ''; + }; + extraConfig = mkOption { - default = ""; + default = ""; type = types.lines; description = '' Extra configuration options that will be added verbatim at @@ -134,7 +151,8 @@ in environment.systemPackages = [ wrappedSlurm ]; systemd.services.slurmd = mkIf (cfg.client.enable) { - path = with pkgs; [ wrappedSlurm coreutils ]; + path = with pkgs; [ wrappedSlurm coreutils ] + ++ lib.optional cfg.enableSrunX11 slurm-spank-x11; wantedBy = [ "multi-user.target" ]; after = [ "systemd-tmpfiles-clean.service" ]; @@ -152,8 +170,9 @@ in }; systemd.services.slurmctld = mkIf (cfg.server.enable) { - path = with pkgs; [ wrappedSlurm munge coreutils ]; - + path = with pkgs; [ wrappedSlurm munge coreutils ] + ++ lib.optional cfg.enableSrunX11 slurm-spank-x11; + wantedBy = [ "multi-user.target" ]; after = [ "network.target" "munged.service" ]; requires = [ "munged.service" ]; diff --git a/nixos/modules/services/continuous-integration/buildkite-agent.nix b/nixos/modules/services/continuous-integration/buildkite-agent.nix index 1b0198ac93fe..0a0c9f665d25 100644 --- a/nixos/modules/services/continuous-integration/buildkite-agent.nix +++ b/nixos/modules/services/continuous-integration/buildkite-agent.nix @@ -4,6 +4,31 @@ with lib; let cfg = config.services.buildkite-agent; + + mkHookOption = { name, description, example ? null }: { + inherit name; + value = mkOption { + default = null; + inherit description; + type = types.nullOr types.lines; + } // (if example == null then {} else { inherit example; }); + }; + mkHookOptions = hooks: listToAttrs (map mkHookOption hooks); + + hooksDir = let + mkHookEntry = name: value: '' + cat > $out/${name} <<EOF + #! ${pkgs.stdenv.shell} + set -e + ${value} + EOF + chmod 755 $out/${name} + ''; + in pkgs.runCommand "buildkite-agent-hooks" {} '' + mkdir $out + ${concatStringsSep "\n" (mapAttrsToList mkHookEntry (filterAttrs (n: v: v != null) cfg.hooks))} + ''; + in { @@ -43,25 +68,28 @@ in name = mkOption { type = types.str; + default = "%hostname-%n"; description = '' The name of the agent. ''; }; - hooksPath = mkOption { - type = types.path; - default = "${pkgs.buildkite-agent}/share/hooks"; - defaultText = "${pkgs.buildkite-agent}/share/hooks"; + meta-data = mkOption { + type = types.str; + default = ""; + example = "queue=default,docker=true,ruby2=true"; description = '' - Path to the directory storing the hooks. + Meta data for the agent. This is a comma-separated list of + <code>key=value</code> pairs. ''; }; - meta-data = mkOption { - type = types.str; + extraConfig = mkOption { + type = types.lines; default = ""; + example = "debug=true"; description = '' - Meta data for the agent. + Extra lines to be added verbatim to the configuration file. ''; }; @@ -85,6 +113,74 @@ in ''; }; }; + + hooks = mkHookOptions [ + { name = "checkout"; + description = '' + The `checkout` hook script will replace the default checkout routine of the + bootstrap.sh script. You can use this hook to do your own SCM checkout + behaviour + ''; } + { name = "command"; + description = '' + The `command` hook script will replace the default implementation of running + the build command. + ''; } + { name = "environment"; + description = '' + The `environment` hook will run before all other commands, and can be used + to set up secrets, data, etc. Anything exported in hooks will be available + to the build script. + + Note: the contents of this file will be copied to the world-readable + Nix store. + ''; + example = '' + export SECRET_VAR=`head -1 /run/keys/secret` + ''; } + { name = "post-artifact"; + description = '' + The `post-artifact` hook will run just after artifacts are uploaded + ''; } + { name = "post-checkout"; + description = '' + The `post-checkout` hook will run after the bootstrap script has checked out + your projects source code. + ''; } + { name = "post-command"; + description = '' + The `post-command` hook will run after the bootstrap script has run your + build commands + ''; } + { name = "pre-artifact"; + description = '' + The `pre-artifact` hook will run just before artifacts are uploaded + ''; } + { name = "pre-checkout"; + description = '' + The `pre-checkout` hook will run just before your projects source code is + checked out from your SCM provider + ''; } + { name = "pre-command"; + description = '' + The `pre-command` hook will run just before your build command runs + ''; } + { name = "pre-exit"; + description = '' + The `pre-exit` hook will run just before your build job finishes + ''; } + ]; + + hooksPath = mkOption { + type = types.path; + default = hooksDir; + defaultText = "generated from services.buildkite-agent.hooks"; + description = '' + Path to the directory storing the hooks. + Consider using <option>services.buildkite-agent.hooks.<name></option> + instead. + ''; + }; }; }; @@ -100,13 +196,10 @@ in environment.systemPackages = [ cfg.package ]; systemd.services.buildkite-agent = - let copy = x: target: perms: - "cp -f ${x} ${target}; ${pkgs.coreutils}/bin/chmod ${toString perms} ${target}; "; - in { description = "Buildkite Agent"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - path = cfg.runtimePackages; + path = cfg.runtimePackages ++ [ pkgs.coreutils ]; environment = config.networking.proxy.envVars // { HOME = cfg.dataDir; NIX_REMOTE = "daemon"; @@ -114,10 +207,14 @@ in ## NB: maximum care is taken so that secrets (ssh keys and the CI token) ## don't end up in the Nix store. - preStart = '' - ${pkgs.coreutils}/bin/mkdir -m 0700 -p ${cfg.dataDir}/.ssh - ${copy (toString cfg.openssh.privateKeyPath) "${cfg.dataDir}/.ssh/id_rsa" 600} - ${copy (toString cfg.openssh.publicKeyPath) "${cfg.dataDir}/.ssh/id_rsa.pub" 600} + preStart = let + sshDir = "${cfg.dataDir}/.ssh"; + in + '' + mkdir -m 0700 -p "${sshDir}" + cp -f "${toString cfg.openssh.privateKeyPath}" "${sshDir}/id_rsa" + cp -f "${toString cfg.openssh.publicKeyPath}" "${sshDir}/id_rsa.pub" + chmod 600 "${sshDir}"/id_rsa* cat > "${cfg.dataDir}/buildkite-agent.cfg" <<EOF token="$(cat ${toString cfg.tokenPath})" @@ -125,7 +222,7 @@ in meta-data="${cfg.meta-data}" build-path="${cfg.dataDir}/builds" hooks-path="${cfg.hooksPath}" - bootstrap-script="${pkgs.buildkite-agent}/share/bootstrap.sh" + ${cfg.extraConfig} EOF ''; @@ -137,6 +234,15 @@ in TimeoutSec = 10; }; }; + + assertions = [ + { assertion = cfg.hooksPath == hooksDir || all isNull (attrValues cfg.hooks); + message = '' + Options `services.buildkite-agent.hooksPath' and + `services.buildkite-agent.hooks.<name>' are mutually exclusive. + ''; + } + ]; }; imports = [ (mkRenamedOptionModule [ "services" "buildkite-agent" "token" ] [ "services" "buildkite-agent" "tokenPath" ]) diff --git a/nixos/modules/services/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix index 36d5340a306f..5b7390503552 100644 --- a/nixos/modules/services/databases/mysql.nix +++ b/nixos/modules/services/databases/mysql.nix @@ -289,10 +289,10 @@ in # Create initial databases if ! test -e "${cfg.dataDir}/${database.name}"; then echo "Creating initial database: ${database.name}" - ( echo "create database ${database.name};" + ( echo "create database `${database.name}`;" ${optionalString (database ? "schema") '' - echo "use ${database.name};" + echo "use `${database.name}`;" if [ -f "${database.schema}" ] then diff --git a/nixos/modules/services/desktops/pipewire.nix b/nixos/modules/services/desktops/pipewire.nix new file mode 100644 index 000000000000..263a06156f84 --- /dev/null +++ b/nixos/modules/services/desktops/pipewire.nix @@ -0,0 +1,23 @@ +# pipewire service. +{ config, lib, pkgs, ... }: + +with lib; + +{ + ###### interface + options = { + services.pipewire = { + enable = mkEnableOption "pipewire service"; + }; + }; + + + ###### implementation + config = mkIf config.services.pipewire.enable { + environment.systemPackages = [ pkgs.pipewire ]; + + systemd.packages = [ pkgs.pipewire ]; + }; + + meta.maintainers = with lib.maintainers; [ jtojnar ]; +} diff --git a/nixos/modules/services/hardware/acpid.nix b/nixos/modules/services/hardware/acpid.nix index bb17c8859d84..f69706ebff34 100644 --- a/nixos/modules/services/hardware/acpid.nix +++ b/nixos/modules/services/hardware/acpid.nix @@ -31,7 +31,7 @@ let '' fn=$out/${name} echo "event=${handler.event}" > $fn - echo "action=${pkgs.writeScript "${name}.sh" (concatStringsSep "\n" [ "#! ${pkgs.bash}/bin/sh" handler.action ])}" >> $fn + echo "action=${pkgs.writeShellScriptBin "${name}.sh" handler.action }/bin/${name}.sh '%e'" >> $fn ''; in concatStringsSep "\n" (mapAttrsToList f (canonicalHandlers // config.services.acpid.handlers)) } @@ -69,11 +69,33 @@ in }; }); - description = "Event handlers."; - default = {}; - example = { mute = { event = "button/mute.*"; action = "amixer set Master toggle"; }; }; - + description = '' + Event handlers. + <note><para> + Handler can be a single command. + </para></note> + ''; + default = {}; + example = { + ac-power = { + event = "ac_adapter/*"; + action = '' + vals=($1) # space separated string to array of multiple values + case ''${vals[3]} in + 00000000) + echo unplugged >> /tmp/acpi.log + ;; + 00000001) + echo plugged in >> /tmp/acpi.log + ;; + *) + echo unknown >> /tmp/acpi.log + ;; + esac + ''; + }; + }; }; powerEventCommands = mkOption { diff --git a/nixos/modules/services/hardware/fwupd.nix b/nixos/modules/services/hardware/fwupd.nix index 14113fe01bb4..1f4acd21eccf 100644 --- a/nixos/modules/services/hardware/fwupd.nix +++ b/nixos/modules/services/hardware/fwupd.nix @@ -87,4 +87,8 @@ in { "d /var/lib/fwupd 0755 root root -" ]; }; + + meta = { + maintainers = pkgs.fwupd.maintainers; + }; } diff --git a/nixos/modules/services/hardware/nvidia-optimus.nix b/nixos/modules/services/hardware/nvidia-optimus.nix index 9fe4021c4247..eb1713baa140 100644 --- a/nixos/modules/services/hardware/nvidia-optimus.nix +++ b/nixos/modules/services/hardware/nvidia-optimus.nix @@ -23,7 +23,7 @@ let kernel = config.boot.kernelPackages; in ###### implementation config = lib.mkIf config.hardware.nvidiaOptimus.disable { - boot.blacklistedKernelModules = ["nouveau" "nvidia" "nvidiafb"]; + boot.blacklistedKernelModules = ["nouveau" "nvidia" "nvidiafb" "nvidia-drm"]; boot.kernelModules = [ "bbswitch" ]; boot.extraModulePackages = [ kernel.bbswitch ]; diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix index 18101a312254..b42c73b86668 100644 --- a/nixos/modules/services/mail/dovecot.nix +++ b/nixos/modules/services/mail/dovecot.nix @@ -104,7 +104,7 @@ let }; mailboxConfig = mailbox: '' - mailbox ${mailbox.name} { + mailbox "${mailbox.name}" { auto = ${toString mailbox.auto} '' + optionalString (mailbox.specialUse != null) '' special_use = \${toString mailbox.specialUse} @@ -113,7 +113,7 @@ let mailboxes = { lib, pkgs, ... }: { options = { name = mkOption { - type = types.str; + type = types.strMatching ''[^"]+''; example = "Spam"; description = "The name of the mailbox."; }; diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix index 22af7e876af2..5ab331ac067f 100644 --- a/nixos/modules/services/mail/postfix.nix +++ b/nixos/modules/services/mail/postfix.nix @@ -414,7 +414,10 @@ in postmasterAlias = mkOption { type = types.str; default = "root"; - description = "Who should receive postmaster e-mail."; + description = " + Who should receive postmaster e-mail. Multiple values can be added by + separating values with comma. + "; }; rootAlias = mkOption { @@ -422,6 +425,7 @@ in default = ""; description = " Who should receive root e-mail. Blank for no redirection. + Multiple values can be added by separating values with comma. "; }; diff --git a/nixos/modules/services/mail/rspamd.nix b/nixos/modules/services/mail/rspamd.nix index b80aa48f2c86..09fb587e74b5 100644 --- a/nixos/modules/services/mail/rspamd.nix +++ b/nixos/modules/services/mail/rspamd.nix @@ -1,14 +1,152 @@ -{ config, lib, pkgs, ... }: +{ config, options, pkgs, lib, ... }: with lib; let cfg = config.services.rspamd; + opts = options.services.rspamd; - mkBindSockets = socks: concatStringsSep "\n" (map (each: " bind_socket = \"${each}\"") socks); + bindSocketOpts = {options, config, ... }: { + options = { + socket = mkOption { + type = types.str; + example = "localhost:11333"; + description = '' + Socket for this worker to listen on in a format acceptable by rspamd. + ''; + }; + mode = mkOption { + type = types.str; + default = "0644"; + description = "Mode to set on unix socket"; + }; + owner = mkOption { + type = types.str; + default = "${cfg.user}"; + description = "Owner to set on unix socket"; + }; + group = mkOption { + type = types.str; + default = "${cfg.group}"; + description = "Group to set on unix socket"; + }; + rawEntry = mkOption { + type = types.str; + internal = true; + }; + }; + config.rawEntry = let + maybeOption = option: + optionalString options.${option}.isDefined " ${option}=${config.${option}}"; + in + if (!(hasPrefix "/" config.socket)) then "${config.socket}" + else "${config.socket}${maybeOption "mode"}${maybeOption "owner"}${maybeOption "group"}"; + }; - rspamdConfFile = pkgs.writeText "rspamd.conf" + workerOpts = { name, ... }: { + options = { + enable = mkOption { + type = types.nullOr types.bool; + default = null; + description = "Whether to run the rspamd worker."; + }; + name = mkOption { + type = types.nullOr types.str; + default = name; + description = "Name of the worker"; + }; + type = mkOption { + type = types.nullOr (types.enum [ + "normal" "controller" "fuzzy_storage" "proxy" "lua" + ]); + description = "The type of this worker"; + }; + bindSockets = mkOption { + type = types.listOf (types.either types.str (types.submodule bindSocketOpts)); + default = []; + description = '' + List of sockets to listen, in format acceptable by rspamd + ''; + example = [{ + socket = "/run/rspamd.sock"; + mode = "0666"; + owner = "rspamd"; + } "*:11333"]; + apply = value: map (each: if (isString each) + then if (isUnixSocket each) + then {socket = each; owner = cfg.user; group = cfg.group; mode = "0644"; rawEntry = "${each}";} + else {socket = each; rawEntry = "${each}";} + else each) value; + }; + count = mkOption { + type = types.nullOr types.int; + default = null; + description = '' + Number of worker instances to run + ''; + }; + includes = mkOption { + type = types.listOf types.str; + default = []; + description = '' + List of files to include in configuration + ''; + }; + extraConfig = mkOption { + type = types.lines; + default = ""; + description = "Additional entries to put verbatim into worker section of rspamd config file."; + }; + }; + config = mkIf (name == "normal" || name == "controller" || name == "fuzzy") { + type = mkDefault name; + includes = mkDefault [ "$CONFDIR/worker-${name}.inc" ]; + bindSockets = mkDefault (if name == "normal" + then [{ + socket = "/run/rspamd/rspamd.sock"; + mode = "0660"; + owner = cfg.user; + group = cfg.group; + }] + else if name == "controller" + then [ "localhost:11334" ] + else [] ); + }; + }; + + indexOf = default: start: list: e: + if list == [] + then default + else if (head list) == e then start + else (indexOf default (start + (length (listenStreams (head list).socket))) (tail list) e); + + systemdSocket = indexOf (abort "Socket not found") 0 allSockets; + + isUnixSocket = socket: hasPrefix "/" (if (isString socket) then socket else socket.socket); + isPort = hasPrefix "*:"; + isIPv4Socket = hasPrefix "*v4:"; + isIPv6Socket = hasPrefix "*v6:"; + isLocalHost = hasPrefix "localhost:"; + listenStreams = socket: + if (isLocalHost socket) then + let port = (removePrefix "localhost:" socket); + in [ "127.0.0.1:${port}" ] ++ (if config.networking.enableIPv6 then ["[::1]:${port}"] else []) + else if (isIPv6Socket socket) then [removePrefix "*v6:" socket] + else if (isPort socket) then [removePrefix "*:" socket] + else if (isIPv4Socket socket) then + throw "error: IPv4 only socket not supported in rspamd with socket activation" + else if (length (splitString " " socket)) != 1 then + throw "error: string options not supported in rspamd with socket activation" + else [socket]; + + mkBindSockets = enabled: socks: concatStringsSep "\n " (flatten (map (each: + if cfg.socketActivation && enabled != false then + let systemd = (systemdSocket each); + in (imap (idx: e: "bind_socket = \"systemd:${toString (systemd + idx - 1)}\";") (listenStreams each.socket)) + else "bind_socket = \"${each.rawEntry}\";") socks)); + + rspamdConfFile = pkgs.writeText "rspamd.conf" '' .include "$CONFDIR/common.conf" @@ -22,19 +160,33 @@ let .include "$CONFDIR/logging.inc" } - worker { - ${mkBindSockets cfg.bindSocket} - .include "$CONFDIR/worker-normal.inc" - } - - worker { - ${mkBindSockets cfg.bindUISocket} - .include "$CONFDIR/worker-controller.inc" - } + ${concatStringsSep "\n" (mapAttrsToList (name: value: '' + worker ${optionalString (value.name != "normal" && value.name != "controller") "${value.name}"} { + type = "${value.type}"; + ${optionalString (value.enable != null) + "enabled = ${if value.enable != false then "yes" else "no"};"} + ${mkBindSockets value.enable value.bindSockets} + ${optionalString (value.count != null) "count = ${toString value.count};"} + ${concatStringsSep "\n " (map (each: ".include \"${each}\"") value.includes)} + ${value.extraConfig} + } + '') cfg.workers)} ${cfg.extraConfig} ''; + allMappedSockets = flatten (mapAttrsToList (name: value: + if value.enable != false + then imap (idx: each: { + name = "${name}"; + index = idx; + value = each; + }) value.bindSockets + else []) cfg.workers); + allSockets = map (e: e.value) allMappedSockets; + + allSocketNames = map (each: "rspamd-${each.name}-${toString each.index}.socket") allMappedSockets; + in { @@ -48,36 +200,43 @@ in enable = mkEnableOption "Whether to run the rspamd daemon."; debug = mkOption { + type = types.bool; default = false; description = "Whether to run the rspamd daemon in debug mode."; }; - bindSocket = mkOption { - type = types.listOf types.str; - default = [ - "/run/rspamd/rspamd.sock mode=0660 owner=${cfg.user} group=${cfg.group}" - ]; - defaultText = ''[ - "/run/rspamd/rspamd.sock mode=0660 owner=${cfg.user} group=${cfg.group}" - ]''; + socketActivation = mkOption { + type = types.bool; description = '' - List of sockets to listen, in format acceptable by rspamd - ''; - example = '' - bindSocket = [ - "/run/rspamd.sock mode=0666 owner=rspamd" - "*:11333" - ]; + Enable systemd socket activation for rspamd. ''; }; - bindUISocket = mkOption { - type = types.listOf types.str; - default = [ - "localhost:11334" - ]; + workers = mkOption { + type = with types; attrsOf (submodule workerOpts); description = '' - List of sockets for web interface, in format acceptable by rspamd + Attribute set of workers to start. + ''; + default = { + normal = {}; + controller = {}; + }; + example = literalExample '' + { + normal = { + includes = [ "$CONFDIR/worker-normal.inc" ]; + bindSockets = [{ + socket = "/run/rspamd/rspamd.sock"; + mode = "0660"; + owner = "${cfg.user}"; + group = "${cfg.group}"; + }]; + }; + controller = { + includes = [ "$CONFDIR/worker-controller.inc" ]; + bindSockets = [ "[::1]:11334" ]; + }; + } ''; }; @@ -113,6 +272,13 @@ in config = mkIf cfg.enable { + services.rspamd.socketActivation = mkDefault (!opts.bindSocket.isDefined && !opts.bindUISocket.isDefined); + + assertions = [ { + assertion = !cfg.socketActivation || !(opts.bindSocket.isDefined || opts.bindUISocket.isDefined); + message = "Can't use socketActivation for rspamd when using renamed bind socket options"; + } ]; + # Allow users to run 'rspamc' and 'rspamadm'. environment.systemPackages = [ pkgs.rspamd ]; @@ -128,17 +294,22 @@ in gid = config.ids.gids.rspamd; }; + environment.etc."rspamd.conf".source = rspamdConfFile; + systemd.services.rspamd = { description = "Rspamd Service"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; + wantedBy = mkIf (!cfg.socketActivation) [ "multi-user.target" ]; + after = [ "network.target" ] ++ + (if cfg.socketActivation then allSocketNames else []); + requires = mkIf cfg.socketActivation allSocketNames; serviceConfig = { ExecStart = "${pkgs.rspamd}/bin/rspamd ${optionalString cfg.debug "-d"} --user=${cfg.user} --group=${cfg.group} --pid=/run/rspamd.pid -c ${rspamdConfFile} -f"; Restart = "always"; RuntimeDirectory = "rspamd"; PrivateTmp = true; + Sockets = mkIf cfg.socketActivation (concatStringsSep " " allSocketNames); }; preStart = '' @@ -146,5 +317,25 @@ in ${pkgs.coreutils}/bin/chown ${cfg.user}:${cfg.group} /var/lib/rspamd ''; }; + systemd.sockets = mkIf cfg.socketActivation + (listToAttrs (map (each: { + name = "rspamd-${each.name}-${toString each.index}"; + value = { + description = "Rspamd socket ${toString each.index} for worker ${each.name}"; + wantedBy = [ "sockets.target" ]; + listenStreams = (listenStreams each.value.socket); + socketConfig = { + BindIPv6Only = mkIf (isIPv6Socket each.value.socket) "ipv6-only"; + Service = "rspamd.service"; + SocketUser = mkIf (isUnixSocket each.value.socket) each.value.owner; + SocketGroup = mkIf (isUnixSocket each.value.socket) each.value.group; + SocketMode = mkIf (isUnixSocket each.value.socket) each.value.mode; + }; + }; + }) allMappedSockets)); }; + imports = [ + (mkRenamedOptionModule [ "services" "rspamd" "bindSocket" ] [ "services" "rspamd" "workers" "normal" "bindSockets" ]) + (mkRenamedOptionModule [ "services" "rspamd" "bindUISocket" ] [ "services" "rspamd" "workers" "controller" "bindSockets" ]) + ]; } diff --git a/nixos/modules/services/misc/home-assistant.nix b/nixos/modules/services/misc/home-assistant.nix index 666fa68b01ce..cc60a143fa6c 100644 --- a/nixos/modules/services/misc/home-assistant.nix +++ b/nixos/modules/services/misc/home-assistant.nix @@ -9,8 +9,27 @@ let availableComponents = pkgs.home-assistant.availableComponents; + # Given component "parentConfig.platform", returns whether config.parentConfig + # is a list containing a set with set.platform == "platform". + # + # For example, the component sensor.luftdaten is used as follows: + # config.sensor = [ { + # platform = "luftdaten"; + # ... + # } ]; + useComponentPlatform = component: + let + path = splitString "." component; + parentConfig = attrByPath (init path) null cfg.config; + platform = last path; + in isList parentConfig && any + (item: item.platform or null == platform) + parentConfig; + # Returns whether component is used in config - useComponent = component: hasAttrByPath (splitString "." component) cfg.config; + useComponent = component: + hasAttrByPath (splitString "." component) cfg.config + || useComponentPlatform component; # List of components used in config extraComponents = filter useComponent availableComponents; diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix index 41cadb4a6de0..5d0f2abd13a9 100644 --- a/nixos/modules/services/misc/nixos-manual.nix +++ b/nixos/modules/services/misc/nixos-manual.nix @@ -16,10 +16,10 @@ let It isn't perfect, but it seems to cover a vast majority of use cases. Caveat: even if the package is reached by a different means, the path above will be shown and not e.g. `${config.services.foo.package}`. */ - manual = import ../../../doc/manual { + manual = import ../../../doc/manual rec { inherit pkgs config; - version = config.system.nixosRelease; - revision = "release-${config.system.nixosRelease}"; + version = config.system.nixos.release; + revision = "release-${version}"; options = let scrubbedEval = evalModules { diff --git a/nixos/modules/services/misc/novacomd.nix b/nixos/modules/services/misc/novacomd.nix new file mode 100644 index 000000000000..7cfc68d2b673 --- /dev/null +++ b/nixos/modules/services/misc/novacomd.nix @@ -0,0 +1,31 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.novacomd; + +in { + + options = { + services.novacomd = { + enable = mkEnableOption "Novacom service for connecting to WebOS devices"; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.webos.novacom ]; + + systemd.services.novacomd = { + description = "Novacom WebOS daemon"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + ExecStart = "${pkgs.webos.novacomd}/sbin/novacomd"; + }; + }; + }; + + meta.maintainers = with maintainers; [ dtzWill ]; +} diff --git a/nixos/modules/services/misc/ssm-agent.nix b/nixos/modules/services/misc/ssm-agent.nix index c1e1f0903539..a57fbca86fb6 100644 --- a/nixos/modules/services/misc/ssm-agent.nix +++ b/nixos/modules/services/misc/ssm-agent.nix @@ -12,7 +12,7 @@ let case "$1" in -i) echo "nixos";; - -r) echo "${config.system.nixosVersion}";; + -r) echo "${config.system.nixos.version}";; esac ''; in { diff --git a/nixos/modules/services/misc/zookeeper.nix b/nixos/modules/services/misc/zookeeper.nix index d85b5e4ec507..91539592511c 100644 --- a/nixos/modules/services/misc/zookeeper.nix +++ b/nixos/modules/services/misc/zookeeper.nix @@ -106,10 +106,19 @@ in { ''; }; + package = mkOption { + description = "The zookeeper package to use"; + default = pkgs.zookeeper; + defaultText = "pkgs.zookeeper"; + type = types.package; + }; + }; config = mkIf cfg.enable { + environment.systemPackages = [cfg.package]; + systemd.services.zookeeper = { description = "Zookeeper Daemon"; wantedBy = [ "multi-user.target" ]; @@ -118,7 +127,7 @@ in { serviceConfig = { ExecStart = '' ${pkgs.jre}/bin/java \ - -cp "${pkgs.zookeeper}/lib/*:${pkgs.zookeeper}/${pkgs.zookeeper.name}.jar:${configDir}" \ + -cp "${cfg.package}/lib/*:${cfg.package}/${cfg.package.name}.jar:${configDir}" \ ${escapeShellArgs cfg.extraCmdLineOptions} \ -Dzookeeper.datadir.autocreate=false \ ${optionalString cfg.preferIPv4 "-Djava.net.preferIPv4Stack=true"} \ diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager.nix b/nixos/modules/services/monitoring/prometheus/alertmanager.nix index cf761edad926..8a47c9f1e7d8 100644 --- a/nixos/modules/services/monitoring/prometheus/alertmanager.nix +++ b/nixos/modules/services/monitoring/prometheus/alertmanager.nix @@ -111,11 +111,11 @@ in { after = [ "network.target" ]; script = '' ${pkgs.prometheus-alertmanager.bin}/bin/alertmanager \ - -config.file ${alertmanagerYml} \ - -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ - -log.level ${cfg.logLevel} \ - ${optionalString (cfg.webExternalUrl != null) ''-web.external-url ${cfg.webExternalUrl} \''} - ${optionalString (cfg.logFormat != null) "-log.format ${cfg.logFormat}"} + --config.file ${alertmanagerYml} \ + --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --log.level ${cfg.logLevel} \ + ${optionalString (cfg.webExternalUrl != null) ''--web.external-url ${cfg.webExternalUrl} \''} + ${optionalString (cfg.logFormat != null) "--log.format ${cfg.logFormat}"} ''; serviceConfig = { diff --git a/nixos/modules/services/network-filesystems/openafs-client/default.nix b/nixos/modules/services/network-filesystems/openafs-client/default.nix deleted file mode 100644 index 0946e379e796..000000000000 --- a/nixos/modules/services/network-filesystems/openafs-client/default.nix +++ /dev/null @@ -1,99 +0,0 @@ -{ config, pkgs, lib, ... }: - -let - inherit (lib) mkOption mkIf; - - cfg = config.services.openafsClient; - - cellServDB = pkgs.fetchurl { - url = http://dl.central.org/dl/cellservdb/CellServDB.2017-03-14; - sha256 = "1197z6c5xrijgf66rhaymnm5cvyg2yiy1i20y4ah4mrzmjx0m7sc"; - }; - - afsConfig = pkgs.runCommand "afsconfig" {} '' - mkdir -p $out - echo ${cfg.cellName} > $out/ThisCell - cp ${cellServDB} $out/CellServDB - echo "/afs:${cfg.cacheDirectory}:${cfg.cacheSize}" > $out/cacheinfo - ''; - - openafsPkgs = config.boot.kernelPackages.openafsClient; -in -{ - ###### interface - - options = { - - services.openafsClient = { - - enable = mkOption { - default = false; - description = "Whether to enable the OpenAFS client."; - }; - - cellName = mkOption { - default = "grand.central.org"; - description = "Cell name."; - }; - - cacheSize = mkOption { - default = "100000"; - description = "Cache size."; - }; - - cacheDirectory = mkOption { - default = "/var/cache/openafs"; - description = "Cache directory."; - }; - - crypt = mkOption { - default = false; - description = "Whether to enable (weak) protocol encryption."; - }; - - sparse = mkOption { - default = false; - description = "Minimal cell list in /afs."; - }; - - }; - }; - - - ###### implementation - - config = mkIf cfg.enable { - - environment.systemPackages = [ openafsPkgs ]; - - environment.etc = [ - { source = afsConfig; - target = "openafs"; - } - ]; - - systemd.services.afsd = { - description = "AFS client"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - serviceConfig = { RemainAfterExit = true; }; - - preStart = '' - mkdir -p -m 0755 /afs - mkdir -m 0700 -p ${cfg.cacheDirectory} - ${pkgs.kmod}/bin/insmod ${openafsPkgs}/lib/openafs/libafs-*.ko || true - ${openafsPkgs}/sbin/afsd -confdir ${afsConfig} -cachedir ${cfg.cacheDirectory} ${if cfg.sparse then "-dynroot-sparse" else "-dynroot"} -fakestat -afsdb - ${openafsPkgs}/bin/fs setcrypt ${if cfg.crypt then "on" else "off"} - ''; - - # Doing this in preStop, because after these commands AFS is basically - # stopped, so systemd has nothing to do, just noticing it. If done in - # postStop, then we get a hang + kernel oops, because AFS can't be - # stopped simply by sending signals to processes. - preStop = '' - ${pkgs.utillinux}/bin/umount /afs - ${openafsPkgs}/sbin/afsd -shutdown - ''; - }; - }; -} diff --git a/nixos/modules/services/network-filesystems/openafs/client.nix b/nixos/modules/services/network-filesystems/openafs/client.nix new file mode 100644 index 000000000000..3826fe3edfd0 --- /dev/null +++ b/nixos/modules/services/network-filesystems/openafs/client.nix @@ -0,0 +1,239 @@ +{ config, pkgs, lib, ... }: + +with import ./lib.nix { inherit lib; }; + +let + inherit (lib) getBin mkOption mkIf optionalString singleton types; + + cfg = config.services.openafsClient; + + cellServDB = pkgs.fetchurl { + url = http://dl.central.org/dl/cellservdb/CellServDB.2017-03-14; + sha256 = "1197z6c5xrijgf66rhaymnm5cvyg2yiy1i20y4ah4mrzmjx0m7sc"; + }; + + clientServDB = pkgs.writeText "client-cellServDB-${cfg.cellName}" (mkCellServDB cfg.cellName cfg.cellServDB); + + afsConfig = pkgs.runCommand "afsconfig" {} '' + mkdir -p $out + echo ${cfg.cellName} > $out/ThisCell + cat ${cellServDB} ${clientServDB} > $out/CellServDB + echo "${cfg.mountPoint}:${cfg.cache.directory}:${toString cfg.cache.blocks}" > $out/cacheinfo + ''; + + openafsMod = config.boot.kernelPackages.openafs; + openafsBin = lib.getBin pkgs.openafs; +in +{ + ###### interface + + options = { + + services.openafsClient = { + + enable = mkOption { + default = false; + type = types.bool; + description = "Whether to enable the OpenAFS client."; + }; + + afsdb = mkOption { + default = true; + type = types.bool; + description = "Resolve cells via AFSDB DNS records."; + }; + + cellName = mkOption { + default = ""; + type = types.str; + description = "Cell name."; + example = "grand.central.org"; + }; + + cellServDB = mkOption { + default = []; + type = with types; listOf (submodule { options = cellServDBConfig; }); + description = '' + This cell's database server records, added to the global + CellServDB. See CellServDB(5) man page for syntax. Ignored when + <literal>afsdb</literal> is set to <literal>true</literal>. + ''; + example = '' + [ { ip = "1.2.3.4"; dnsname = "first.afsdb.server.dns.fqdn.org"; } + { ip = "2.3.4.5"; dnsname = "second.afsdb.server.dns.fqdn.org"; } + ] + ''; + }; + + cache = { + blocks = mkOption { + default = 100000; + type = types.int; + description = "Cache size in 1KB blocks."; + }; + + chunksize = mkOption { + default = 0; + type = types.ints.between 0 30; + description = '' + Size of each cache chunk given in powers of + 2. <literal>0</literal> resets the chunk size to its default + values (13 (8 KB) for memcache, 18-20 (256 KB to 1 MB) for + diskcache). Maximum value is 30. Important performance + parameter. Set to higher values when dealing with large files. + ''; + }; + + directory = mkOption { + default = "/var/cache/openafs"; + type = types.str; + description = "Cache directory."; + }; + + diskless = mkOption { + default = false; + type = types.bool; + description = '' + Use in-memory cache for diskless machines. Has no real + performance benefit anymore. + ''; + }; + }; + + crypt = mkOption { + default = true; + type = types.bool; + description = "Whether to enable (weak) protocol encryption."; + }; + + daemons = mkOption { + default = 2; + type = types.int; + description = '' + Number of daemons to serve user requests. Numbers higher than 6 + usually do no increase performance. Default is sufficient for up + to five concurrent users. + ''; + }; + + fakestat = mkOption { + default = false; + type = types.bool; + description = '' + Return fake data on stat() calls. If <literal>true</literal>, + always do so. If <literal>false</literal>, only do so for + cross-cell mounts (as these are potentially expensive). + ''; + }; + + inumcalc = mkOption { + default = "compat"; + type = types.strMatching "compat|md5"; + description = '' + Inode calculation method. <literal>compat</literal> is + computationally less expensive, but <literal>md5</literal> greatly + reduces the likelihood of inode collisions in larger scenarios + involving multiple cells mounted into one AFS space. + ''; + }; + + mountPoint = mkOption { + default = "/afs"; + type = types.str; + description = '' + Mountpoint of the AFS file tree, conventionally + <literal>/afs</literal>. When set to a different value, only + cross-cells that use the same value can be accessed. + ''; + }; + + sparse = mkOption { + default = true; + type = types.bool; + description = "Minimal cell list in /afs."; + }; + + startDisconnected = mkOption { + default = false; + type = types.bool; + description = '' + Start up in disconnected mode. You need to execute + <literal>fs disco online</literal> (as root) to switch to + connected mode. Useful for roaming devices. + ''; + }; + + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + + assertions = [ + { assertion = cfg.afsdb || cfg.cellServDB != []; + message = "You should specify all cell-local database servers in config.services.openafsClient.cellServDB or set config.services.openafsClient.afsdb."; + } + { assertion = cfg.cellName != ""; + message = "You must specify the local cell name in config.services.openafsClient.cellName."; + } + ]; + + environment.systemPackages = [ pkgs.openafs ]; + + environment.etc = { + clientCellServDB = { + source = pkgs.runCommand "CellServDB" {} '' + cat ${cellServDB} ${clientServDB} > $out + ''; + target = "openafs/CellServDB"; + mode = "0644"; + }; + clientCell = { + text = '' + ${cfg.cellName} + ''; + target = "openafs/ThisCell"; + mode = "0644"; + }; + }; + + systemd.services.afsd = { + description = "AFS client"; + wantedBy = [ "multi-user.target" ]; + after = singleton (if cfg.startDisconnected then "network.target" else "network-online.target"); + serviceConfig = { RemainAfterExit = true; }; + restartIfChanged = false; + + preStart = '' + mkdir -p -m 0755 ${cfg.mountPoint} + mkdir -m 0700 -p ${cfg.cache.directory} + ${pkgs.kmod}/bin/insmod ${openafsMod}/lib/modules/*/extra/openafs/libafs.ko.xz + ${openafsBin}/sbin/afsd \ + -mountdir ${cfg.mountPoint} \ + -confdir ${afsConfig} \ + ${optionalString (!cfg.cache.diskless) "-cachedir ${cfg.cache.directory}"} \ + -blocks ${toString cfg.cache.blocks} \ + -chunksize ${toString cfg.cache.chunksize} \ + ${optionalString cfg.cache.diskless "-memcache"} \ + -inumcalc ${cfg.inumcalc} \ + ${if cfg.fakestat then "-fakestat-all" else "-fakestat"} \ + ${if cfg.sparse then "-dynroot-sparse" else "-dynroot"} \ + ${optionalString cfg.afsdb "-afsdb"} + ${openafsBin}/bin/fs setcrypt ${if cfg.crypt then "on" else "off"} + ${optionalString cfg.startDisconnected "${openafsBin}/bin/fs discon offline"} + ''; + + # Doing this in preStop, because after these commands AFS is basically + # stopped, so systemd has nothing to do, just noticing it. If done in + # postStop, then we get a hang + kernel oops, because AFS can't be + # stopped simply by sending signals to processes. + preStop = '' + ${pkgs.utillinux}/bin/umount ${cfg.mountPoint} + ${openafsBin}/sbin/afsd -shutdown + ${pkgs.kmod}/sbin/rmmod libafs + ''; + }; + }; +} diff --git a/nixos/modules/services/network-filesystems/openafs/lib.nix b/nixos/modules/services/network-filesystems/openafs/lib.nix new file mode 100644 index 000000000000..ecfc72d2eaf9 --- /dev/null +++ b/nixos/modules/services/network-filesystems/openafs/lib.nix @@ -0,0 +1,28 @@ +{ lib, ...}: + +let + inherit (lib) concatStringsSep mkOption types; + +in rec { + + mkCellServDB = cellName: db: '' + >${cellName} + '' + (concatStringsSep "\n" (map (dbm: if (dbm.ip != "" && dbm.dnsname != "") then dbm.ip + " #" + dbm.dnsname else "") + db)); + + # CellServDB configuration type + cellServDBConfig = { + ip = mkOption { + type = types.str; + default = ""; + example = "1.2.3.4"; + description = "IP Address of a database server"; + }; + dnsname = mkOption { + type = types.str; + default = ""; + example = "afs.example.org"; + description = "DNS full-qualified domain name of a database server"; + }; + }; +} diff --git a/nixos/modules/services/network-filesystems/openafs/server.nix b/nixos/modules/services/network-filesystems/openafs/server.nix new file mode 100644 index 000000000000..429eb945ac9e --- /dev/null +++ b/nixos/modules/services/network-filesystems/openafs/server.nix @@ -0,0 +1,260 @@ +{ config, pkgs, lib, ... }: + +with import ./lib.nix { inherit lib; }; + +let + inherit (lib) concatStringsSep intersperse mapAttrsToList mkForce mkIf mkMerge mkOption optionalString types; + + bosConfig = pkgs.writeText "BosConfig" ('' + restrictmode 1 + restarttime 16 0 0 0 0 + checkbintime 3 0 5 0 0 + '' + (optionalString cfg.roles.database.enable '' + bnode simple vlserver 1 + parm ${openafsBin}/libexec/openafs/vlserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.vlserverArgs} + end + bnode simple ptserver 1 + parm ${openafsBin}/libexec/openafs/ptserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} ${cfg.roles.database.ptserverArgs} + end + '') + (optionalString cfg.roles.fileserver.enable '' + bnode dafs dafs 1 + parm ${openafsBin}/libexec/openafs/dafileserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.fileserverArgs} + parm ${openafsBin}/libexec/openafs/davolserver ${optionalString cfg.dottedPrincipals "-allow-dotted-principals"} -udpsize ${udpSizeStr} ${cfg.roles.fileserver.volserverArgs} + parm ${openafsBin}/libexec/openafs/salvageserver ${cfg.roles.fileserver.salvageserverArgs} + parm ${openafsBin}/libexec/openafs/dasalvager ${cfg.roles.fileserver.salvagerArgs} + end + '') + (optionalString (cfg.roles.database.enable && cfg.roles.backup.enable) '' + bnode simple buserver 1 + parm ${openafsBin}/libexec/openafs/buserver ${cfg.roles.backup.buserverArgs} ${optionalString (cfg.roles.backup.cellServDB != []) "-cellservdb /etc/openafs/backup/"} + end + '')); + + netInfo = if (cfg.advertisedAddresses != []) then + pkgs.writeText "NetInfo" ((concatStringsSep "\nf " cfg.advertisedAddresses) + "\n") + else null; + + buCellServDB = pkgs.writeText "backup-cellServDB-${cfg.cellName}" (mkCellServDB cfg.cellName cfg.roles.backup.cellServDB); + + cfg = config.services.openafsServer; + + udpSizeStr = toString cfg.udpPacketSize; + + openafsBin = lib.getBin pkgs.openafs; + +in { + + options = { + + services.openafsServer = { + + enable = mkOption { + default = false; + type = types.bool; + description = '' + Whether to enable the OpenAFS server. An OpenAFS server needs a + complex setup. So, be aware that enabling this service and setting + some options does not give you a turn-key-ready solution. You need + at least a running Kerberos 5 setup, as OpenAFS relies on it for + authentication. See the Guide "QuickStartUnix" coming with + <literal>pkgs.openafs.doc</literal> for complete setup + instructions. + ''; + }; + + advertisedAddresses = mkOption { + default = []; + description = "List of IP addresses this server is advertised under. See NetInfo(5)"; + }; + + cellName = mkOption { + default = ""; + type = types.str; + description = "Cell name, this server will serve."; + example = "grand.central.org"; + }; + + cellServDB = mkOption { + default = []; + type = with types; listOf (submodule [ { options = cellServDBConfig;} ]); + description = "Definition of all cell-local database server machines."; + }; + + roles = { + fileserver = { + enable = mkOption { + default = true; + type = types.bool; + description = "Fileserver role, serves files and volumes from its local storage."; + }; + + fileserverArgs = mkOption { + default = "-vattachpar 128 -vhashsize 11 -L -rxpck 400 -cb 1000000"; + type = types.str; + description = "Arguments to the dafileserver process. See its man page."; + }; + + volserverArgs = mkOption { + default = ""; + type = types.str; + description = "Arguments to the davolserver process. See its man page."; + example = "-sync never"; + }; + + salvageserverArgs = mkOption { + default = ""; + type = types.str; + description = "Arguments to the salvageserver process. See its man page."; + example = "-showlog"; + }; + + salvagerArgs = mkOption { + default = ""; + type = types.str; + description = "Arguments to the dasalvager process. See its man page."; + example = "-showlog -showmounts"; + }; + }; + + database = { + enable = mkOption { + default = true; + type = types.bool; + description = '' + Database server role, maintains the Volume Location Database, + Protection Database (and Backup Database, see + <literal>backup</literal> role). There can be multiple + servers in the database role for replication, which then need + reliable network connection to each other. + + Servers in this role appear in AFSDB DNS records or the + CellServDB. + ''; + }; + + vlserverArgs = mkOption { + default = ""; + type = types.str; + description = "Arguments to the vlserver process. See its man page."; + example = "-rxbind"; + }; + + ptserverArgs = mkOption { + default = ""; + type = types.str; + description = "Arguments to the ptserver process. See its man page."; + example = "-restricted -default_access S---- S-M---"; + }; + }; + + backup = { + enable = mkOption { + default = false; + type = types.bool; + description = '' + Backup server role. Use in conjunction with the + <literal>database</literal> role to maintain the Backup + Database. Normally only used in conjunction with tape storage + or IBM's Tivoli Storage Manager. + ''; + }; + + buserverArgs = mkOption { + default = ""; + type = types.str; + description = "Arguments to the buserver process. See its man page."; + example = "-p 8"; + }; + + cellServDB = mkOption { + default = []; + type = with types; listOf (submodule [ { options = cellServDBConfig;} ]); + description = '' + Definition of all cell-local backup database server machines. + Use this when your cell uses less backup database servers than + other database server machines. + ''; + }; + }; + }; + + dottedPrincipals= mkOption { + default = false; + type = types.bool; + description = '' + If enabled, allow principal names containing (.) dots. Enabling + this has security implications! + ''; + }; + + udpPacketSize = mkOption { + default = 1310720; + type = types.int; + description = '' + UDP packet size to use in Bytes. Higher values can speed up + communications. The default of 1 MB is a sufficient in most + cases. Make sure to increase the kernel's UDP buffer size + accordingly via <literal>net.core(w|r|opt)mem_max</literal> + sysctl. + ''; + }; + + }; + + }; + + config = mkIf cfg.enable { + + assertions = [ + { assertion = cfg.cellServDB != []; + message = "You must specify all cell-local database servers in config.services.openafsServer.cellServDB."; + } + { assertion = cfg.cellName != ""; + message = "You must specify the local cell name in config.services.openafsServer.cellName."; + } + ]; + + environment.systemPackages = [ pkgs.openafs ]; + + environment.etc = { + bosConfig = { + source = bosConfig; + target = "openafs/BosConfig"; + mode = "0644"; + }; + cellServDB = { + text = mkCellServDB cfg.cellName cfg.cellServDB; + target = "openafs/server/CellServDB"; + mode = "0644"; + }; + thisCell = { + text = cfg.cellName; + target = "openafs/server/ThisCell"; + mode = "0644"; + }; + buCellServDB = { + enable = (cfg.roles.backup.cellServDB != []); + text = mkCellServDB cfg.cellName cfg.roles.backup.cellServDB; + target = "openafs/backup/CellServDB"; + }; + }; + + systemd.services = { + openafs-server = { + description = "OpenAFS server"; + after = [ "syslog.target" "network.target" ]; + wantedBy = [ "multi-user.target" ]; + restartIfChanged = false; + unitConfig.ConditionPathExists = [ "/etc/openafs/server/rxkad.keytab" ]; + preStart = '' + mkdir -m 0755 -p /var/openafs + ${optionalString (netInfo != null) "cp ${netInfo} /var/openafs/netInfo"} + ${optionalString (cfg.roles.backup.cellServDB != []) "cp ${buCellServDB}"} + ''; + serviceConfig = { + ExecStart = "${openafsBin}/bin/bosserver -nofork"; + ExecStop = "${openafsBin}/bin/bos shutdown localhost -wait -localauth"; + }; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/bird.nix b/nixos/modules/services/networking/bird.nix index 1a7a1e24b702..c25bd0fdc541 100644 --- a/nixos/modules/services/networking/bird.nix +++ b/nixos/modules/services/networking/bird.nix @@ -7,21 +7,27 @@ let let cfg = config.services.${variant}; pkg = pkgs.${variant}; + birdBin = if variant == "bird6" then "bird6" else "bird"; birdc = if variant == "bird6" then "birdc6" else "birdc"; + descr = + { bird = "1.9.x with IPv4 suport"; + bird6 = "1.9.x with IPv6 suport"; + bird2 = "2.x"; + }.${variant}; configFile = pkgs.stdenv.mkDerivation { name = "${variant}.conf"; text = cfg.config; preferLocalBuild = true; buildCommand = '' echo -n "$text" > $out - ${pkg}/bin/${variant} -d -p -c $out + ${pkg}/bin/${birdBin} -d -p -c $out ''; }; in { ###### interface options = { services.${variant} = { - enable = mkEnableOption "BIRD Internet Routing Daemon"; + enable = mkEnableOption "BIRD Internet Routing Daemon (${descr})"; config = mkOption { type = types.lines; description = '' @@ -36,12 +42,12 @@ let config = mkIf cfg.enable { environment.systemPackages = [ pkg ]; systemd.services.${variant} = { - description = "BIRD Internet Routing Daemon"; + description = "BIRD Internet Routing Daemon (${descr})"; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "forking"; Restart = "on-failure"; - ExecStart = "${pkg}/bin/${variant} -c ${configFile} -u ${variant} -g ${variant}"; + ExecStart = "${pkg}/bin/${birdBin} -c ${configFile} -u ${variant} -g ${variant}"; ExecReload = "${pkg}/bin/${birdc} configure"; ExecStop = "${pkg}/bin/${birdc} down"; CapabilityBoundingSet = [ "CAP_CHOWN" "CAP_FOWNER" "CAP_DAC_OVERRIDE" "CAP_SETUID" "CAP_SETGID" @@ -56,14 +62,15 @@ let users = { extraUsers.${variant} = { description = "BIRD Internet Routing Daemon user"; - group = "${variant}"; + group = variant; }; extraGroups.${variant} = {}; }; }; }; - inherit (config.services) bird bird6; -in { - imports = [(generic "bird") (generic "bird6")]; +in + +{ + imports = map generic [ "bird" "bird6" "bird2" ]; } diff --git a/nixos/modules/services/networking/connman.nix b/nixos/modules/services/networking/connman.nix index 546d27069232..c3ca6fbe725e 100644 --- a/nixos/modules/services/networking/connman.nix +++ b/nixos/modules/services/networking/connman.nix @@ -52,6 +52,15 @@ in { ''; }; + extraFlags = mkOption { + type = with types; listOf string; + default = [ ]; + example = [ "--nodnsproxy" ]; + description = '' + Extra flags to pass to connmand + ''; + }; + }; }; @@ -81,7 +90,7 @@ in { Type = "dbus"; BusName = "net.connman"; Restart = "on-failure"; - ExecStart = "${pkgs.connman}/sbin/connmand --config=${configFile} --nodaemon"; + ExecStart = "${pkgs.connman}/sbin/connmand --config=${configFile} --nodaemon ${toString cfg.extraFlags}"; StandardOutput = "null"; }; }; diff --git a/nixos/modules/services/networking/dante.nix b/nixos/modules/services/networking/dante.nix index a9a77f3412af..32acce51e692 100644 --- a/nixos/modules/services/networking/dante.nix +++ b/nixos/modules/services/networking/dante.nix @@ -47,7 +47,7 @@ in systemd.services.dante = { description = "Dante SOCKS v4 and v5 compatible proxy server"; - after = [ "network.target" ]; + after = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix index d283c7624335..de0aa1a2c2c3 100644 --- a/nixos/modules/services/networking/dhcpcd.nix +++ b/nixos/modules/services/networking/dhcpcd.nix @@ -16,7 +16,7 @@ let # Don't start dhcpcd on explicitly configured interfaces or on # interfaces that are part of a bridge, bond or sit device. ignoredInterfaces = - map (i: i.name) (filter (i: if i.useDHCP != null then !i.useDHCP else i.ip4 != [ ] || i.ipAddress != null) interfaces) + map (i: i.name) (filter (i: if i.useDHCP != null then !i.useDHCP else i.ipv4.addresses != [ ]) interfaces) ++ mapAttrsToList (i: _: i) config.networking.sits ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges)) ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.vswitches)) @@ -156,11 +156,11 @@ in systemd.services.dhcpcd = let cfgN = config.networking; hasDefaultGatewaySet = (cfgN.defaultGateway != null && cfgN.defaultGateway.address != "") - || (cfgN.defaultGateway6 != null && cfgN.defaultGateway6.address != ""); + && (!cfgN.enableIPv6 || (cfgN.defaultGateway6 != null && cfgN.defaultGateway6.address != "")); in { description = "DHCP Client"; - wantedBy = optional (!hasDefaultGatewaySet) "network-online.target"; + wantedBy = [ "multi-user.target" ] ++ optional (!hasDefaultGatewaySet) "network-online.target"; after = [ "network.target" ]; wants = [ "network.target" ]; diff --git a/nixos/modules/services/networking/firefox/sync-server.nix b/nixos/modules/services/networking/firefox/sync-server.nix index a9f3fd65d76b..97d223a56cab 100644 --- a/nixos/modules/services/networking/firefox/sync-server.nix +++ b/nixos/modules/services/networking/firefox/sync-server.nix @@ -33,6 +33,8 @@ let in { + meta.maintainers = with lib.maintainers; [ nadrieril ]; + options = { services.firefox.syncserver = { enable = mkOption { @@ -70,18 +72,6 @@ in ''; }; - user = mkOption { - type = types.str; - default = "syncserver"; - description = "User account under which syncserver runs."; - }; - - group = mkOption { - type = types.str; - default = "syncserver"; - description = "Group account under which syncserver runs."; - }; - publicUrl = mkOption { type = types.str; default = "http://localhost:5000/"; @@ -137,7 +127,9 @@ in config = mkIf cfg.enable { systemd.services.syncserver = let - syncServerEnv = pkgs.python.withPackages(ps: with ps; [ syncserver pasteScript ]); + syncServerEnv = pkgs.python.withPackages(ps: with ps; [ syncserver pasteScript requests ]); + user = "syncserver"; + group = "syncserver"; in { after = [ "network.target" ]; description = "Firefox Sync Server"; @@ -145,43 +137,43 @@ in path = [ pkgs.coreutils syncServerEnv ]; serviceConfig = { - User = cfg.user; - Group = cfg.group; + User = user; + Group = group; PermissionsStartOnly = true; }; preStart = '' if ! test -e ${cfg.privateConfig}; then - mkdir -m 700 -p $(dirname ${cfg.privateConfig}) + mkdir -p $(dirname ${cfg.privateConfig}) echo > ${cfg.privateConfig} '[syncserver]' + chmod 600 ${cfg.privateConfig} echo >> ${cfg.privateConfig} "secret = $(head -c 20 /dev/urandom | sha1sum | tr -d ' -')" fi - chown ${cfg.user}:${cfg.group} ${cfg.privateConfig} + chmod 600 ${cfg.privateConfig} + chmod 755 $(dirname ${cfg.privateConfig}) + chown ${user}:${group} ${cfg.privateConfig} + '' + optionalString (cfg.sqlUri == defaultSqlUri) '' if ! test -e $(dirname ${defaultDbLocation}); then mkdir -m 700 -p $(dirname ${defaultDbLocation}) - chown ${cfg.user}:${cfg.group} $(dirname ${defaultDbLocation}) + chown ${user}:${group} $(dirname ${defaultDbLocation}) fi + # Move previous database file if it exists oldDb="/var/db/firefox-sync-server.db" if test -f $oldDb; then mv $oldDb ${defaultDbLocation} - chown ${cfg.user}:${cfg.group} ${defaultDbLocation} + chown ${user}:${group} ${defaultDbLocation} fi ''; serviceConfig.ExecStart = "${syncServerEnv}/bin/paster serve ${syncServerIni}"; }; - users.extraUsers = optionalAttrs (cfg.user == "syncserver") - (singleton { - name = "syncserver"; - group = cfg.group; - isSystemUser = true; - }); - - users.extraGroups = optionalAttrs (cfg.group == "syncserver") - (singleton { - name = "syncserver"; - }); + users.users.syncserver = { + group = "syncserver"; + isSystemUser = true; + }; + + users.groups.syncserver = {}; }; } diff --git a/nixos/modules/services/networking/freeradius.nix b/nixos/modules/services/networking/freeradius.nix new file mode 100644 index 000000000000..45cba1ce2770 --- /dev/null +++ b/nixos/modules/services/networking/freeradius.nix @@ -0,0 +1,72 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.freeradius; + + freeradiusService = cfg: + { + description = "FreeRadius server"; + wantedBy = ["multi-user.target"]; + after = ["network-online.target"]; + wants = ["network-online.target"]; + preStart = '' + ${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout + ''; + + serviceConfig = { + ExecStart = "${pkgs.freeradius}/bin/radiusd -f -d ${cfg.configDir} -l stdout -xx"; + ExecReload = [ + "${pkgs.freeradius}/bin/radiusd -C -d ${cfg.configDir} -l stdout" + "${pkgs.coreutils}/bin/kill -HUP $MAINPID" + ]; + User = "radius"; + ProtectSystem = "full"; + ProtectHome = "on"; + Restart = "on-failure"; + RestartSec = 2; + }; + }; + + freeradiusConfig = { + enable = mkEnableOption "the freeradius server"; + + configDir = mkOption { + type = types.path; + default = "/etc/raddb"; + description = '' + The path of the freeradius server configuration directory. + ''; + }; + + }; + +in + +{ + + ###### interface + + options = { + services.freeradius = freeradiusConfig; + }; + + + ###### implementation + + config = mkIf (cfg.enable) { + + users = { + extraUsers.radius = { + /*uid = config.ids.uids.radius;*/ + description = "Radius daemon user"; + }; + }; + + systemd.services.freeradius = freeradiusService cfg; + + }; + +} diff --git a/nixos/modules/services/networking/gnunet.nix b/nixos/modules/services/networking/gnunet.nix index 03ee54af4334..02cd53c6fa38 100644 --- a/nixos/modules/services/networking/gnunet.nix +++ b/nixos/modules/services/networking/gnunet.nix @@ -137,6 +137,8 @@ in after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; path = [ pkgs.gnunet pkgs.miniupnpc ]; + environment.TMPDIR = "/tmp"; + serviceConfig.PrivateTemp = true; serviceConfig.ExecStart = "${pkgs.gnunet}/lib/gnunet/libexec/gnunet-service-arm -c ${configFile}"; serviceConfig.User = "gnunet"; serviceConfig.UMask = "0007"; diff --git a/nixos/modules/services/networking/kresd.nix b/nixos/modules/services/networking/kresd.nix index d0c19c4ecb71..aac02b811d71 100644 --- a/nixos/modules/services/networking/kresd.nix +++ b/nixos/modules/services/networking/kresd.nix @@ -46,6 +46,15 @@ in What addresses the server should listen on. (UDP+TCP 53) ''; }; + listenTLS = mkOption { + type = with types; listOf str; + default = []; + example = [ "198.51.100.1:853" "[2001:db8::1]:853" "853" ]; + description = '' + Addresses on which kresd should provide DNS over TLS (see RFC 7858). + For detailed syntax see ListenStream in man systemd.socket. + ''; + }; # TODO: perhaps options for more common stuff like cache size or forwarding }; @@ -75,6 +84,18 @@ in socketConfig.FreeBind = true; }; + systemd.sockets.kresd-tls = mkIf (cfg.listenTLS != []) rec { + wantedBy = [ "sockets.target" ]; + before = wantedBy; + partOf = [ "kresd.socket" ]; + listenStreams = cfg.listenTLS; + socketConfig = { + FileDescriptorName = "tls"; + FreeBind = true; + Service = "kresd.service"; + }; + }; + systemd.sockets.kresd-control = rec { wantedBy = [ "sockets.target" ]; before = wantedBy; @@ -97,6 +118,8 @@ in Type = "notify"; WorkingDirectory = cfg.cacheDir; Restart = "on-failure"; + Sockets = [ "kresd.socket" "kresd-control.socket" ] + ++ optional (cfg.listenTLS != []) "kresd-tls.socket"; }; # Trust anchor goes from dns-root-data by default. diff --git a/nixos/modules/services/networking/monero.nix b/nixos/modules/services/networking/monero.nix new file mode 100644 index 000000000000..31379189f5de --- /dev/null +++ b/nixos/modules/services/networking/monero.nix @@ -0,0 +1,238 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.monero; + dataDir = "/var/lib/monero"; + + listToConf = option: list: + concatMapStrings (value: "${option}=${value}\n") list; + + login = (cfg.rpc.user != null && cfg.rpc.password != null); + + configFile = with cfg; pkgs.writeText "monero.conf" '' + log-file=/dev/stdout + data-dir=${dataDir} + + ${optionalString mining.enable '' + start-mining=${mining.address} + mining-threads=${toString mining.threads} + ''} + + rpc-bind-ip=${rpc.address} + rpc-bind-port=${toString rpc.port} + ${optionalString login '' + rpc-login=${rpc.user}:${rpc.password} + ''} + ${optionalString rpc.restricted '' + restrict-rpc=1 + ''} + + limit-rate-up=${toString limits.upload} + limit-rate-down=${toString limits.download} + max-concurrency=${toString limits.threads} + block-sync-size=${toString limits.syncSize} + + ${listToConf "add-peer" extraNodes} + ${listToConf "add-priority-node" priorityNodes} + ${listToConf "add-exclusive-node" exclusiveNodes} + + ${extraConfig} + ''; + +in + +{ + + ###### interface + + options = { + + services.monero = { + + enable = mkEnableOption "Monero node daemon."; + + mining.enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to mine moneroj. + ''; + }; + + mining.address = mkOption { + type = types.str; + default = ""; + description = '' + Monero address where to send mining rewards. + ''; + }; + + mining.threads = mkOption { + type = types.addCheck types.int (x: x>=0); + default = 0; + description = '' + Number of threads used for mining. + Set to <literal>0</literal> to use all available. + ''; + }; + + rpc.user = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + User name for RPC connections. + ''; + }; + + rpc.password = mkOption { + type = types.str; + default = null; + description = '' + Password for RPC connections. + ''; + }; + + rpc.address = mkOption { + type = types.str; + default = "127.0.0.1"; + description = '' + IP address the RPC server will bind to. + ''; + }; + + rpc.port = mkOption { + type = types.int; + default = 18081; + description = '' + Port the RPC server will bind to. + ''; + }; + + rpc.restricted = mkOption { + type = types.bool; + default = false; + description = '' + Whether to restrict RPC to view only commands. + ''; + }; + + limits.upload = mkOption { + type = types.addCheck types.int (x: x>=-1); + default = -1; + description = '' + Limit of the upload rate in kB/s. + Set to <literal>-1</literal> to leave unlimited. + ''; + }; + + limits.download = mkOption { + type = types.addCheck types.int (x: x>=-1); + default = -1; + description = '' + Limit of the download rate in kB/s. + Set to <literal>-1</literal> to leave unlimited. + ''; + }; + + limits.threads = mkOption { + type = types.addCheck types.int (x: x>=0); + default = 0; + description = '' + Maximum number of threads used for a parallel job. + Set to <literal>0</literal> to leave unlimited. + ''; + }; + + limits.syncSize = mkOption { + type = types.addCheck types.int (x: x>=0); + default = 0; + description = '' + Maximum number of blocks to sync at once. + Set to <literal>0</literal> for adaptive. + ''; + }; + + extraNodes = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + List of additional peer IP addresses to add to the local list. + ''; + }; + + priorityNodes = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + List of peer IP addresses to connect to and + attempt to keep the connection open. + ''; + }; + + exclusiveNodes = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + List of peer IP addresses to connect to *only*. + If given the other peer options will be ignored. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra lines to be added verbatim to monerod configuration. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + users.extraUsers = singleton { + name = "monero"; + uid = config.ids.uids.monero; + description = "Monero daemon user"; + home = dataDir; + createHome = true; + }; + + users.extraGroups = singleton { + name = "monero"; + gid = config.ids.gids.monero; + }; + + systemd.services.monero = { + description = "monero daemon"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + User = "monero"; + Group = "monero"; + ExecStart = "${pkgs.monero}/bin/monerod --config-file=${configFile} --non-interactive"; + Restart = "always"; + SuccessExitStatus = [ 0 1 ]; + }; + }; + + assertions = singleton { + assertion = cfg.mining.enable -> cfg.mining.address != ""; + message = '' + You need a Monero address to receive mining rewards: + specify one using option monero.mining.address. + ''; + }; + + }; + +} + diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix index 273ca797b98d..d8135f4d0ffa 100644 --- a/nixos/modules/services/networking/mosquitto.nix +++ b/nixos/modules/services/networking/mosquitto.nix @@ -212,7 +212,7 @@ in '' + concatStringsSep "\n" ( mapAttrsToList (n: c: if c.hashedPassword != null then - "echo '${n}:${c.hashedPassword}' > ${cfg.dataDir}/passwd" + "echo '${n}:${c.hashedPassword}' >> ${cfg.dataDir}/passwd" else optionalString (c.password != null) "${pkgs.mosquitto}/bin/mosquitto_passwd -b ${cfg.dataDir}/passwd ${n} ${c.password}" ) cfg.users); diff --git a/nixos/modules/services/networking/nat.nix b/nixos/modules/services/networking/nat.nix index df4246d216d8..da3827c35e63 100644 --- a/nixos/modules/services/networking/nat.nix +++ b/nixos/modules/services/networking/nat.nix @@ -53,12 +53,36 @@ let -i ${cfg.externalInterface} -p ${fwd.proto} \ --dport ${builtins.toString fwd.sourcePort} \ -j DNAT --to-destination ${fwd.destination} + + ${concatMapStrings (loopbackip: + let + m = builtins.match "([0-9.]+):([0-9-]+)" fwd.destination; + destinationIP = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else elemAt m 0; + destinationPorts = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else elemAt m 1; + in '' + # Allow connections to ${loopbackip}:${toString fwd.sourcePort} from the host itself + iptables -w -t nat -A OUTPUT \ + -d ${loopbackip} -p ${fwd.proto} \ + --dport ${builtins.toString fwd.sourcePort} \ + -j DNAT --to-destination ${fwd.destination} + + # Allow connections to ${loopbackip}:${toString fwd.sourcePort} from other hosts behind NAT + iptables -w -t nat -A nixos-nat-pre \ + -d ${loopbackip} -p ${fwd.proto} \ + --dport ${builtins.toString fwd.sourcePort} \ + -j DNAT --to-destination ${fwd.destination} + + iptables -w -t nat -A nixos-nat-post \ + -d ${destinationIP} -p ${fwd.proto} \ + --dport ${destinationPorts} \ + -j SNAT --to-source ${loopbackip} + '') fwd.loopbackIPs} '') cfg.forwardPorts} ${optionalString (cfg.dmzHost != null) '' iptables -w -t nat -A nixos-nat-pre \ -i ${cfg.externalInterface} -j DNAT \ - --to-destination ${cfg.dmzHost} + --to-destination ${cfg.dmzHost} ''} ${cfg.extraCommands} @@ -152,6 +176,13 @@ in example = "udp"; description = "Protocol of forwarded connection"; }; + + loopbackIPs = mkOption { + type = types.listOf types.str; + default = []; + example = literalExample ''[ "55.1.2.3" ]''; + description = "Public IPs for NAT reflection; for connections to `loopbackip:sourcePort' from the host itself and from other hosts behind NAT"; + }; }; }); default = []; diff --git a/nixos/modules/services/networking/nixops-dns.nix b/nixos/modules/services/networking/nixops-dns.nix new file mode 100644 index 000000000000..2bb1263b7fa2 --- /dev/null +++ b/nixos/modules/services/networking/nixops-dns.nix @@ -0,0 +1,79 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + pkg = pkgs.nixops-dns; + cfg = config.services.nixops-dns; +in + +{ + options = { + services.nixops-dns = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable the nixops-dns resolution + of NixOps virtual machines via dnsmasq and fake domain name. + ''; + }; + + user = mkOption { + type = types.str; + description = '' + The user the nixops-dns daemon should run as. + This should be the user, which is also used for nixops and + have the .nixops directory in its home. + ''; + }; + + domain = mkOption { + type = types.str; + description = '' + Fake domain name to resolve to NixOps virtual machines. + + For example "ops" will resolve "vm.ops". + ''; + example = "ops"; + default = "ops"; + }; + + dnsmasq = mkOption { + type = types.bool; + default = true; + description = '' + Enable dnsmasq forwarding to nixops-dns. This allows to use + nixops-dns for `services.nixops-dns.domain` resolution + while forwarding the rest of the queries to original resolvers. + ''; + }; + + }; + }; + + config = mkIf cfg.enable { + systemd.services.nixops-dns = { + description = "nixops-dns: DNS server for resolving NixOps machines"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + ExecStart="${pkg}/bin/nixops-dns --domain=.${cfg.domain}"; + }; + }; + + services.dnsmasq = mkIf cfg.dnsmasq { + enable = true; + resolveLocalQueries = true; + servers = [ + "/${cfg.domain}/127.0.0.1#5300" + ]; + extraConfig = '' + bind-interfaces + listen-address=127.0.0.1 + ''; + }; + + }; +} diff --git a/nixos/modules/services/networking/prosody.nix b/nixos/modules/services/networking/prosody.nix index f34d8e172b46..9d7e6d6018af 100644 --- a/nixos/modules/services/networking/prosody.nix +++ b/nixos/modules/services/networking/prosody.nix @@ -179,6 +179,19 @@ in description = "Whether to enable the prosody server"; }; + package = mkOption { + type = types.package; + description = "Prosody package to use"; + default = pkgs.prosody; + defaultText = "pkgs.prosody"; + example = literalExample '' + pkgs.prosody.override { + withExtraLibs = [ pkgs.luaPackages.lpty ]; + withCommunityModules = [ "auth_external" ]; + }; + ''; + }; + allowRegistration = mkOption { type = types.bool; default = false; @@ -306,7 +319,7 @@ in User = "prosody"; Type = "forking"; PIDFile = "/var/lib/prosody/prosody.pid"; - ExecStart = "${pkgs.prosody}/bin/prosodyctl start"; + ExecStart = "${cfg.package}/bin/prosodyctl start"; }; }; diff --git a/nixos/modules/services/networking/radvd.nix b/nixos/modules/services/networking/radvd.nix index 0199502163a3..85d7f9e4a41b 100644 --- a/nixos/modules/services/networking/radvd.nix +++ b/nixos/modules/services/networking/radvd.nix @@ -59,24 +59,11 @@ in systemd.services.radvd = { description = "IPv6 Router Advertisement Daemon"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - - path = [ pkgs.radvd ]; - - preStart = '' - mkdir -m 755 -p /run/radvd - chown radvd /run/radvd - ''; - serviceConfig = - { ExecStart = "@${pkgs.radvd}/sbin/radvd radvd" - + " -p /run/radvd/radvd.pid -m syslog -u radvd -C ${confFile}"; + { ExecStart = "@${pkgs.radvd}/bin/radvd radvd -n -u radvd -C ${confFile}"; Restart = "always"; - Type = "forking"; - PIDFile = "/run/radvd/radvd.pid"; }; }; diff --git a/nixos/modules/services/networking/rxe.nix b/nixos/modules/services/networking/rxe.nix new file mode 100644 index 000000000000..a6a069ec50c0 --- /dev/null +++ b/nixos/modules/services/networking/rxe.nix @@ -0,0 +1,63 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.networking.rxe; + + runRxeCmd = cmd: ifcs: + concatStrings ( map (x: "${pkgs.rdma-core}/bin/rxe_cfg -n ${cmd} ${x};") ifcs); + + startScript = pkgs.writeShellScriptBin "rxe-start" '' + ${pkgs.rdma-core}/bin/rxe_cfg -n start + ${runRxeCmd "add" cfg.interfaces} + ${pkgs.rdma-core}/bin/rxe_cfg + ''; + + stopScript = pkgs.writeShellScriptBin "rxe-stop" '' + ${runRxeCmd "remove" cfg.interfaces } + ${pkgs.rdma-core}/bin/rxe_cfg -n stop + ''; + +in { + ###### interface + + options = { + networking.rxe = { + enable = mkEnableOption "RDMA over converged ethernet"; + interfaces = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "eth0" ]; + description = '' + Enable RDMA on the listed interfaces. The corresponding virtual + RDMA interfaces will be named rxe0 ... rxeN where the ordering + will be as they are named in the list. UDP port 4791 must be + open on the respective ethernet interfaces. + ''; + }; + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + + systemd.services.rxe = { + path = with pkgs; [ kmod rdma-core ]; + description = "RoCE interfaces"; + + wantedBy = [ "multi-user.target" ]; + after = [ "systemd-modules-load.service" "network-online.target" ]; + wants = [ "network-pre.target" ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${startScript}/bin/rxe-start"; + ExecStop = "${stopScript}/bin/rxe-stop"; + }; + }; + }; +} + diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index d9b12d278160..e50c4dbacf36 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -375,9 +375,6 @@ in # LogLevel VERBOSE logs user's key fingerprint on login. # Needed to have a clear audit track of which key was used to log in. LogLevel VERBOSE - - # Use kernel sandbox mechanisms where possible in unprivileged processes. - UsePrivilegeSeparation sandbox ''; assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true; diff --git a/nixos/modules/services/security/hologram-agent.nix b/nixos/modules/services/security/hologram-agent.nix index 6c53a2df6306..39ed506f7617 100644 --- a/nixos/modules/services/security/hologram-agent.nix +++ b/nixos/modules/services/security/hologram-agent.nix @@ -35,10 +35,9 @@ in { config = mkIf cfg.enable { boot.kernelModules = [ "dummy" ]; - networking.interfaces.dummy0 = { - ipAddress = "169.254.169.254"; - prefixLength = 32; - }; + networking.interfaces.dummy0.ipv4.addresses = [ + { address = "169.254.169.254"; prefixLength = 32; } + ]; systemd.services.hologram-agent = { description = "Provide EC2 instance credentials to machines outside of EC2"; diff --git a/nixos/modules/services/security/physlock.nix b/nixos/modules/services/security/physlock.nix index 30224d7fc6ba..97fbd6aae6e0 100644 --- a/nixos/modules/services/security/physlock.nix +++ b/nixos/modules/services/security/physlock.nix @@ -30,6 +30,20 @@ in ''; }; + allowAnyUser = mkOption { + type = types.bool; + default = false; + description = '' + Whether to allow any user to lock the screen. This will install a + setuid wrapper to allow any user to start physlock as root, which + is a minor security risk. Call the physlock binary to use this instead + of using the systemd service. + + Note that you might need to relog to have the correct binary in your + PATH upon changing this option. + ''; + }; + disableSysRq = mkOption { type = types.bool; default = true; @@ -79,28 +93,36 @@ in ###### implementation - config = mkIf cfg.enable { - - # for physlock -l and physlock -L - environment.systemPackages = [ pkgs.physlock ]; - - systemd.services."physlock" = { - enable = true; - description = "Physlock"; - wantedBy = optional cfg.lockOn.suspend "suspend.target" - ++ optional cfg.lockOn.hibernate "hibernate.target" - ++ cfg.lockOn.extraTargets; - before = optional cfg.lockOn.suspend "systemd-suspend.service" - ++ optional cfg.lockOn.hibernate "systemd-hibernate.service" - ++ cfg.lockOn.extraTargets; - serviceConfig.Type = "forking"; - script = '' - ${pkgs.physlock}/bin/physlock -d${optionalString cfg.disableSysRq "s"} - ''; - }; + config = mkIf cfg.enable (mkMerge [ + { + + # for physlock -l and physlock -L + environment.systemPackages = [ pkgs.physlock ]; + + systemd.services."physlock" = { + enable = true; + description = "Physlock"; + wantedBy = optional cfg.lockOn.suspend "suspend.target" + ++ optional cfg.lockOn.hibernate "hibernate.target" + ++ cfg.lockOn.extraTargets; + before = optional cfg.lockOn.suspend "systemd-suspend.service" + ++ optional cfg.lockOn.hibernate "systemd-hibernate.service" + ++ cfg.lockOn.extraTargets; + serviceConfig = { + Type = "forking"; + ExecStart = "${pkgs.physlock}/bin/physlock -d${optionalString cfg.disableSysRq "s"}"; + }; + }; - security.pam.services.physlock = {}; + security.pam.services.physlock = {}; - }; + } + + (mkIf cfg.allowAnyUser { + + security.wrappers.physlock = { source = "${pkgs.physlock}/bin/physlock"; user = "root"; }; + + }) + ]); } diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix index fa4aeb22ae9d..fed91756e769 100644 --- a/nixos/modules/services/security/tor.nix +++ b/nixos/modules/services/security/tor.nix @@ -88,6 +88,9 @@ let ${flip concatMapStrings v.map (p: '' HiddenServicePort ${toString p.port} ${p.destination} '')} + ${optionalString (v.authorizeClient != null) '' + HiddenServiceAuthorizeClient ${v.authorizeClient.authType} ${concatStringsSep "," v.authorizeClient.clientNames} + ''} '')) + cfg.extraConfig; @@ -619,6 +622,33 @@ in })); }; + authorizeClient = mkOption { + default = null; + description = "If configured, the hidden service is accessible for authorized clients only."; + type = types.nullOr (types.submodule ({config, ...}: { + + options = { + + authType = mkOption { + type = types.enum [ "basic" "stealth" ]; + description = '' + Either <literal>"basic"</literal> for a general-purpose authorization protocol + or <literal>"stealth"</literal> for a less scalable protocol + that also hides service activity from unauthorized clients. + ''; + }; + + clientNames = mkOption { + type = types.nonEmptyListOf (types.strMatching "[A-Za-z0-9+-_]+"); + description = '' + Only clients that are listed here are authorized to access the hidden service. + Generated authorization data can be found in <filename>${torDirectory}/onion/$name/hostname</filename>. + Clients need to put this authorization data in their configuration file using <literal>HidServAuth</literal>. + ''; + }; + }; + })); + }; }; config = { diff --git a/nixos/modules/services/ttys/agetty.nix b/nixos/modules/services/ttys/agetty.nix index 3429397d2cc2..b50de496e975 100644 --- a/nixos/modules/services/ttys/agetty.nix +++ b/nixos/modules/services/ttys/agetty.nix @@ -64,8 +64,8 @@ in config = { # Note: this is set here rather than up there so that changing - # nixosLabel would not rebuild manual pages - services.mingetty.greetingLine = mkDefault ''<<< Welcome to NixOS ${config.system.nixosLabel} (\m) - \l >>>''; + # nixos.label would not rebuild manual pages + services.mingetty.greetingLine = mkDefault ''<<< Welcome to NixOS ${config.system.nixos.label} (\m) - \l >>>''; systemd.services."getty@" = { serviceConfig.ExecStart = [ diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 100fabf902f8..dee877f1c114 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -578,6 +578,7 @@ in mkdir -p ${cfg.stateDir}/logs chmod 700 ${cfg.stateDir} chown -R ${cfg.user}:${cfg.group} ${cfg.stateDir} + ${cfg.package}/bin/nginx -c ${configFile} -p ${cfg.stateDir} -t ''; serviceConfig = { ExecStart = "${cfg.package}/bin/nginx -c ${configFile} -p ${cfg.stateDir}"; diff --git a/nixos/modules/services/web-servers/traefik.nix b/nixos/modules/services/web-servers/traefik.nix index 4ede4fc20967..b6c7fef21fb2 100644 --- a/nixos/modules/services/web-servers/traefik.nix +++ b/nixos/modules/services/web-servers/traefik.nix @@ -64,6 +64,16 @@ in { ''; }; + group = mkOption { + default = "traefik"; + type = types.string; + example = "docker"; + description = '' + Set the group that traefik runs under. + For the docker backend this needs to be set to <literal>docker</literal> instead. + ''; + }; + package = mkOption { default = pkgs.traefik; defaultText = "pkgs.traefik"; @@ -87,7 +97,7 @@ in { ]; Type = "simple"; User = "traefik"; - Group = "traefik"; + Group = cfg.group; Restart = "on-failure"; StartLimitInterval = 86400; StartLimitBurst = 5; diff --git a/nixos/modules/services/web-servers/varnish/default.nix b/nixos/modules/services/web-servers/varnish/default.nix index c3bc065d4651..d63fb954ef96 100644 --- a/nixos/modules/services/web-servers/varnish/default.nix +++ b/nixos/modules/services/web-servers/varnish/default.nix @@ -1,9 +1,13 @@ { config, lib, pkgs, ...}: + +with lib; + let cfg = config.services.varnish; + commandLine = "-f ${pkgs.writeText "default.vcl" cfg.config}" + + optionalString (cfg.extraModules != []) " -p vmod_path='${makeSearchPathOutput "lib" "lib/varnish/vmods" ([pkgs.varnish] ++ cfg.extraModules)}' -r vmod_path"; in -with lib; { options = { services.varnish = { @@ -69,8 +73,7 @@ with lib; serviceConfig = { Type = "simple"; PermissionsStartOnly = true; - ExecStart = "${pkgs.varnish}/sbin/varnishd -a ${cfg.http_address} -f ${pkgs.writeText "default.vcl" cfg.config} -n ${cfg.stateDir} -F ${cfg.extraCommandLine}" - + optionalString (cfg.extraModules != []) " -p vmod_path='${makeSearchPathOutput "lib" "lib/varnish/vmods" ([pkgs.varnish] ++ cfg.extraModules)}' -r vmod_path"; + ExecStart = "${pkgs.varnish}/sbin/varnishd -a ${cfg.http_address} -n ${cfg.stateDir} -F ${cfg.extraCommandLine} ${commandLine}"; Restart = "always"; RestartSec = "5s"; User = "varnish"; @@ -83,6 +86,14 @@ with lib; environment.systemPackages = [ pkgs.varnish ]; + # check .vcl syntax at compile time (e.g. before nixops deployment) + system.extraDependencies = [ + (pkgs.stdenv.mkDerivation { + name = "check-varnish-syntax"; + buildCommand = "${pkgs.varnish}/sbin/varnishd -C ${commandLine} 2> $out"; + }) + ]; + users.extraUsers.varnish = { group = "varnish"; uid = config.ids.uids.varnish; diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix index 4c76ce0bb195..b794e2b12d73 100644 --- a/nixos/modules/services/x11/desktop-managers/plasma5.nix +++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix @@ -66,6 +66,10 @@ in security.wrappers = { kcheckpass.source = "${lib.getBin plasma5.plasma-workspace}/lib/libexec/kcheckpass"; "start_kdeinit".source = "${lib.getBin pkgs.kinit}/lib/libexec/kf5/start_kdeinit"; + kwin_wayland = { + source = "${lib.getBin plasma5.kwin}/bin/kwin_wayland"; + capabilities = "cap_sys_nice+ep"; + }; }; environment.systemPackages = with pkgs; with qt5; with libsForQt5; with plasma5; with kdeApplications; diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix index 0c50241f2edf..091a2e412eed 100644 --- a/nixos/modules/system/activation/top-level.nix +++ b/nixos/modules/system/activation/top-level.nix @@ -30,6 +30,8 @@ let let kernelPath = "${config.boot.kernelPackages.kernel}/" + "${config.system.boot.loader.kernelFile}"; + initrdPath = "${config.system.build.initialRamdisk}/" + + "${config.system.boot.loader.initrdFile}"; in '' mkdir $out @@ -50,7 +52,7 @@ let echo -n "$kernelParams" > $out/kernel-params - ln -s ${config.system.build.initialRamdisk}/initrd $out/initrd + ln -s ${initrdPath} $out/initrd ln -s ${config.system.build.initialRamdiskSecretAppender}/bin/append-initrd-secrets $out @@ -106,7 +108,7 @@ let if [] == failed then pkgs.stdenvNoCC.mkDerivation { name = let hn = config.networking.hostName; nn = if (hn != "") then hn else "unnamed"; - in "nixos-system-${nn}-${config.system.nixosLabel}"; + in "nixos-system-${nn}-${config.system.nixos.label}"; preferLocalBuild = true; allowSubstitutes = false; buildCommand = systemBuilder; @@ -120,7 +122,7 @@ let config.system.build.installBootLoader or "echo 'Warning: do not know how to make this configuration bootable; please enable a boot loader.' 1>&2; true"; activationScript = config.system.activationScripts.script; - nixosLabel = config.system.nixosLabel; + nixosLabel = config.system.nixos.label; configurationName = config.boot.loader.grub.configurationName; @@ -179,6 +181,15 @@ in ''; }; + system.boot.loader.initrdFile = mkOption { + internal = true; + default = "initrd"; + type = types.str; + description = '' + Name of the initrd file to be passed to the bootloader. + ''; + }; + system.copySystemConfiguration = mkOption { type = types.bool; default = false; diff --git a/nixos/modules/system/boot/binfmt.nix b/nixos/modules/system/boot/binfmt.nix new file mode 100644 index 000000000000..15e84dc021e2 --- /dev/null +++ b/nixos/modules/system/boot/binfmt.nix @@ -0,0 +1,139 @@ +{ config, lib, ... }: +let + inherit (lib) mkOption types optionalString; + + cfg = config.boot.binfmtMiscRegistrations; + + makeBinfmtLine = name: { recognitionType, offset, magicOrExtension + , mask, preserveArgvZero, openBinary + , matchCredentials, fixBinary, ... + }: let + type = if recognitionType == "magic" then "M" else "E"; + offset' = toString offset; + mask' = toString mask; + interpreter = "/run/binfmt/${name}"; + flags = if !(matchCredentials -> openBinary) + then throw "boot.binfmtMiscRegistrations.${name}: you can't specify openBinary = false when matchCredentials = true." + else optionalString preserveArgvZero "P" + + optionalString (openBinary && !matchCredentials) "O" + + optionalString matchCredentials "C" + + optionalString fixBinary "F"; + in ":${name}:${type}:${offset'}:${magicOrExtension}:${mask'}:${interpreter}:${flags}"; + + binfmtFile = builtins.toFile "binfmt_nixos.conf" + (lib.concatStringsSep "\n" (lib.mapAttrsToList makeBinfmtLine cfg)); + + activationSnippet = name: { interpreter, ... }: + "ln -sf ${interpreter} /run/binfmt/${name}"; + activationScript = '' + mkdir -p -m 0755 /run/binfmt + ${lib.concatStringsSep "\n" (lib.mapAttrsToList activationSnippet cfg)} + ''; +in { + options = { + boot.binfmtMiscRegistrations = mkOption { + default = {}; + + description = '' + Extra binary formats to register with the kernel. + See https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html for more details. + ''; + + type = types.attrsOf (types.submodule ({ config, ... }: { + options = { + recognitionType = mkOption { + default = "magic"; + description = "Whether to recognize executables by magic number or extension."; + type = types.enum [ "magic" "extension" ]; + }; + + offset = mkOption { + default = null; + description = "The byte offset of the magic number used for recognition."; + type = types.nullOr types.int; + }; + + magicOrExtension = mkOption { + description = "The magic number or extension to match on."; + type = types.str; + }; + + mask = mkOption { + default = null; + description = + "A mask to be ANDed with the byte sequence of the file before matching"; + type = types.nullOr types.str; + }; + + interpreter = mkOption { + description = '' + The interpreter to invoke to run the program. + + Note that the actual registration will point to + /run/binfmt/''${name}, so the kernel interpreter length + limit doesn't apply. + ''; + type = types.path; + }; + + preserveArgvZero = mkOption { + default = false; + description = '' + Whether to pass the original argv[0] to the interpreter. + + See the description of the 'P' flag in the kernel docs + for more details; + ''; + type = types.bool; + }; + + openBinary = mkOption { + default = config.matchCredentials; + description = '' + Whether to pass the binary to the interpreter as an open + file descriptor, instead of a path. + ''; + type = types.bool; + }; + + matchCredentials = mkOption { + default = false; + description = '' + Whether to launch with the credentials and security + token of the binary, not the interpreter (e.g. setuid + bit). + + See the description of the 'C' flag in the kernel docs + for more details. + + Implies/requires openBinary = true. + ''; + type = types.bool; + }; + + fixBinary = mkOption { + default = false; + description = '' + Whether to open the interpreter file as soon as the + registration is loaded, rather than waiting for a + relevant file to be invoked. + + See the description of the 'F' flag in the kernel docs + for more details. + ''; + type = types.bool; + }; + }; + })); + }; + }; + + config = lib.mkIf (cfg != {}) { + environment.etc."binfmt.d/nixos.conf".source = binfmtFile; + system.activationScripts.binfmt = activationScript; + systemd.additionalUpstreamSystemUnits = + [ "proc-sys-fs-binfmt_misc.automount" + "proc-sys-fs-binfmt_misc.mount" + ]; + }; +} diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix index d21908f84537..3bd7d3558269 100644 --- a/nixos/modules/system/boot/kernel.nix +++ b/nixos/modules/system/boot/kernel.nix @@ -5,7 +5,7 @@ with lib; let inherit (config.boot) kernelPatches; - + inherit (config.boot.kernel) features; inherit (config.boot.kernelPackages) kernel; kernelModulesConf = pkgs.writeText "nixos.conf" @@ -21,11 +21,25 @@ in options = { + boot.kernel.features = mkOption { + default = {}; + example = literalExample "{ debug = true; }"; + internal = true; + description = '' + This option allows to enable or disable certain kernel features. + It's not API, because it's about kernel feature sets, that + make sense for specific use cases. Mostly along with programs, + which would have separate nixos options. + `grep features pkgs/os-specific/linux/kernel/common-config.nix` + ''; + }; + boot.kernelPackages = mkOption { default = pkgs.linuxPackages; apply = kernelPackages: kernelPackages.extend (self: super: { kernel = super.kernel.override { kernelPatches = super.kernel.kernelPatches ++ kernelPatches; + features = lib.recursiveUpdate super.kernel.features features; }; }); # We don't want to evaluate all of linuxPackages for the manual @@ -170,7 +184,7 @@ in [ "loglevel=${toString config.boot.consoleLogLevel}" ] ++ optionals config.boot.vesa [ "vga=0x317" ]; - boot.kernel.sysctl."kernel.printk" = config.boot.consoleLogLevel; + boot.kernel.sysctl."kernel.printk" = mkDefault config.boot.consoleLogLevel; boot.kernelModules = [ "loop" "atkbd" ]; diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index 9d2cea3ad165..eea10613ea58 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -94,7 +94,7 @@ let checkNetwork = checkUnitConfig "Network" [ (assertOnlyFields [ "Description" "DHCP" "DHCPServer" "IPForward" "IPMasquerade" "IPv4LL" "IPv4LLRoute" - "LLMNR" "MulticastDNS" "Domains" "Bridge" "Bond" + "LLMNR" "MulticastDNS" "Domains" "Bridge" "Bond" "IPv6PrivacyExtensions" ]) (assertValueOneOf "DHCP" ["both" "none" "v4" "v6"]) (assertValueOneOf "DHCPServer" boolValues) @@ -104,6 +104,7 @@ let (assertValueOneOf "IPv4LLRoute" boolValues) (assertValueOneOf "LLMNR" boolValues) (assertValueOneOf "MulticastDNS" boolValues) + (assertValueOneOf "IPv6PrivacyExtensions" ["yes" "no" "prefer-public" "kernel"]) ]; checkAddress = checkUnitConfig "Address" [ @@ -700,7 +701,6 @@ in systemd.additionalUpstreamSystemUnits = [ "systemd-networkd.service" "systemd-networkd-wait-online.service" - "org.freedesktop.network1.busname" ]; systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.link" (linkToUnit n v)) cfg.links diff --git a/nixos/modules/system/boot/plymouth.nix b/nixos/modules/system/boot/plymouth.nix index e78fdf1311d3..f8fb8a64cb9b 100644 --- a/nixos/modules/system/boot/plymouth.nix +++ b/nixos/modules/system/boot/plymouth.nix @@ -10,7 +10,7 @@ let breezePlymouth = pkgs.breeze-plymouth.override { nixosBranding = true; - nixosVersion = config.system.nixosRelease; + nixosVersion = config.system.nixos.release; }; themesEnv = pkgs.buildEnv { diff --git a/nixos/modules/system/boot/resolved.nix b/nixos/modules/system/boot/resolved.nix index 2147d43c4f19..4d9de020c84e 100644 --- a/nixos/modules/system/boot/resolved.nix +++ b/nixos/modules/system/boot/resolved.nix @@ -126,7 +126,7 @@ in config = mkIf cfg.enable { systemd.additionalUpstreamSystemUnits = [ - "systemd-resolved.service" "org.freedesktop.resolve1.busname" + "systemd-resolved.service" ]; systemd.services.systemd-resolved = { diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index b442386914ad..964ec68cfe2f 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -167,6 +167,7 @@ done # Load the required kernel modules. mkdir -p /lib ln -s @modulesClosure@/lib/modules /lib/modules +ln -s @modulesClosure@/lib/firmware /lib/firmware echo @extraUtils@/bin/modprobe > /proc/sys/kernel/modprobe for i in @kernelModules@; do echo "loading module $(basename $i)..." diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index d6e3e3a87d01..df450be8c401 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -13,12 +13,14 @@ let kernelPackages = config.boot.kernelPackages; modulesTree = config.system.modulesTree; + firmware = config.hardware.firmware; # Determine the set of modules that we need to mount the root FS. modulesClosure = pkgs.makeModulesClosure { rootModules = config.boot.initrd.availableKernelModules ++ config.boot.initrd.kernelModules; kernel = modulesTree; + firmware = firmware; allowMissing = true; }; diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index dd9ba7104485..aff46ea861a2 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -14,7 +14,6 @@ let upstreamSystemUnits = [ # Targets. "basic.target" - "busnames.target" "sysinit.target" "sockets.target" "exit.target" @@ -47,6 +46,7 @@ let # Consoles. "getty.target" + "getty-pre.target" "getty@.service" "serial-getty@.service" "console-getty.service" @@ -63,10 +63,7 @@ let "systemd-logind.service" "autovt@.service" "systemd-user-sessions.service" - "dbus-org.freedesktop.login1.service" "dbus-org.freedesktop.machine1.service" - "org.freedesktop.login1.busname" - "org.freedesktop.machine1.busname" "user@.service" # Journal. @@ -99,7 +96,6 @@ let "swap.target" "dev-hugepages.mount" "dev-mqueue.mount" - "proc-sys-fs-binfmt_misc.mount" "sys-fs-fuse-connections.mount" "sys-kernel-config.mount" "sys-kernel-debug.mount" @@ -155,19 +151,16 @@ let "systemd-tmpfiles-setup-dev.service" # Misc. - "org.freedesktop.systemd1.busname" "systemd-sysctl.service" "dbus-org.freedesktop.timedate1.service" "dbus-org.freedesktop.locale1.service" "dbus-org.freedesktop.hostname1.service" - "org.freedesktop.timedate1.busname" - "org.freedesktop.locale1.busname" - "org.freedesktop.hostname1.busname" "systemd-timedated.service" "systemd-localed.service" "systemd-hostnamed.service" "systemd-binfmt.service" "systemd-exit.service" + "systemd-update-done.service" ] ++ cfg.additionalUpstreamSystemUnits; @@ -182,7 +175,6 @@ let upstreamUserUnits = [ "basic.target" "bluetooth.target" - "busnames.target" "default.target" "exit.target" "graphical-session-pre.target" @@ -789,8 +781,7 @@ in # Keep a persistent journal. Note that systemd-tmpfiles will # set proper ownership/permissions. - # FIXME: revert to 0700 with systemd v233. - mkdir -m 0750 -p /var/log/journal + mkdir -m 0700 -p /var/log/journal ''; users.extraUsers.systemd-network.uid = config.ids.uids.systemd-network; @@ -887,7 +878,7 @@ in systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true; systemd.targets.remote-fs.unitConfig.X-StopOnReconfiguration = true; systemd.targets.network-online.wantedBy = [ "multi-user.target" ]; - systemd.services.systemd-binfmt.wants = [ "proc-sys-fs-binfmt_misc.automount" ]; + systemd.services.systemd-binfmt.wants = [ "proc-sys-fs-binfmt_misc.mount" ]; # Don't bother with certain units in containers. systemd.services.systemd-remount-fs.unitConfig.ConditionVirtualization = "!container"; diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix index 2c0a165887bd..30c54ddd0e4e 100644 --- a/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixos/modules/tasks/filesystems/zfs.nix @@ -24,7 +24,11 @@ let kernel = config.boot.kernelPackages; - packages = if config.boot.zfs.enableUnstable then { + packages = if config.boot.zfs.enableLegacyCrypto then { + spl = kernel.splLegacyCrypto; + zfs = kernel.zfsLegacyCrypto; + zfsUser = pkgs.zfsLegacyCrypto; + } else if config.boot.zfs.enableUnstable then { spl = kernel.splUnstable; zfs = kernel.zfsUnstable; zfsUser = pkgs.zfsUnstable; @@ -75,6 +79,27 @@ in ''; }; + enableLegacyCrypto = mkOption { + type = types.bool; + default = false; + description = '' + Enabling this option will allow you to continue to use the old format for + encrypted datasets. With the inclusion of stability patches the format of + encrypted datasets has changed. They can still be accessed and mounted but + in read-only mode mounted. It is highly recommended to convert them to + the new format. + + This option is only for convenience to people that cannot convert their + datasets to the new format yet and it will be removed in due time. + + For migration strategies from old format to this new one, check the Wiki: + https://nixos.wiki/wiki/NixOS_on_ZFS#Encrypted_Dataset_Format_Change + + See https://github.com/zfsonlinux/zfs/pull/6864 for more details about + the stability patches. + ''; + }; + extraPools = mkOption { type = types.listOf types.str; default = []; diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index 63d07832d105..8aa5163ce229 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -20,14 +20,8 @@ let "sys-subsystem-net-devices-${escapeSystemdPath interface}.device"; interfaceIps = i: - i.ip4 ++ optionals cfg.enableIPv6 i.ip6 - ++ optional (i.ipAddress != null) { - address = i.ipAddress; - prefixLength = i.prefixLength; - } ++ optional (cfg.enableIPv6 && i.ipv6Address != null) { - address = i.ipv6Address; - prefixLength = i.ipv6PrefixLength; - }; + i.ipv4.addresses + ++ optionals cfg.enableIPv6 i.ipv6.addresses; destroyBond = i: '' while true; do @@ -80,7 +74,7 @@ let else optional (dev != null && dev != "lo" && !config.boot.isContainer) (subsystemDevice dev); hasDefaultGatewaySet = (cfg.defaultGateway != null && cfg.defaultGateway.address != "") - || (cfg.defaultGateway6 != null && cfg.defaultGateway6.address != ""); + || (cfg.enableIPv6 && cfg.defaultGateway6 != null && cfg.defaultGateway6.address != ""); networkLocalCommands = { after = [ "network-setup.service" ]; @@ -185,33 +179,58 @@ let path = [ pkgs.iproute ]; script = '' - # FIXME: shouldn't this be done in network-link? - echo "bringing up interface..." - ip link set "${i.name}" up - state="/run/nixos/network/addresses/${i.name}" + mkdir -p $(dirname "$state") + ${flip concatMapStrings ips (ip: + let + cidr = "${ip.address}/${toString ip.prefixLength}"; + in + '' + echo "${cidr}" >> $state + echo -n "adding address ${cidr}... " + if out=$(ip addr add "${cidr}" dev "${i.name}" 2>&1); then + echo "done" + elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then + echo "failed" + exit 1 + fi + '' + )} + + state="/run/nixos/network/routes/${i.name}" mkdir -p $(dirname "$state") - '' + flip concatMapStrings (ips) (ip: - let - address = "${ip.address}/${toString ip.prefixLength}"; - in - '' - echo "${address}" >> $state - if out=$(ip addr add "${address}" dev "${i.name}" 2>&1); then - echo "added ip ${address}" - elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then - echo "failed to add ${address}" - exit 1 - fi - ''); + ${flip concatMapStrings (i.ipv4.routes ++ i.ipv6.routes) (route: + let + cidr = "${route.address}/${toString route.prefixLength}"; + via = optionalString (route.via != null) ''via "${route.via}"''; + options = concatStrings (mapAttrsToList (name: val: "${name} ${val} ") route.options); + in + '' + echo "${cidr}" >> $state + echo -n "adding route ${cidr}... " + if out=$(ip route add "${cidr}" ${options} ${via} dev "${i.name}" 2>&1); then + echo "done" + elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then + echo "failed" + exit 1 + fi + '' + )} + ''; preStop = '' + state="/run/nixos/network/routes/${i.name}" + while read cidr; do + echo -n "deleting route $cidr... " + ip route del "$cidr" dev "${i.name}" >/dev/null 2>&1 && echo "done" || echo "failed" + done < "$state" + rm -f "$state" + state="/run/nixos/network/addresses/${i.name}" - while read address; do - echo -n "deleting $address..." - ip addr del "$address" dev "${i.name}" >/dev/null 2>&1 || echo -n " Failed" - echo "" + while read cidr; do + echo -n "deleting address $cidr... " + ip addr del "$cidr" dev "${i.name}" >/dev/null 2>&1 && echo "done" || echo "failed" done < "$state" rm -f "$state" ''; diff --git a/nixos/modules/tasks/network-interfaces-systemd.nix b/nixos/modules/tasks/network-interfaces-systemd.nix index 5d72ad0f1bde..c640e886fca8 100644 --- a/nixos/modules/tasks/network-interfaces-systemd.nix +++ b/nixos/modules/tasks/network-interfaces-systemd.nix @@ -9,14 +9,8 @@ let interfaces = attrValues cfg.interfaces; interfaceIps = i: - i.ip4 ++ optionals cfg.enableIPv6 i.ip6 - ++ optional (i.ipAddress != null) { - address = i.ipAddress; - prefixLength = i.prefixLength; - } ++ optional (cfg.enableIPv6 && i.ipv6Address != null) { - address = i.ipv6Address; - prefixLength = i.ipv6PrefixLength; - }; + i.ipv4.addresses + ++ optionals cfg.enableIPv6 i.ipv6.addresses; dhcpStr = useDHCP: if useDHCP == true || useDHCP == null then "both" else "none"; @@ -91,6 +85,7 @@ in (if i.useDHCP != null then i.useDHCP else cfg.useDHCP && interfaceIps i == [ ])); address = flip map (interfaceIps i) (ip: "${ip.address}/${toString ip.prefixLength}"); + networkConfig.IPv6PrivacyExtensions = "kernel"; } ]; }))) (mkMerge (flip mapAttrsToList cfg.bridges (name: bridge: { diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index f4851988d63d..5036b701bd86 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, utils, stdenv, ... }: +{ config, options, lib, pkgs, utils, stdenv, ... }: with lib; with utils; @@ -101,7 +101,7 @@ let address = mkOption { type = types.str; description = '' - IPv${toString v} address of the interface. Leave empty to configure the + IPv${toString v} address of the interface. Leave empty to configure the interface using DHCP. ''; }; @@ -116,6 +116,40 @@ let }; }; + routeOpts = v: + { options = { + address = mkOption { + type = types.str; + description = "IPv${toString v} address of the network."; + }; + + prefixLength = mkOption { + type = types.addCheck types.int (n: n >= 0 && n <= (if v == 4 then 32 else 128)); + description = '' + Subnet mask of the network, specified as the number of + bits in the prefix (<literal>${if v == 4 then "24" else "64"}</literal>). + ''; + }; + + via = mkOption { + type = types.nullOr types.str; + default = null; + description = "IPv${toString v} address of the next hop."; + }; + + options = mkOption { + type = types.attrsOf types.str; + default = { }; + example = { mtu = "1492"; window = "524288"; }; + description = '' + Other route options. See the symbol <literal>OPTION</literal> + in the <literal>ip-route(8)</literal> manual page for the details. + ''; + }; + + }; + }; + gatewayCoerce = address: { inherit address; }; gatewayOpts = { ... }: { @@ -148,13 +182,22 @@ let interfaceOpts = { name, ... }: { options = { - name = mkOption { example = "eth0"; type = types.str; description = "Name of the interface."; }; + preferTempAddress = mkOption { + type = types.bool; + default = cfg.enableIPv6; + defaultText = literalExample "config.networking.enableIpv6"; + description = '' + When using SLAAC prefer a temporary (IPv6) address over the EUI-64 + address for originating connections. This is used to reduce tracking. + ''; + }; + useDHCP = mkOption { type = types.nullOr types.bool; default = null; @@ -165,7 +208,7 @@ let ''; }; - ip4 = mkOption { + ipv4.addresses = mkOption { default = [ ]; example = [ { address = "10.0.0.1"; prefixLength = 16; } @@ -177,7 +220,7 @@ let ''; }; - ip6 = mkOption { + ipv6.addresses = mkOption { default = [ ]; example = [ { address = "fdfd:b3f0:482::1"; prefixLength = 48; } @@ -189,50 +232,27 @@ let ''; }; - ipAddress = mkOption { - default = null; - example = "10.0.0.1"; - type = types.nullOr types.str; - description = '' - IP address of the interface. Leave empty to configure the - interface using DHCP. - ''; - }; - - prefixLength = mkOption { - default = null; - example = 24; - type = types.nullOr types.int; - description = '' - Subnet mask of the interface, specified as the number of - bits in the prefix (<literal>24</literal>). - ''; - }; - - subnetMask = mkOption { - default = null; - description = '' - Defunct, supply the prefix length instead. - ''; - }; - - ipv6Address = mkOption { - default = null; - example = "2001:1470:fffd:2098::e006"; - type = types.nullOr types.str; + ipv4.routes = mkOption { + default = []; + example = [ + { address = "10.0.0.0"; prefixLength = 16; } + { address = "192.168.2.0"; prefixLength = 24; via = "192.168.1.1"; } + ]; + type = with types; listOf (submodule (routeOpts 4)); description = '' - IPv6 address of the interface. Leave empty to configure the - interface using NDP. + List of extra IPv4 static routes that will be assigned to the interface. ''; }; - ipv6PrefixLength = mkOption { - default = 64; - example = 64; - type = types.int; + ipv6.routes = mkOption { + default = []; + example = [ + { address = "fdfd:b3f0::"; prefixLength = 48; } + { address = "2001:1470:fffd:2098::"; prefixLength = 64; via = "fdfd:b3f0::1"; } + ]; + type = with types; listOf (submodule (routeOpts 6)); description = '' - Subnet mask of the interface, specified as the number of - bits in the prefix (<literal>64</literal>). + List of extra IPv6 static routes that will be assigned to the interface. ''; }; @@ -307,6 +327,32 @@ let name = mkDefault name; }; + # Renamed or removed options + imports = + let + defined = x: x != "_mkMergedOptionModule"; + in [ + (mkRenamedOptionModule [ "ip4" ] [ "ipv4" "addresses"]) + (mkRenamedOptionModule [ "ip6" ] [ "ipv6" "addresses"]) + (mkRemovedOptionModule [ "subnetMask" ] '' + Supply a prefix length instead; use option + networking.interfaces.<name>.ipv{4,6}.addresses'') + (mkMergedOptionModule + [ [ "ipAddress" ] [ "prefixLength" ] ] + [ "ipv4" "addresses" ] + (cfg: with cfg; + optional (defined ipAddress && defined prefixLength) + { address = ipAddress; prefixLength = prefixLength; })) + (mkMergedOptionModule + [ [ "ipv6Address" ] [ "ipv6PrefixLength" ] ] + [ "ipv6" "addresses" ] + (cfg: with cfg; + optional (defined ipv6Address && defined ipv6PrefixLength) + { address = ipv6Address; prefixLength = ipv6PrefixLength; })) + + ({ options.warnings = options.warnings; }) + ]; + }; hexChars = stringToCharacters "0123456789abcdef"; @@ -443,7 +489,7 @@ in networking.interfaces = mkOption { default = {}; example = - { eth0.ip4 = [ { + { eth0.ipv4 = [ { address = "131.211.84.78"; prefixLength = 25; } ]; @@ -922,13 +968,10 @@ in config = { + warnings = concatMap (i: i.warnings) interfaces; + assertions = (flip map interfaces (i: { - assertion = i.subnetMask == null; - message = '' - The networking.interfaces."${i.name}".subnetMask option is defunct. Use prefixLength instead. - ''; - })) ++ (flip map interfaces (i: { # With the linux kernel, interface name length is limited by IFNAMSIZ # to 16 bytes, including the trailing null byte. # See include/linux/if.h in the kernel sources @@ -937,10 +980,15 @@ in The name of networking.interfaces."${i.name}" is too long, it needs to be less than 16 characters. ''; })) ++ (flip map slaveIfs (i: { - assertion = i.ip4 == [ ] && i.ipAddress == null && i.ip6 == [ ] && i.ipv6Address == null; + assertion = i.ipv4.addresses == [ ] && i.ipv6.addresses == [ ]; message = '' The networking.interfaces."${i.name}" must not have any defined ips when it is a slave. ''; + })) ++ (flip map interfaces (i: { + assertion = i.preferTempAddress -> cfg.enableIPv6; + message = '' + Temporary addresses are only needed when IPv6 is enabled. + ''; })) ++ [ { assertion = cfg.hostId == null || (stringLength cfg.hostId == 8 && isHexString cfg.hostId); @@ -963,9 +1011,10 @@ in "net.ipv6.conf.all.disable_ipv6" = mkDefault (!cfg.enableIPv6); "net.ipv6.conf.default.disable_ipv6" = mkDefault (!cfg.enableIPv6); "net.ipv6.conf.all.forwarding" = mkDefault (any (i: i.proxyARP) interfaces); - } // listToAttrs (concatLists (flip map (filter (i: i.proxyARP) interfaces) - (i: flip map [ "4" "6" ] (v: nameValuePair "net.ipv${v}.conf.${i.name}.proxy_arp" true)) - )); + } // listToAttrs (flip concatMap (filter (i: i.proxyARP) interfaces) + (i: flip map [ "4" "6" ] (v: nameValuePair "net.ipv${v}.conf.${i.name}.proxy_arp" true))) + // listToAttrs (flip map (filter (i: i.preferTempAddress) interfaces) + (i: nameValuePair "net.ipv6.conf.${i.name}.use_tempaddr" 2)); # Capabilities won't work unless we have at-least a 4.3 Linux # kernel because we need the ambient capability @@ -1073,6 +1122,9 @@ in '' + optionalString (i.mtu != null) '' echo "setting MTU to ${toString i.mtu}..." ip link set "${i.name}" mtu "${toString i.mtu}" + '' + '' + echo -n "bringing up interface... " + ip link set "${i.name}" up && echo "done" || (echo "failed"; exit 1) ''; }))); diff --git a/nixos/modules/virtualisation/brightbox-image.nix b/nixos/modules/virtualisation/brightbox-image.nix index 08bbcfd9d7c2..39a655b4c104 100644 --- a/nixos/modules/virtualisation/brightbox-image.nix +++ b/nixos/modules/virtualisation/brightbox-image.nix @@ -26,7 +26,7 @@ in rm $diskImageBase popd ''; - diskImageBase = "nixos-image-${config.system.nixosLabel}-${pkgs.stdenv.system}.raw"; + diskImageBase = "nixos-image-${config.system.nixos.label}-${pkgs.stdenv.system}.raw"; buildInputs = [ pkgs.utillinux pkgs.perl ]; exportReferencesGraph = [ "closure" config.system.build.toplevel ]; diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix index 2fb38059b261..155a33b3bb37 100644 --- a/nixos/modules/virtualisation/google-compute-image.nix +++ b/nixos/modules/virtualisation/google-compute-image.nix @@ -14,7 +14,7 @@ in PATH=$PATH:${pkgs.stdenv.lib.makeBinPath [ pkgs.gnutar pkgs.gzip ]} pushd $out mv $diskImage disk.raw - tar -Szcf nixos-image-${config.system.nixosLabel}-${pkgs.stdenv.system}.raw.tar.gz disk.raw + tar -Szcf nixos-image-${config.system.nixos.label}-${pkgs.stdenv.system}.raw.tar.gz disk.raw rm $out/disk.raw popd ''; diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix index b1ff0337994e..4988886baf60 100644 --- a/nixos/modules/virtualisation/lxd.nix +++ b/nixos/modules/virtualisation/lxd.nix @@ -38,6 +38,15 @@ in environment.systemPackages = [ pkgs.lxd ]; + security.apparmor = { + enable = true; + profiles = [ + "${pkgs.lxc}/etc/apparmor.d/usr.bin.lxc-start" + "${pkgs.lxc}/etc/apparmor.d/lxc-containers" + ]; + packages = [ pkgs.lxc ]; + }; + systemd.services.lxd = { description = "LXD Container Management Daemon"; @@ -47,6 +56,10 @@ in # TODO(wkennington): Add lvm2 and thin-provisioning-tools path = with pkgs; [ acl rsync gnutar xz btrfs-progs gzip dnsmasq squashfsTools iproute iptables ]; + preStart = '' + mkdir -m 0755 -p /var/lib/lxc/rootfs + ''; + serviceConfig.ExecStart = "@${pkgs.lxd.bin}/bin/lxd lxd --syslog --group lxd"; serviceConfig.Type = "simple"; serviceConfig.KillMode = "process"; # when stopping, leave the containers alone diff --git a/nixos/modules/virtualisation/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix index bb0c38bd4eb8..7413e12c8f3d 100644 --- a/nixos/modules/virtualisation/virtualbox-host.nix +++ b/nixos/modules/virtualisation/virtualbox-host.nix @@ -124,7 +124,7 @@ in ''; }; - networking.interfaces.vboxnet0.ip4 = [ { address = "192.168.56.1"; prefixLength = 24; } ]; + networking.interfaces.vboxnet0.ipv4.addresses = [{ address = "192.168.56.1"; prefixLength = 24; }]; # Make sure NetworkManager won't assume this interface being up # means we have internet access. networking.networkmanager.unmanaged = ["vboxnet0"]; diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix index a544403e6bed..64f145f77ca3 100644 --- a/nixos/modules/virtualisation/virtualbox-image.nix +++ b/nixos/modules/virtualisation/virtualbox-image.nix @@ -22,7 +22,7 @@ in { config = { system.build.virtualBoxOVA = import ../../lib/make-disk-image.nix { - name = "nixos-ova-${config.system.nixosLabel}-${pkgs.stdenv.system}"; + name = "nixos-ova-${config.system.nixos.label}-${pkgs.stdenv.system}"; inherit pkgs lib config; partitionTableType = "legacy"; @@ -37,7 +37,7 @@ in { VBoxManage internalcommands createrawvmdk -filename disk.vmdk -rawdisk $diskImage echo "creating VirtualBox VM..." - vmName="NixOS ${config.system.nixosLabel} (${pkgs.stdenv.system})" + vmName="NixOS ${config.system.nixos.label} (${pkgs.stdenv.system})" VBoxManage createvm --name "$vmName" --register \ --ostype ${if pkgs.stdenv.system == "x86_64-linux" then "Linux26_64" else "Linux26"} VBoxManage modifyvm "$vmName" \ @@ -53,7 +53,7 @@ in { echo "exporting VirtualBox VM..." mkdir -p $out - fn="$out/nixos-${config.system.nixosLabel}-${pkgs.stdenv.system}.ova" + fn="$out/nixos-${config.system.nixos.label}-${pkgs.stdenv.system}.ova" VBoxManage export "$vmName" --output "$fn" rm -v $diskImage diff --git a/nixos/modules/virtualisation/xen-dom0.nix b/nixos/modules/virtualisation/xen-dom0.nix index c7656bc309c0..afc5a42f8b4e 100644 --- a/nixos/modules/virtualisation/xen-dom0.nix +++ b/nixos/modules/virtualisation/xen-dom0.nix @@ -35,24 +35,19 @@ in description = '' The package used for Xen binary. ''; + relatedPackages = [ "xen" "xen-light" ]; }; - virtualisation.xen.qemu = mkOption { - type = types.path; - defaultText = "\${pkgs.xen}/lib/xen/bin/qemu-system-i386"; - example = literalExample "''${pkgs.qemu_xen-light}/bin/qemu-system-i386"; - description = '' - The qemu binary to use for Dom-0 backend. - ''; - }; - - virtualisation.xen.qemu-package = mkOption { + virtualisation.xen.package-qemu = mkOption { type = types.package; defaultText = "pkgs.xen"; example = literalExample "pkgs.qemu_xen-light"; description = '' - The package with qemu binaries for xendomains. + The package with qemu binaries for dom0 qemu and xendomains. ''; + relatedPackages = [ "xen" + { name = "qemu_xen-light"; comment = "For use with pkgs.xen-light."; } + ]; }; virtualisation.xen.bootParams = @@ -158,8 +153,7 @@ in } ]; virtualisation.xen.package = mkDefault pkgs.xen; - virtualisation.xen.qemu = mkDefault "${pkgs.xen}/lib/xen/bin/qemu-system-i386"; - virtualisation.xen.qemu-package = mkDefault pkgs.xen; + virtualisation.xen.package-qemu = mkDefault pkgs.xen; virtualisation.xen.stored = mkDefault "${cfg.package}/bin/oxenstored"; environment.systemPackages = [ cfg.package ]; @@ -339,7 +333,8 @@ in after = [ "xen-console.service" ]; requires = [ "xen-store.service" ]; serviceConfig.ExecStart = '' - ${cfg.qemu} -xen-attach -xen-domid 0 -name dom0 -M xenpv \ + ${cfg.package-qemu}/${cfg.package-qemu.qemu-system-i386} \ + -xen-attach -xen-domid 0 -name dom0 -M xenpv \ -nographic -monitor /dev/null -serial /dev/null -parallel /dev/null ''; }; @@ -448,7 +443,7 @@ in before = [ "dhcpd.service" ]; restartIfChanged = false; serviceConfig.RemainAfterExit = "yes"; - path = [ cfg.package cfg.qemu-package ]; + path = [ cfg.package cfg.package-qemu ]; environment.XENDOM_CONFIG = "${cfg.package}/etc/sysconfig/xendomains"; preStart = "mkdir -p /var/lock/subsys -m 755"; serviceConfig.ExecStart = "${cfg.package}/etc/init.d/xendomains start"; diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix index 3564e6298256..9d4a551a958b 100644 --- a/nixos/release-combined.nix +++ b/nixos/release-combined.nix @@ -2,7 +2,7 @@ # and nixos-14.04). The channel is updated every time the ‘tested’ job # succeeds, and all other jobs have finished (they may fail). -{ nixpkgs ? { outPath = ./..; revCount = 56789; shortRev = "gfedcba"; } +{ nixpkgs ? { outPath = (import ../lib).cleanSource ./..; revCount = 56789; shortRev = "gfedcba"; } , stableBranch ? false , supportedSystems ? [ "x86_64-linux" ] , limitedSupportedSystems ? [ "i686-linux" ] @@ -52,7 +52,8 @@ in rec { (all nixos.dummy) (all nixos.manual) - (all nixos.iso_minimal) + nixos.iso_minimal.x86_64-linux + nixos.iso_minimal.i686-linux nixos.iso_graphical.x86_64-linux nixos.ova.x86_64-linux diff --git a/nixos/release-small.nix b/nixos/release-small.nix index e9f3cfb4de53..2b532c70763f 100644 --- a/nixos/release-small.nix +++ b/nixos/release-small.nix @@ -2,7 +2,7 @@ # small subset of Nixpkgs, mostly useful for servers that need fast # security updates. -{ nixpkgs ? { outPath = ./..; revCount = 56789; shortRev = "gfedcba"; } +{ nixpkgs ? { outPath = (import ../lib).cleanSource ./..; revCount = 56789; shortRev = "gfedcba"; } , stableBranch ? false , supportedSystems ? [ "x86_64-linux" ] # no i686-linux }: @@ -41,6 +41,7 @@ in rec { nfs3 openssh php-pcre + predictable-interface-names proxy simple; installer = { diff --git a/nixos/release.nix b/nixos/release.nix index a9c0aae7a526..c85150190587 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -1,4 +1,4 @@ -{ nixpkgs ? { outPath = ./..; revCount = 56789; shortRev = "gfedcba"; } +{ nixpkgs ? { outPath = (import ../lib).cleanSource ./..; revCount = 56789; shortRev = "gfedcba"; } , stableBranch ? false , supportedSystems ? [ "x86_64-linux" "aarch64-linux" ] }: @@ -35,8 +35,8 @@ let versionModule = - { system.nixosVersionSuffix = versionSuffix; - system.nixosRevision = nixpkgs.rev or nixpkgs.shortRev; + { system.nixos.versionSuffix = versionSuffix; + system.nixos.revision = nixpkgs.rev or nixpkgs.shortRev; }; @@ -244,6 +244,7 @@ in rec { tests.containers-macvlans = callTest tests/containers-macvlans.nix {}; tests.couchdb = callTest tests/couchdb.nix {}; tests.docker = callTestOnTheseSystems ["x86_64-linux"] tests/docker.nix {}; + tests.docker-tools = callTestOnTheseSystems ["x86_64-linux"] tests/docker-tools.nix {}; tests.docker-edge = callTestOnTheseSystems ["x86_64-linux"] tests/docker-edge.nix {}; tests.dovecot = callTest tests/dovecot.nix {}; tests.dnscrypt-proxy = callTestOnTheseSystems ["x86_64-linux"] tests/dnscrypt-proxy.nix {}; @@ -257,8 +258,10 @@ in rec { tests.firefox = callTest tests/firefox.nix {}; tests.firewall = callTest tests/firewall.nix {}; tests.fleet = callTestOnTheseSystems ["x86_64-linux"] tests/fleet.nix {}; + #tests.fwupd = callTest tests/fwupd.nix {}; # build during evaluation #tests.gitlab = callTest tests/gitlab.nix {}; tests.gitolite = callTest tests/gitolite.nix {}; + tests.gjs = callTest tests/gjs.nix {}; tests.gocd-agent = callTest tests/gocd-agent.nix {}; tests.gocd-server = callTest tests/gocd-server.nix {}; tests.gnome3 = callTest tests/gnome3.nix {}; @@ -276,6 +279,7 @@ in rec { tests.ipv6 = callTest tests/ipv6.nix {}; tests.jenkins = callTest tests/jenkins.nix {}; tests.plasma5 = callTest tests/plasma5.nix {}; + tests.plotinus = callTest tests/plotinus.nix {}; tests.keymap = callSubTests tests/keymap.nix {}; tests.initrdNetwork = callTest tests/initrd-network.nix {}; tests.kafka_0_9 = callTest tests/kafka_0_9.nix {}; @@ -314,6 +318,7 @@ in rec { tests.nfs4 = callTest tests/nfs.nix { version = 4; }; tests.nginx = callTest tests/nginx.nix { }; tests.nghttpx = callTest tests/nghttpx.nix { }; + tests.novacomd = callTestOnTheseSystems ["x86_64-linux"] tests/novacomd.nix { }; tests.leaps = callTest tests/leaps.nix { }; tests.nsd = callTest tests/nsd.nix {}; tests.openssh = callTest tests/openssh.nix {}; @@ -325,15 +330,20 @@ in rec { tests.postgresql = callSubTests tests/postgresql.nix {}; tests.pgmanage = callTest tests/pgmanage.nix {}; tests.postgis = callTest tests/postgis.nix {}; + tests.powerdns = callTest tests/powerdns.nix {}; #tests.pgjwt = callTest tests/pgjwt.nix {}; + tests.predictable-interface-names = callSubTests tests/predictable-interface-names.nix {}; tests.printing = callTest tests/printing.nix {}; tests.prometheus = callTest tests/prometheus.nix {}; tests.proxy = callTest tests/proxy.nix {}; tests.pumpio = callTest tests/pump.io.nix {}; # tests.quagga = callTest tests/quagga.nix {}; tests.quake3 = callTest tests/quake3.nix {}; + tests.rabbitmq = callTest tests/rabbitmq.nix {}; tests.radicale = callTest tests/radicale.nix {}; + tests.rspamd = callSubTests tests/rspamd.nix {}; tests.runInMachine = callTest tests/run-in-machine.nix {}; + tests.rxe = callTest tests/rxe.nix {}; tests.samba = callTest tests/samba.nix {}; tests.sddm = callSubTests tests/sddm.nix {}; tests.simple = callTest tests/simple.nix {}; @@ -351,6 +361,7 @@ in rec { tests.wordpress = callTest tests/wordpress.nix {}; tests.xfce = callTest tests/xfce.nix {}; tests.xmonad = callTest tests/xmonad.nix {}; + tests.yabar = callTest tests/yabar.nix {}; tests.zookeeper = callTest tests/zookeeper.nix {}; /* Build a bunch of typical closures so that Hydra can keep track of diff --git a/nixos/tests/bittorrent.nix b/nixos/tests/bittorrent.nix index 3a718a798315..50c98664660a 100644 --- a/nixos/tests/bittorrent.nix +++ b/nixos/tests/bittorrent.nix @@ -16,7 +16,7 @@ let miniupnpdConf = nodes: pkgs.writeText "miniupnpd.conf" '' ext_ifname=eth1 - listening_ip=${(pkgs.lib.head nodes.router.config.networking.interfaces.eth2.ip4).address}/24 + listening_ip=${(pkgs.lib.head nodes.router.config.networking.interfaces.eth2.ipv4.addresses).address}/24 allow 1024-65535 192.168.2.0/24 1024-65535 ''; @@ -56,7 +56,7 @@ in { environment.systemPackages = [ pkgs.transmission ]; virtualisation.vlans = [ 2 ]; networking.defaultGateway = - (pkgs.lib.head nodes.router.config.networking.interfaces.eth2.ip4).address; + (pkgs.lib.head nodes.router.config.networking.interfaces.eth2.ipv4.addresses).address; networking.firewall.enable = false; }; @@ -84,7 +84,7 @@ in # Create the torrent. $tracker->succeed("mkdir /tmp/data"); $tracker->succeed("cp ${file} /tmp/data/test.tar.bz2"); - $tracker->succeed("transmission-create /tmp/data/test.tar.bz2 -p -t http://${(pkgs.lib.head nodes.tracker.config.networking.interfaces.eth1.ip4).address}:6969/announce -o /tmp/test.torrent"); + $tracker->succeed("transmission-create /tmp/data/test.tar.bz2 -p -t http://${(pkgs.lib.head nodes.tracker.config.networking.interfaces.eth1.ipv4.addresses).address}:6969/announce -o /tmp/test.torrent"); $tracker->succeed("chmod 644 /tmp/test.torrent"); # Start the tracker. !!! use a less crappy tracker diff --git a/nixos/tests/boot-stage1.nix b/nixos/tests/boot-stage1.nix index eeaca9f50edc..b2e74bff6fcd 100644 --- a/nixos/tests/boot-stage1.nix +++ b/nixos/tests/boot-stage1.nix @@ -9,6 +9,7 @@ import ./make-test.nix ({ pkgs, ... }: { kver = config.boot.kernelPackages.kernel.modDirVersion; ksrc = "${kdev}/lib/modules/${kver}/build"; hardeningDisable = [ "pic" ]; + nativeBuildInputs = kdev.moduleBuildDependencies; } '' echo "obj-m += $name.o" > Makefile echo "$source" > "$name.c" diff --git a/nixos/tests/cjdns.nix b/nixos/tests/cjdns.nix index 466663799241..4d3b58abc6e5 100644 --- a/nixos/tests/cjdns.nix +++ b/nixos/tests/cjdns.nix @@ -12,7 +12,6 @@ let # the sequence of address assignment less stochastic. networking.useDHCP = false; - networking.interfaces.eth1.prefixLength = 24; # CJDNS output is incompatible with the XML log. systemd.services.cjdns.serviceConfig.StandardOutput = "null"; #networking.firewall.enable = true; @@ -49,7 +48,9 @@ import ./make-test.nix ({ pkgs, ...} : { { imports = [ basicConfig ]; - networking.interfaces.eth1.ipAddress = "192.168.0.2"; + networking.interfaces.eth1.ipv4.addresses = [ + { address = "192.168.0.2"; prefixLength = 24; } + ]; services.cjdns = { UDPInterface = @@ -76,7 +77,9 @@ import ./make-test.nix ({ pkgs, ...} : { CJDNS_ADMIN_PASSWORD=FOOBAR ''; - networking.interfaces.eth1.ipAddress = "192.168.0.1"; + networking.interfaces.eth1.ipv4.addresses = [ + { address = "192.168.0.1"; prefixLength = 24; } + ]; services.cjdns = { authorizedPasswords = [ carolPassword ]; diff --git a/nixos/tests/containers-bridge.nix b/nixos/tests/containers-bridge.nix index b8d4759684cc..dfef46a2ada4 100644 --- a/nixos/tests/containers-bridge.nix +++ b/nixos/tests/containers-bridge.nix @@ -26,8 +26,8 @@ import ./make-test.nix ({ pkgs, ...} : { }; networking.interfaces = { br0 = { - ip4 = [{ address = hostIp; prefixLength = 24; }]; - ip6 = [{ address = hostIp6; prefixLength = 7; }]; + ipv4.addresses = [{ address = hostIp; prefixLength = 24; }]; + ipv6.addresses = [{ address = hostIp6; prefixLength = 7; }]; }; }; diff --git a/nixos/tests/containers-extra_veth.nix b/nixos/tests/containers-extra_veth.nix index 6339c8c558b9..df3f3354b2d9 100644 --- a/nixos/tests/containers-extra_veth.nix +++ b/nixos/tests/containers-extra_veth.nix @@ -21,11 +21,11 @@ import ./make-test.nix ({ pkgs, ...} : { }; networking.interfaces = { br0 = { - ip4 = [{ address = "192.168.0.1"; prefixLength = 24; }]; - ip6 = [{ address = "fc00::1"; prefixLength = 7; }]; + ipv4.addresses = [{ address = "192.168.0.1"; prefixLength = 24; }]; + ipv6.addresses = [{ address = "fc00::1"; prefixLength = 7; }]; }; br1 = { - ip4 = [{ address = "192.168.1.1"; prefixLength = 24; }]; + ipv4.addresses = [{ address = "192.168.1.1"; prefixLength = 24; }]; }; }; diff --git a/nixos/tests/containers-hosts.nix b/nixos/tests/containers-hosts.nix index c7a85f190a5d..df1ef6d14936 100644 --- a/nixos/tests/containers-hosts.nix +++ b/nixos/tests/containers-hosts.nix @@ -13,9 +13,9 @@ import ./make-test.nix ({ pkgs, ...} : { virtualisation.vlans = []; networking.bridges.br0.interfaces = []; - networking.interfaces.br0 = { - ip4 = [ { address = "10.11.0.254"; prefixLength = 24; } ]; - }; + networking.interfaces.br0.ipv4.addresses = [ + { address = "10.11.0.254"; prefixLength = 24; } + ]; # Force /etc/hosts to be the only source for host name resolution environment.etc."nsswitch.conf".text = lib.mkForce '' diff --git a/nixos/tests/containers-macvlans.nix b/nixos/tests/containers-macvlans.nix index 721f98481497..390dc4ad2c29 100644 --- a/nixos/tests/containers-macvlans.nix +++ b/nixos/tests/containers-macvlans.nix @@ -26,9 +26,9 @@ import ./make-test.nix ({ pkgs, ...} : { interface = "eth1"; mode = "bridge"; }; - networking.interfaces.eth1.ip4 = lib.mkForce []; + networking.interfaces.eth1.ipv4.addresses = lib.mkForce []; networking.interfaces.mv-eth1-host = { - ip4 = [ { address = "192.168.1.1"; prefixLength = 24; } ]; + ipv4.addresses = [ { address = "192.168.1.1"; prefixLength = 24; } ]; }; containers.test1 = { @@ -37,7 +37,7 @@ import ./make-test.nix ({ pkgs, ...} : { config = { networking.interfaces.mv-eth1 = { - ip4 = [ { address = containerIp1; prefixLength = 24; } ]; + ipv4.addresses = [ { address = containerIp1; prefixLength = 24; } ]; }; }; }; @@ -48,7 +48,7 @@ import ./make-test.nix ({ pkgs, ...} : { config = { networking.interfaces.mv-eth1 = { - ip4 = [ { address = containerIp2; prefixLength = 24; } ]; + ipv4.addresses = [ { address = containerIp2; prefixLength = 24; } ]; }; }; }; diff --git a/nixos/tests/containers-physical_interfaces.nix b/nixos/tests/containers-physical_interfaces.nix index a3b0b29951bf..bd1228b8e37d 100644 --- a/nixos/tests/containers-physical_interfaces.nix +++ b/nixos/tests/containers-physical_interfaces.nix @@ -16,9 +16,9 @@ import ./make-test.nix ({ pkgs, ...} : { interfaces = [ "eth1" ]; config = { - networking.interfaces.eth1 = { - ip4 = [ { address = "10.10.0.1"; prefixLength = 24; } ]; - }; + networking.interfaces.eth1.ipv4.addresses = [ + { address = "10.10.0.1"; prefixLength = 24; } + ]; networking.firewall.enable = false; }; }; @@ -33,9 +33,9 @@ import ./make-test.nix ({ pkgs, ...} : { config = { networking.bridges.br0.interfaces = [ "eth1" ]; - networking.interfaces.br0 = { - ip4 = [ { address = "10.10.0.2"; prefixLength = 24; } ]; - }; + networking.interfaces.br0.ipv4.addresses = [ + { address = "10.10.0.2"; prefixLength = 24; } + ]; networking.firewall.enable = false; }; }; @@ -54,9 +54,9 @@ import ./make-test.nix ({ pkgs, ...} : { interfaces = [ "eth1" ]; mode = "active-backup"; }; - networking.interfaces.bond0 = { - ip4 = [ { address = "10.10.0.3"; prefixLength = 24; } ]; - }; + networking.interfaces.bond0.ipv4.addresses = [ + { address = "10.10.0.3"; prefixLength = 24; } + ]; networking.firewall.enable = false; }; }; @@ -76,9 +76,9 @@ import ./make-test.nix ({ pkgs, ...} : { mode = "active-backup"; }; networking.bridges.br0.interfaces = [ "bond0" ]; - networking.interfaces.br0 = { - ip4 = [ { address = "10.10.0.4"; prefixLength = 24; } ]; - }; + networking.interfaces.br0.ipv4.addresses = [ + { address = "10.10.0.4"; prefixLength = 24; } + ]; networking.firewall.enable = false; }; }; diff --git a/nixos/tests/containers-reloadable.nix b/nixos/tests/containers-reloadable.nix index b5867c6f6ab1..5fb42f2272b3 100644 --- a/nixos/tests/containers-reloadable.nix +++ b/nixos/tests/containers-reloadable.nix @@ -11,7 +11,7 @@ let # prevent make-test.nix to change IP networking.interfaces = { - eth1.ip4 = lib.mkOverride 0 [ ]; + eth1.ipv4.addresses = lib.mkOverride 0 [ ]; }; }; in { diff --git a/nixos/tests/containers-restart_networking.nix b/nixos/tests/containers-restart_networking.nix index 086d056c51cd..f68c9b07759b 100644 --- a/nixos/tests/containers-restart_networking.nix +++ b/nixos/tests/containers-restart_networking.nix @@ -11,7 +11,7 @@ let config = { networking.firewall.enable = false; networking.firewall.allowPing = true; - networking.interfaces.eth0.ip4 = [ + networking.interfaces.eth0.ipv4.addresses = [ { address = "192.168.1.122"; prefixLength = 24; } ]; }; @@ -33,8 +33,8 @@ in import ./make-test.nix ({ pkgs, lib, ...} : rstp = false; }; networking.interfaces = { - eth1.ip4 = lib.mkOverride 0 [ ]; - br0.ip4 = [{ address = "192.168.1.1"; prefixLength = 24; }]; + eth1.ipv4.addresses = lib.mkOverride 0 [ ]; + br0.ipv4.addresses = [ { address = "192.168.1.1"; prefixLength = 24; } ]; }; }; @@ -44,8 +44,8 @@ in import ./make-test.nix ({ pkgs, lib, ...} : rstp = false; }; networking.interfaces = { - eth1.ip4 = lib.mkOverride 0 [ ]; - br0.ip4 = [{ address = "192.168.1.2"; prefixLength = 24; }]; + eth1.ipv4.addresses = lib.mkOverride 0 [ ]; + br0.ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ]; }; }; client_eth1_rstp = { lib, pkgs, ... }: client_base // { @@ -54,8 +54,8 @@ in import ./make-test.nix ({ pkgs, lib, ...} : rstp = true; }; networking.interfaces = { - eth1.ip4 = lib.mkOverride 0 [ ]; - br0.ip4 = [{ address = "192.168.1.2"; prefixLength = 24; }]; + eth1.ipv4.addresses = lib.mkOverride 0 [ ]; + br0.ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ]; }; }; }; diff --git a/nixos/tests/docker-tools.nix b/nixos/tests/docker-tools.nix new file mode 100644 index 000000000000..e52a4c3f884e --- /dev/null +++ b/nixos/tests/docker-tools.nix @@ -0,0 +1,39 @@ +# this test creates a simple GNU image with docker tools and sees if it executes + +import ./make-test.nix ({ pkgs, ... }: { + name = "docker-tools"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ ]; + }; + + nodes = { + docker = + { config, pkgs, ... }: { + virtualisation = { + diskSize = 1024; + docker.enable = true; + }; + }; + }; + + testScript = + '' + $docker->waitForUnit("sockets.target"); + + $docker->succeed("docker load --input='${pkgs.dockerTools.examples.bash}'"); + $docker->succeed("docker run ${pkgs.dockerTools.examples.bash.imageName} /bin/bash --version"); + + $docker->succeed("docker load --input='${pkgs.dockerTools.examples.nix}'"); + $docker->succeed("docker run ${pkgs.dockerTools.examples.nix.imageName} /bin/nix-store -qR ${pkgs.nix}"); + + # To test the pullImage tool + $docker->succeed("docker load --input='${pkgs.dockerTools.examples.nixFromDockerHub}'"); + $docker->succeed("docker run nixos/nix:1.11 nix-store --version"); + + # To test runAsRoot and entry point + $docker->succeed("docker load --input='${pkgs.dockerTools.examples.nginx}'"); + $docker->succeed("docker run --name nginx -d -p 8000:80 ${pkgs.dockerTools.examples.nginx.imageName}"); + $docker->waitUntilSucceeds('curl http://localhost:8000/'); + $docker->succeed("docker rm --force nginx"); + ''; +}) diff --git a/nixos/tests/ferm.nix b/nixos/tests/ferm.nix index 8f2a8c01eebc..bb7daae118c0 100644 --- a/nixos/tests/ferm.nix +++ b/nixos/tests/ferm.nix @@ -11,8 +11,8 @@ import ./make-test.nix ({ pkgs, ...} : { with pkgs.lib; { networking = { - interfaces.eth1.ip6 = mkOverride 0 [ { address = "fd00::2"; prefixLength = 64; } ]; - interfaces.eth1.ip4 = mkOverride 0 [ { address = "192.168.1.2"; prefixLength = 24; } ]; + interfaces.eth1.ipv6.addresses = mkOverride 0 [ { address = "fd00::2"; prefixLength = 64; } ]; + interfaces.eth1.ipv4.addresses = mkOverride 0 [ { address = "192.168.1.2"; prefixLength = 24; } ]; }; }; server = @@ -20,8 +20,8 @@ import ./make-test.nix ({ pkgs, ...} : { with pkgs.lib; { networking = { - interfaces.eth1.ip6 = mkOverride 0 [ { address = "fd00::1"; prefixLength = 64; } ]; - interfaces.eth1.ip4 = mkOverride 0 [ { address = "192.168.1.1"; prefixLength = 24; } ]; + interfaces.eth1.ipv6.addresses = mkOverride 0 [ { address = "fd00::1"; prefixLength = 64; } ]; + interfaces.eth1.ipv4.addresses = mkOverride 0 [ { address = "192.168.1.1"; prefixLength = 24; } ]; }; services = { diff --git a/nixos/tests/fwupd.nix b/nixos/tests/fwupd.nix new file mode 100644 index 000000000000..bf4ef25130b3 --- /dev/null +++ b/nixos/tests/fwupd.nix @@ -0,0 +1,19 @@ +# run installed tests +import ./make-test.nix ({ pkgs, ... }: { + name = "fwupd"; + + meta = { + maintainers = pkgs.fwupd.meta.maintainers; + }; + + machine = { config, pkgs, ... }: { + services.fwupd.enable = true; + environment.systemPackages = with pkgs; [ gnome-desktop-testing ]; + environment.variables.XDG_DATA_DIRS = [ "${pkgs.fwupd.installedTests}/share" ]; + virtualisation.memorySize = 768; + }; + + testScript = '' + $machine->succeed("gnome-desktop-testing-runner"); + ''; +}) diff --git a/nixos/tests/gjs.nix b/nixos/tests/gjs.nix new file mode 100644 index 000000000000..e6002ef98dd0 --- /dev/null +++ b/nixos/tests/gjs.nix @@ -0,0 +1,19 @@ +# run installed tests +import ./make-test.nix ({ pkgs, ... }: { + name = "gjs"; + + meta = { + maintainers = pkgs.gnome3.gjs.meta.maintainers; + }; + + machine = { pkgs, ... }: { + imports = [ ./common/x11.nix ]; + environment.systemPackages = with pkgs; [ gnome-desktop-testing ]; + environment.variables.XDG_DATA_DIRS = [ "${pkgs.gnome3.gjs.installedTests}/share" ]; + }; + + testScript = '' + $machine->waitForX; + $machine->succeed("gnome-desktop-testing-runner"); + ''; +}) diff --git a/nixos/tests/home-assistant.nix b/nixos/tests/home-assistant.nix index 5d7e0ec65e73..2e45dc78471f 100644 --- a/nixos/tests/home-assistant.nix +++ b/nixos/tests/home-assistant.nix @@ -2,17 +2,27 @@ import ./make-test.nix ({ pkgs, ... }: let configDir = "/var/lib/foobar"; + apiPassword = "secret"; in { name = "home-assistant"; + meta = with pkgs.stdenv.lib; { + maintainers = with maintainers; [ dotlambda ]; + }; nodes = { hass = { config, pkgs, ... }: { + environment.systemPackages = with pkgs; [ + mosquitto + ]; services.home-assistant = { inherit configDir; enable = true; + package = pkgs.home-assistant.override { + extraPackages = ps: with ps; [ hbmqtt ]; + }; config = { homeassistant = { name = "Home"; @@ -22,7 +32,16 @@ in { elevation = 0; }; frontend = { }; - http = { }; + http.api_password = apiPassword; + mqtt = { }; # Use hbmqtt as broker + binary_sensor = [ + { + platform = "mqtt"; + state_topic = "home-assistant/test"; + payload_on = "let_there_be_light"; + payload_off = "off"; + } + ]; }; }; }; @@ -31,7 +50,7 @@ in { testScript = '' startAll; $hass->waitForUnit("home-assistant.service"); - + # Since config is specified using a Nix attribute set, # configuration.yaml is a link to the Nix store $hass->succeed("test -L ${configDir}/configuration.yaml"); @@ -39,8 +58,19 @@ in { # Check that Home Assistant's web interface and API can be reached $hass->waitForOpenPort(8123); $hass->succeed("curl --fail http://localhost:8123/states"); - $hass->succeed("curl --fail http://localhost:8123/api/ | grep 'API running'"); + $hass->succeed("curl --fail -H 'x-ha-access: ${apiPassword}' http://localhost:8123/api/ | grep -qF 'API running'"); + # Toggle a binary sensor using MQTT + $hass->succeed("curl http://localhost:8123/api/states/binary_sensor.mqtt_binary_sensor -H 'x-ha-access: ${apiPassword}' | grep -qF '\"state\": \"off\"'"); + $hass->waitUntilSucceeds("mosquitto_pub -V mqttv311 -t home-assistant/test -u homeassistant -P '${apiPassword}' -m let_there_be_light"); + $hass->succeed("curl http://localhost:8123/api/states/binary_sensor.mqtt_binary_sensor -H 'x-ha-access: ${apiPassword}' | grep -qF '\"state\": \"on\"'"); + + # Check that no errors were logged $hass->fail("cat ${configDir}/home-assistant.log | grep -qF ERROR"); + + # Print log to ease debugging + my $log = $hass->succeed("cat ${configDir}/home-assistant.log"); + print "\n### home-assistant.log ###\n"; + print "$log\n"; ''; }) diff --git a/nixos/tests/initrd-network-ssh/default.nix b/nixos/tests/initrd-network-ssh/default.nix index 9d476cb1a967..b1f3d147e862 100644 --- a/nixos/tests/initrd-network-ssh/default.nix +++ b/nixos/tests/initrd-network-ssh/default.nix @@ -11,9 +11,7 @@ import ../make-test.nix ({ pkgs, lib, ... }: { config, pkgs, ... }: { boot.kernelParams = [ - "ip=${ - (head config.networking.interfaces.eth1.ip4).address - }:::255.255.255.0::eth1:none" + "ip=${config.networking.primaryIPAddress}:::255.255.255.0::eth1:none" ]; boot.initrd.network = { enable = true; diff --git a/nixos/tests/ipv6.nix b/nixos/tests/ipv6.nix index 060f63216796..7a98fd85cfda 100644 --- a/nixos/tests/ipv6.nix +++ b/nixos/tests/ipv6.nix @@ -47,7 +47,7 @@ import ./make-test.nix ({ pkgs, ...} : { # Detection). sub waitForAddress { my ($machine, $iface, $scope) = @_; - $machine->waitUntilSucceeds("[ `ip -o -6 addr show dev $iface scope $scope | grep -v tentative | wc -l` -eq 1 ]"); + $machine->waitUntilSucceeds("[ `ip -o -6 addr show dev $iface scope $scope | grep -v tentative | wc -l` -ge 1 ]"); my $ip = (split /[ \/]+/, $machine->succeed("ip -o -6 addr show dev $iface scope $scope"))[3]; $machine->log("$scope address on $iface is $ip"); return $ip; diff --git a/nixos/tests/kubernetes/base.nix b/nixos/tests/kubernetes/base.nix index f3b930b630ba..27b99aacab7d 100644 --- a/nixos/tests/kubernetes/base.nix +++ b/nixos/tests/kubernetes/base.nix @@ -7,7 +7,7 @@ let mkKubernetesBaseTest = { name, domain ? "my.zyx", test, machines , pkgs ? import <nixpkgs> { inherit system; } - , certs ? import ./certs.nix { inherit pkgs; externalDomain = domain; } + , certs ? import ./certs.nix { inherit pkgs; externalDomain = domain; kubelets = attrNames machines; } , extraConfiguration ? null }: let masterName = head (filter (machineName: any (role: role == "master") machines.${machineName}.roles) (attrNames machines)); diff --git a/nixos/tests/kubernetes/certs.nix b/nixos/tests/kubernetes/certs.nix index f108e35b98cd..d3eff910c467 100644 --- a/nixos/tests/kubernetes/certs.nix +++ b/nixos/tests/kubernetes/certs.nix @@ -2,7 +2,8 @@ pkgs ? import <nixpkgs> {}, internalDomain ? "cloud.yourdomain.net", externalDomain ? "myawesomecluster.cluster.yourdomain.net", - serviceClusterIp ? "10.0.0.1" + serviceClusterIp ? "10.0.0.1", + kubelets }: let runWithCFSSL = name: cmd: @@ -123,9 +124,10 @@ let }; apiserver-client = { - kubelet = createClientCertKey { + kubelet = hostname: createClientCertKey { inherit ca; - cn = "apiserver-client-kubelet"; + name = "apiserver-client-kubelet-${hostname}"; + cn = "system:node:${hostname}.${externalDomain}"; groups = ["system:nodes"]; }; @@ -175,10 +177,9 @@ in { paths = [ (writeCFSSL (noKey ca)) (writeCFSSL kubelet) - (writeCFSSL apiserver-client.kubelet) (writeCFSSL apiserver-client.kube-proxy) (writeCFSSL etcd-client) - ]; + ] ++ map (hostname: writeCFSSL (apiserver-client.kubelet hostname)) kubelets; }; admin = writeCFSSL apiserver-client.admin; diff --git a/nixos/tests/kubernetes/dns.nix b/nixos/tests/kubernetes/dns.nix index 74d98dabec8d..8c488d271bcd 100644 --- a/nixos/tests/kubernetes/dns.nix +++ b/nixos/tests/kubernetes/dns.nix @@ -3,7 +3,7 @@ with import ./base.nix { inherit system; }; let domain = "my.zyx"; - certs = import ./certs.nix { externalDomain = domain; }; + certs = import ./certs.nix { externalDomain = domain; kubelets = [ "machine1" "machine2" ]; }; redisPod = pkgs.writeText "redis-pod.json" (builtins.toJSON { kind = "Pod"; diff --git a/nixos/tests/kubernetes/kubernetes-common.nix b/nixos/tests/kubernetes/kubernetes-common.nix index 00a5c9aba4e3..ddf427e1b01a 100644 --- a/nixos/tests/kubernetes/kubernetes-common.nix +++ b/nixos/tests/kubernetes/kubernetes-common.nix @@ -29,8 +29,8 @@ let tlsKeyFile = "${certs.worker}/kubelet-key.pem"; hostname = "${config.networking.hostName}.${config.networking.domain}"; kubeconfig = { - certFile = "${certs.worker}/apiserver-client-kubelet.pem"; - keyFile = "${certs.worker}/apiserver-client-kubelet-key.pem"; + certFile = "${certs.worker}/apiserver-client-kubelet-${config.networking.hostName}.pem"; + keyFile = "${certs.worker}/apiserver-client-kubelet-${config.networking.hostName}-key.pem"; }; }; controllerManager = { diff --git a/nixos/tests/nat.nix b/nixos/tests/nat.nix index a12b7645bc28..7057158a829b 100644 --- a/nixos/tests/nat.nix +++ b/nixos/tests/nat.nix @@ -35,7 +35,7 @@ import ./make-test.nix ({ pkgs, lib, withFirewall, withConntrackHelpers ? false, { virtualisation.vlans = [ 1 ]; networking.firewall.allowPing = true; networking.defaultGateway = - (pkgs.lib.head nodes.router.config.networking.interfaces.eth2.ip4).address; + (pkgs.lib.head nodes.router.config.networking.interfaces.eth2.ipv4.addresses).address; } (lib.optionalAttrs withConntrackHelpers { networking.firewall.connectionTrackingModules = [ "ftp" ]; diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix index 182328b32962..5cb40af5799e 100644 --- a/nixos/tests/networking.nix +++ b/nixos/tests/networking.nix @@ -21,10 +21,8 @@ let firewall.allowedUDPPorts = [ 547 ]; interfaces = mkOverride 0 (listToAttrs (flip map vlanIfs (n: nameValuePair "eth${toString n}" { - ipAddress = "192.168.${toString n}.1"; - prefixLength = 24; - ipv6Address = "fd00:1234:5678:${toString n}::1"; - ipv6PrefixLength = 64; + ipv4.addresses = [ { address = "192.168.${toString n}.1"; prefixLength = 24; } ]; + ipv6.addresses = [ { address = "fd00:1234:5678:${toString n}::1"; prefixLength = 64; } ]; }))); }; services.dhcpd4 = { @@ -90,12 +88,12 @@ let firewall.allowPing = true; useDHCP = false; defaultGateway = "192.168.1.1"; - interfaces.eth1.ip4 = mkOverride 0 [ + interfaces.eth1.ipv4.addresses = 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 [ + interfaces.eth2.ipv4.addresses = mkOverride 0 [ { address = "192.168.2.2"; prefixLength = 24; } ]; }; @@ -143,12 +141,12 @@ let firewall.allowPing = true; useDHCP = true; interfaces.eth1 = { - ip4 = mkOverride 0 [ ]; - ip6 = mkOverride 0 [ ]; + ipv4.addresses = mkOverride 0 [ ]; + ipv6.addresses = mkOverride 0 [ ]; }; interfaces.eth2 = { - ip4 = mkOverride 0 [ ]; - ip6 = mkOverride 0 [ ]; + ipv4.addresses = mkOverride 0 [ ]; + ipv6.addresses = mkOverride 0 [ ]; }; }; }; @@ -198,10 +196,10 @@ let firewall.allowPing = true; useDHCP = false; interfaces.eth1 = { - ip4 = mkOverride 0 [ ]; + ipv4.addresses = mkOverride 0 [ ]; useDHCP = true; }; - interfaces.eth2.ip4 = mkOverride 0 [ ]; + interfaces.eth2.ipv4.addresses = mkOverride 0 [ ]; }; }; testScript = { nodes, ... }: @@ -241,9 +239,9 @@ let interfaces = [ "eth1" "eth2" ]; driverOptions.mode = "balance-rr"; }; - interfaces.eth1.ip4 = mkOverride 0 [ ]; - interfaces.eth2.ip4 = mkOverride 0 [ ]; - interfaces.bond.ip4 = mkOverride 0 + interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; + interfaces.eth2.ipv4.addresses = mkOverride 0 [ ]; + interfaces.bond.ipv4.addresses = mkOverride 0 [ { inherit address; prefixLength = 30; } ]; }; }; @@ -274,7 +272,7 @@ let useNetworkd = networkd; firewall.allowPing = true; useDHCP = false; - interfaces.eth1.ip4 = mkOverride 0 + interfaces.eth1.ipv4.addresses = mkOverride 0 [ { inherit address; prefixLength = 24; } ]; }; }; @@ -289,9 +287,9 @@ let 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 + interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; + interfaces.eth2.ipv4.addresses = mkOverride 0 [ ]; + interfaces.bridge.ipv4.addresses = mkOverride 0 [ { address = "192.168.1.1"; prefixLength = 24; } ]; }; }; @@ -328,7 +326,7 @@ let firewall.allowPing = true; useDHCP = true; macvlans.macvlan.interface = "eth1"; - interfaces.eth1.ip4 = mkOverride 0 [ ]; + interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; }; }; testScript = { nodes, ... }: @@ -369,9 +367,9 @@ let local = address4; dev = "eth1"; }; - interfaces.eth1.ip4 = mkOverride 0 + interfaces.eth1.ipv4.addresses = mkOverride 0 [ { address = address4; prefixLength = 24; } ]; - interfaces.sit.ip6 = mkOverride 0 + interfaces.sit.ipv6.addresses = mkOverride 0 [ { address = address6; prefixLength = 64; } ]; }; }; @@ -410,9 +408,9 @@ let id = 1; interface = "eth0"; }; - interfaces.eth0.ip4 = mkOverride 0 [ ]; - interfaces.eth1.ip4 = mkOverride 0 [ ]; - interfaces.vlan.ip4 = mkOverride 0 + interfaces.eth0.ipv4.addresses = mkOverride 0 [ ]; + interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; + interfaces.vlan.ipv4.addresses = mkOverride 0 [ { inherit address; prefixLength = 24; } ]; }; }; @@ -437,13 +435,13 @@ let name = "Virtual"; machine = { networking.interfaces."tap0" = { - ip4 = [ { address = "192.168.1.1"; prefixLength = 24; } ]; - ip6 = [ { address = "2001:1470:fffd:2096::"; prefixLength = 64; } ]; + ipv4.addresses = [ { address = "192.168.1.1"; prefixLength = 24; } ]; + ipv6.addresses = [ { address = "2001:1470:fffd:2096::"; prefixLength = 64; } ]; virtual = true; }; networking.interfaces."tun0" = { - ip4 = [ { address = "192.168.1.2"; prefixLength = 24; } ]; - ip6 = [ { address = "2001:1470:fffd:2097::"; prefixLength = 64; } ]; + ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ]; + ipv6.addresses = [ { address = "2001:1470:fffd:2097::"; prefixLength = 64; } ]; virtual = true; }; }; @@ -476,6 +474,126 @@ let ); ''; }; + privacy = { + name = "Privacy"; + nodes.router = { config, pkgs, ... }: { + virtualisation.vlans = [ 1 ]; + boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = true; + networking = { + useNetworkd = networkd; + interfaces.eth1.ipv6.addresses = singleton { + address = "fd00:1234:5678:1::1"; + prefixLength = 64; + }; + }; + services.radvd = { + enable = true; + config = '' + interface eth1 { + AdvSendAdvert on; + AdvManagedFlag on; + AdvOtherConfigFlag on; + + prefix fd00:1234:5678:1::/64 { + AdvAutonomous on; + AdvOnLink on; + }; + }; + ''; + }; + }; + nodes.client = { config, pkgs, ... }: with pkgs.lib; { + virtualisation.vlans = [ 1 ]; + networking = { + useNetworkd = networkd; + useDHCP = true; + interfaces.eth1 = { + preferTempAddress = true; + ipv4.addresses = mkOverride 0 [ ]; + ipv6.addresses = mkOverride 0 [ ]; + }; + }; + }; + testScript = { nodes, ... }: + '' + startAll; + + $client->waitForUnit("network.target"); + $router->waitForUnit("network-online.target"); + + # Wait until we have an ip address + $client->waitUntilSucceeds("ip addr show dev eth1 | grep -q 'fd00:1234:5678:1:'"); + + # Test vlan 1 + $client->waitUntilSucceeds("ping -c 1 fd00:1234:5678:1::1"); + + # Test address used is temporary + $client->waitUntilSucceeds("! ip route get fd00:1234:5678:1::1 | grep -q ':[a-f0-9]*ff:fe[a-f0-9]*:'"); + ''; + }; + routes = { + name = "routes"; + machine = { + networking.useDHCP = false; + networking.interfaces."eth0" = { + ipv4.addresses = [ { address = "192.168.1.2"; prefixLength = 24; } ]; + ipv6.addresses = [ { address = "2001:1470:fffd:2097::"; prefixLength = 64; } ]; + ipv6.routes = [ + { address = "fdfd:b3f0::"; prefixLength = 48; } + { address = "2001:1470:fffd:2098::"; prefixLength = 64; via = "fdfd:b3f0::1"; } + ]; + ipv4.routes = [ + { address = "10.0.0.0"; prefixLength = 16; options = { mtu = "1500"; }; } + { address = "192.168.2.0"; prefixLength = 24; via = "192.168.1.1"; } + ]; + }; + virtualisation.vlans = [ ]; + }; + + testScript = '' + my $targetIPv4Table = <<'END'; + 10.0.0.0/16 scope link mtu 1500 + 192.168.1.0/24 proto kernel scope link src 192.168.1.2 + 192.168.2.0/24 via 192.168.1.1 + END + + my $targetIPv6Table = <<'END'; + 2001:1470:fffd:2097::/64 proto kernel metric 256 pref medium + 2001:1470:fffd:2098::/64 via fdfd:b3f0::1 metric 1024 pref medium + fdfd:b3f0::/48 metric 1024 pref medium + END + + $machine->start; + $machine->waitForUnit("network.target"); + + # test routing tables + my $ipv4Table = $machine->succeed("ip -4 route list dev eth0 | head -n3"); + my $ipv6Table = $machine->succeed("ip -6 route list dev eth0 | head -n3"); + "$ipv4Table" eq "$targetIPv4Table" or die( + "The IPv4 routing table does not match the expected one:\n", + "Result:\n", "$ipv4Table\n", + "Expected:\n", "$targetIPv4Table\n" + ); + "$ipv6Table" eq "$targetIPv6Table" or die( + "The IPv6 routing table does not match the expected one:\n", + "Result:\n", "$ipv6Table\n", + "Expected:\n", "$targetIPv6Table\n" + ); + + # test clean-up of the tables + $machine->succeed("systemctl stop network-addresses-eth0"); + my $ipv4Residue = $machine->succeed("ip -4 route list dev eth0 | head -n-3"); + my $ipv6Residue = $machine->succeed("ip -6 route list dev eth0 | head -n-3"); + $ipv4Residue eq "" or die( + "The IPv4 routing table has not been properly cleaned:\n", + "$ipv4Residue\n" + ); + $ipv6Residue eq "" or die( + "The IPv6 routing table has not been properly cleaned:\n", + "$ipv6Residue\n" + ); + ''; + }; }; in mapAttrs (const (attrs: makeTest (attrs // { diff --git a/nixos/tests/novacomd.nix b/nixos/tests/novacomd.nix new file mode 100644 index 000000000000..21b86f6dae27 --- /dev/null +++ b/nixos/tests/novacomd.nix @@ -0,0 +1,28 @@ +import ./make-test.nix ({ pkgs, ...} : { + name = "novacomd"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ dtzWill ]; + }; + + machine = { config, pkgs, ... }: { + services.novacomd.enable = true; + }; + + testScript = '' + startAll; + + $machine->waitForUnit("novacomd.service"); + + # Check status and try connecting with novacom + $machine->succeed("systemctl status novacomd.service >&2"); + $machine->succeed("novacom -l"); + + # Stop the daemon, double-check novacom fails if daemon isn't working + $machine->stopJob("novacomd"); + $machine->fail("novacom -l"); + + # And back again for good measure + $machine->startJob("novacomd"); + $machine->succeed("novacom -l"); + ''; +}) diff --git a/nixos/tests/nsd.nix b/nixos/tests/nsd.nix index 0b1082056f6f..ad4d4f822435 100644 --- a/nixos/tests/nsd.nix +++ b/nixos/tests/nsd.nix @@ -15,25 +15,31 @@ in import ./make-test.nix ({ pkgs, ...} : { clientv4 = { lib, nodes, ... }: { imports = [ common ]; networking.nameservers = lib.mkForce [ - nodes.server.config.networking.interfaces.eth1.ipAddress + (lib.head nodes.server.config.networking.interfaces.eth1.ipv4.addresses).address + ]; + networking.interfaces.eth1.ipv4.addresses = [ + { address = "192.168.0.2"; prefixLength = 24; } ]; - networking.interfaces.eth1.ipAddress = "192.168.0.2"; - networking.interfaces.eth1.prefixLength = 24; }; clientv6 = { lib, nodes, ... }: { imports = [ common ]; networking.nameservers = lib.mkForce [ - nodes.server.config.networking.interfaces.eth1.ipv6Address + (lib.head nodes.server.config.networking.interfaces.eth1.ipv6.addresses).address + ]; + networking.interfaces.eth1.ipv4.addresses = [ + { address = "dead:beef::2"; prefixLength = 24; } ]; - networking.interfaces.eth1.ipv6Address = "dead:beef::2"; }; server = { lib, ... }: { imports = [ common ]; - networking.interfaces.eth1.ipAddress = "192.168.0.1"; - networking.interfaces.eth1.prefixLength = 24; - networking.interfaces.eth1.ipv6Address = "dead:beef::1"; + networking.interfaces.eth1.ipv4.addresses = [ + { address = "192.168.0.1"; prefixLength = 24; } + ]; + networking.interfaces.eth1.ipv6.addresses = [ + { address = "dead:beef::1"; prefixLength = 64; } + ]; services.nsd.enable = true; services.nsd.interfaces = lib.mkForce []; services.nsd.zones."example.com.".data = '' diff --git a/nixos/tests/plotinus.nix b/nixos/tests/plotinus.nix new file mode 100644 index 000000000000..557d65f7960a --- /dev/null +++ b/nixos/tests/plotinus.nix @@ -0,0 +1,27 @@ +import ./make-test.nix ({ pkgs, ... }: { + name = "plotinus"; + meta = { + maintainers = pkgs.plotinus.meta.maintainers; + }; + + machine = + { config, pkgs, ... }: + + { imports = [ ./common/x11.nix ]; + programs.plotinus.enable = true; + environment.systemPackages = [ pkgs.gnome3.gnome-calculator pkgs.xdotool ]; + }; + + testScript = + '' + $machine->waitForX; + $machine->execute("xterm -e 'gnome-calculator' &"); + $machine->waitForWindow(qr/Calculator/); + $machine->execute("xdotool key ctrl+shift+p"); + $machine->sleep(1); # wait for the popup + $machine->execute("xdotool key p r e f e r e n c e s Return"); + $machine->waitForWindow(qr/Preferences/); + $machine->screenshot("screen"); + ''; + +}) diff --git a/nixos/tests/powerdns.nix b/nixos/tests/powerdns.nix new file mode 100644 index 000000000000..0d5b0f715f52 --- /dev/null +++ b/nixos/tests/powerdns.nix @@ -0,0 +1,12 @@ +import ./make-test.nix ({ pkgs, ... }: { + name = "powerdns"; + + nodes.server = { config, pkgs, ... }: { + services.powerdns.enable = true; + }; + + testScript = '' + $server->waitForUnit("pdns"); + $server->succeed("${pkgs.dnsutils}/bin/dig version.bind txt chaos \@127.0.0.1"); + ''; +}) diff --git a/nixos/tests/predictable-interface-names.nix b/nixos/tests/predictable-interface-names.nix new file mode 100644 index 000000000000..b4c2039923cf --- /dev/null +++ b/nixos/tests/predictable-interface-names.nix @@ -0,0 +1,27 @@ +{ system ? builtins.currentSystem +, pkgs ? import ../.. { inherit system; } +}: +with import ../lib/testing.nix { inherit system; }; +let boolToString = x: if x then "yes" else "no"; in +let testWhenSetTo = predictable: withNetworkd: +makeTest { + name = "${if predictable then "" else "un"}predictableInterfaceNames${if withNetworkd then "-with-networkd" else ""}"; + meta = {}; + + machine = { config, pkgs, ... }: { + networking.usePredictableInterfaceNames = pkgs.stdenv.lib.mkForce predictable; + networking.useNetworkd = withNetworkd; + networking.dhcpcd.enable = !withNetworkd; + }; + + testScript = '' + print $machine->succeed("ip link"); + $machine->succeed("ip link show ${if predictable then "ens3" else "eth0"}"); + $machine->fail("ip link show ${if predictable then "eth0" else "ens3"}"); + ''; +}; in +with pkgs.stdenv.lib.lists; +with pkgs.stdenv.lib.attrsets; +listToAttrs (map (drv: nameValuePair drv.name drv) ( +crossLists testWhenSetTo [[true false] [true false]] +)) diff --git a/nixos/tests/quagga.nix b/nixos/tests/quagga.nix index b9644b4768c0..613180942c41 100644 --- a/nixos/tests/quagga.nix +++ b/nixos/tests/quagga.nix @@ -8,7 +8,7 @@ import ./make-test.nix ({ pkgs, ... }: let - ifAddr = node: iface: (pkgs.lib.head node.config.networking.interfaces.${iface}.ip4).address; + ifAddr = node: iface: (pkgs.lib.head node.config.networking.interfaces.${iface}.ipv4.addresses).address; ospfConf = '' interface eth2 diff --git a/nixos/tests/rspamd.nix b/nixos/tests/rspamd.nix new file mode 100644 index 000000000000..6b2e2dd3a531 --- /dev/null +++ b/nixos/tests/rspamd.nix @@ -0,0 +1,140 @@ +{ system ? builtins.currentSystem }: +with import ../lib/testing.nix { inherit system; }; +with pkgs.lib; +let + initMachine = '' + startAll + $machine->waitForUnit("rspamd.service"); + $machine->succeed("id \"rspamd\" >/dev/null"); + ''; + checkSocket = socket: user: group: mode: '' + $machine->succeed("ls ${socket} >/dev/null"); + $machine->succeed("[[ \"\$(stat -c %U ${socket})\" == \"${user}\" ]]"); + $machine->succeed("[[ \"\$(stat -c %G ${socket})\" == \"${group}\" ]]"); + $machine->succeed("[[ \"\$(stat -c %a ${socket})\" == \"${mode}\" ]]"); + ''; + simple = name: socketActivation: enableIPv6: makeTest { + name = "rspamd-${name}"; + machine = { + services.rspamd = { + enable = true; + socketActivation = socketActivation; + }; + networking.enableIPv6 = enableIPv6; + }; + testScript = '' + startAll + $machine->waitForUnit("multi-user.target"); + $machine->waitForOpenPort(11334); + $machine->waitForUnit("rspamd.service"); + $machine->succeed("id \"rspamd\" >/dev/null"); + ${checkSocket "/run/rspamd/rspamd.sock" "rspamd" "rspamd" "660" } + sleep 10; + $machine->log($machine->succeed("cat /etc/rspamd.conf")); + $machine->log($machine->succeed("systemctl cat rspamd.service")); + ${if socketActivation then '' + $machine->log($machine->succeed("systemctl cat rspamd-controller-1.socket")); + $machine->log($machine->succeed("systemctl cat rspamd-normal-1.socket")); + '' else '' + $machine->fail("systemctl cat rspamd-controller-1.socket"); + $machine->fail("systemctl cat rspamd-normal-1.socket"); + ''} + $machine->log($machine->succeed("curl http://localhost:11334/auth")); + $machine->log($machine->succeed("curl http://127.0.0.1:11334/auth")); + ${optionalString enableIPv6 '' + $machine->log($machine->succeed("curl http://[::1]:11334/auth")); + ''} + ''; + }; +in +{ + simple = simple "simple" false true; + ipv4only = simple "ipv4only" false false; + simple-socketActivated = simple "simple-socketActivated" true true; + ipv4only-socketActivated = simple "ipv4only-socketActivated" true false; + deprecated = makeTest { + name = "rspamd-deprecated"; + machine = { + services.rspamd = { + enable = true; + bindSocket = [ "/run/rspamd.sock mode=0600 user=root group=root" ]; + bindUISocket = [ "/run/rspamd-worker.sock mode=0666 user=root group=root" ]; + }; + }; + + testScript = '' + ${initMachine} + $machine->waitForFile("/run/rspamd.sock"); + ${checkSocket "/run/rspamd.sock" "root" "root" "600" } + ${checkSocket "/run/rspamd-worker.sock" "root" "root" "666" } + $machine->log($machine->succeed("cat /etc/rspamd.conf")); + $machine->fail("systemctl cat rspamd-normal-1.socket"); + $machine->log($machine->succeed("rspamc -h /run/rspamd-worker.sock stat")); + $machine->log($machine->succeed("curl --unix-socket /run/rspamd-worker.sock http://localhost/ping")); + ''; + }; + + bindports = makeTest { + name = "rspamd-bindports"; + machine = { + services.rspamd = { + enable = true; + socketActivation = false; + workers.normal.bindSockets = [{ + socket = "/run/rspamd.sock"; + mode = "0600"; + owner = "root"; + group = "root"; + }]; + workers.controller.bindSockets = [{ + socket = "/run/rspamd-worker.sock"; + mode = "0666"; + owner = "root"; + group = "root"; + }]; + }; + }; + + testScript = '' + ${initMachine} + $machine->waitForFile("/run/rspamd.sock"); + ${checkSocket "/run/rspamd.sock" "root" "root" "600" } + ${checkSocket "/run/rspamd-worker.sock" "root" "root" "666" } + $machine->log($machine->succeed("cat /etc/rspamd.conf")); + $machine->fail("systemctl cat rspamd-normal-1.socket"); + $machine->log($machine->succeed("rspamc -h /run/rspamd-worker.sock stat")); + $machine->log($machine->succeed("curl --unix-socket /run/rspamd-worker.sock http://localhost/ping")); + ''; + }; + socketActivated = makeTest { + name = "rspamd-socketActivated"; + machine = { + services.rspamd = { + enable = true; + workers.normal.bindSockets = [{ + socket = "/run/rspamd.sock"; + mode = "0600"; + owner = "root"; + group = "root"; + }]; + workers.controller.bindSockets = [{ + socket = "/run/rspamd-worker.sock"; + mode = "0666"; + owner = "root"; + group = "root"; + }]; + }; + }; + + testScript = '' + startAll + $machine->waitForFile("/run/rspamd.sock"); + ${checkSocket "/run/rspamd.sock" "root" "root" "600" } + ${checkSocket "/run/rspamd-worker.sock" "root" "root" "666" } + $machine->log($machine->succeed("cat /etc/rspamd.conf")); + $machine->log($machine->succeed("systemctl cat rspamd-normal-1.socket")); + $machine->log($machine->succeed("rspamc -h /run/rspamd-worker.sock stat")); + $machine->log($machine->succeed("curl --unix-socket /run/rspamd-worker.sock http://localhost/ping")); + ''; + }; +} diff --git a/nixos/tests/rxe.nix b/nixos/tests/rxe.nix new file mode 100644 index 000000000000..cfe64a75a635 --- /dev/null +++ b/nixos/tests/rxe.nix @@ -0,0 +1,53 @@ +import ./make-test.nix ({ pkgs, ... } : + +let + node = { config, pkgs, lib, ... } : { + networking = { + firewall = { + allowedUDPPorts = [ 4791 ]; # open RoCE port + allowedTCPPorts = [ 4800 ]; # port for test utils + }; + rxe = { + enable = true; + interfaces = [ "eth1" ]; + }; + }; + + environment.systemPackages = with pkgs; [ rdma-core screen ]; + }; + +in { + name = "rxe"; + + nodes = { + server = node; + client = node; + }; + + testScript = '' + # Test if rxe interface comes up + $server->waitForUnit("default.target"); + $server->succeed("systemctl status rxe.service"); + $server->succeed("ibv_devices | grep rxe0"); + + $client->waitForUnit("default.target"); + + # ping pong test + $server->succeed("screen -dmS rc_pingpong ibv_rc_pingpong -p 4800 -g0"); + $client->succeed("sleep 2; ibv_rc_pingpong -p 4800 -g0 server"); + + $server->succeed("screen -dmS uc_pingpong ibv_uc_pingpong -p 4800 -g0"); + $client->succeed("sleep 2; ibv_uc_pingpong -p 4800 -g0 server"); + + $server->succeed("screen -dmS ud_pingpong ibv_ud_pingpong -p 4800 -s 1024 -g0"); + $client->succeed("sleep 2; ibv_ud_pingpong -p 4800 -s 1024 -g0 server"); + + $server->succeed("screen -dmS srq_pingpong ibv_srq_pingpong -p 4800 -g0"); + $client->succeed("sleep 2; ibv_srq_pingpong -p 4800 -g0 server"); + + $server->succeed("screen -dmS rping rping -s -a server -C 10"); + $client->succeed("sleep 2; rping -c -a server -C 10"); + ''; +}) + + diff --git a/nixos/tests/yabar.nix b/nixos/tests/yabar.nix new file mode 100644 index 000000000000..40ca91e8064d --- /dev/null +++ b/nixos/tests/yabar.nix @@ -0,0 +1,25 @@ +import ./make-test.nix ({ pkgs, lib }: + +with lib; + +{ + name = "yabar"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ ma27 ]; + }; + + nodes.yabar = { + imports = [ ./common/x11.nix ./common/user-account.nix ]; + + services.xserver.displayManager.auto.user = "bob"; + + programs.yabar.enable = true; + }; + + testScript = '' + $yabar->start; + $yabar->waitForX; + + $yabar->waitForUnit("yabar.service", "bob"); + ''; +}) |