diff options
author | John Ericson <John.Ericson@Obsidian.Systems> | 2018-11-01 16:47:42 -0400 |
---|---|---|
committer | John Ericson <John.Ericson@Obsidian.Systems> | 2018-11-01 16:47:42 -0400 |
commit | e3082c313b75f13e8e1049673efe6a42dcd1499f (patch) | |
tree | 0d11815c9bed24ca9f27d3839ac0f9577d8308e5 /nixos | |
parent | f2ed7c7af9f5b2db5e88b78e192b470c47f4c4fd (diff) | |
parent | cc41aefe4485dea399930b8d173c26e438cb5e22 (diff) | |
download | nixlib-e3082c313b75f13e8e1049673efe6a42dcd1499f.tar nixlib-e3082c313b75f13e8e1049673efe6a42dcd1499f.tar.gz nixlib-e3082c313b75f13e8e1049673efe6a42dcd1499f.tar.bz2 nixlib-e3082c313b75f13e8e1049673efe6a42dcd1499f.tar.lz nixlib-e3082c313b75f13e8e1049673efe6a42dcd1499f.tar.xz nixlib-e3082c313b75f13e8e1049673efe6a42dcd1499f.tar.zst nixlib-e3082c313b75f13e8e1049673efe6a42dcd1499f.zip |
Merge remote-tracking branch 'upstream/master' into release-lib-cleanup
Diffstat (limited to 'nixos')
287 files changed, 11170 insertions, 4256 deletions
diff --git a/nixos/doc/manual/Makefile b/nixos/doc/manual/Makefile index 2e9adf70c396..b251a1f5e2c3 100644 --- a/nixos/doc/manual/Makefile +++ b/nixos/doc/manual/Makefile @@ -4,7 +4,7 @@ all: manual-combined.xml format .PHONY: debug debug: generated manual-combined.xml -manual-combined.xml: generated *.xml +manual-combined.xml: generated *.xml **/*.xml rm -f ./manual-combined.xml nix-shell --packages xmloscopy \ --run "xmloscopy --docbook5 ./manual.xml ./manual-combined.xml" diff --git a/nixos/doc/manual/administration/container-networking.xml b/nixos/doc/manual/administration/container-networking.xml index 4b977d1d82eb..2ee8bfdd50f1 100644 --- a/nixos/doc/manual/administration/container-networking.xml +++ b/nixos/doc/manual/administration/container-networking.xml @@ -52,4 +52,8 @@ $ ping -c1 10.233.4.2 networking.networkmanager.unmanaged = [ "interface-name:ve-*" ]; </programlisting> </para> + + <para> + You may need to restart your system for the changes to take effect. + </para> </section> diff --git a/nixos/doc/manual/administration/declarative-containers.xml b/nixos/doc/manual/administration/declarative-containers.xml index 2a98fb126231..d03dbc4d7055 100644 --- a/nixos/doc/manual/administration/declarative-containers.xml +++ b/nixos/doc/manual/administration/declarative-containers.xml @@ -15,7 +15,7 @@ containers.database = { config = { config, pkgs, ... }: { <xref linkend="opt-services.postgresql.enable"/> = true; - <xref linkend="opt-services.postgresql.package"/> = pkgs.postgresql96; + <xref linkend="opt-services.postgresql.package"/> = pkgs.postgresql_9_6; }; }; </programlisting> diff --git a/nixos/doc/manual/configuration/config-file.xml b/nixos/doc/manual/configuration/config-file.xml index 8a1a39c98c10..c77cfe137baa 100644 --- a/nixos/doc/manual/configuration/config-file.xml +++ b/nixos/doc/manual/configuration/config-file.xml @@ -197,10 +197,10 @@ swapDevices = [ { device = "/dev/disk/by-label/swap"; } ]; pkgs.emacs ]; -<xref linkend="opt-services.postgresql.package"/> = pkgs.postgresql90; +<xref linkend="opt-services.postgresql.package"/> = pkgs.postgresql_10; </programlisting> The latter option definition changes the default PostgreSQL package used - by NixOS’s PostgreSQL service to 9.0. For more information on packages, + by NixOS’s PostgreSQL service to 10.x. For more information on packages, including how to add new ones, see <xref linkend="sec-custom-packages"/>. </para> </listitem> diff --git a/nixos/doc/manual/configuration/firewall.xml b/nixos/doc/manual/configuration/firewall.xml index b66adcedce6e..47a19ac82c0f 100644 --- a/nixos/doc/manual/configuration/firewall.xml +++ b/nixos/doc/manual/configuration/firewall.xml @@ -34,13 +34,4 @@ Similarly, UDP port ranges can be opened through <xref linkend="opt-networking.firewall.allowedUDPPortRanges"/>. </para> - - <para> - Also of interest is -<programlisting> -<xref linkend="opt-networking.firewall.allowPing"/> = true; -</programlisting> - to allow the machine to respond to ping requests. (ICMPv6 pings are always - allowed.) - </para> </section> diff --git a/nixos/doc/manual/configuration/linux-kernel.xml b/nixos/doc/manual/configuration/linux-kernel.xml index 2f766f2b32f7..644d3a33ffd2 100644 --- a/nixos/doc/manual/configuration/linux-kernel.xml +++ b/nixos/doc/manual/configuration/linux-kernel.xml @@ -84,18 +84,17 @@ nixpkgs.config.packageOverrides = pkgs: allowImportFromDerivation = true; }; ]]></screen> - -You can edit the config with this snippet (by default <command>make menuconfig</command> won't work - out of the box on nixos): - <screen><![CDATA[ + You can edit the config with this snippet (by default <command>make + menuconfig</command> won't work out of the box on nixos): +<screen><![CDATA[ nix-shell -E 'with import <nixpkgs> {}; kernelToOverride.overrideAttrs (o: {nativeBuildInputs=o.nativeBuildInputs ++ [ pkgconfig ncurses ];})' ]]></screen> - - - or you can let nixpkgs generate the configuration. - Nixpkgs generates it via answering the interactive kernel utility <command>make config</command>. - The answers depend on parameters passed to <filename>pkgs/os-specific/linux/kernel/generic.nix</filename> - (which you can influence by overriding <literal>extraConfig, autoModules, modDirVersion, preferBuiltin, extraConfig</literal>). + or you can let nixpkgs generate the configuration. Nixpkgs generates it via + answering the interactive kernel utility <command>make config</command>. The + answers depend on parameters passed to + <filename>pkgs/os-specific/linux/kernel/generic.nix</filename> (which you + can influence by overriding <literal>extraConfig, autoModules, + modDirVersion, preferBuiltin, extraConfig</literal>). <screen><![CDATA[ mptcp93.override ({ diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix index be28c2c17afd..faae4f205443 100644 --- a/nixos/doc/manual/default.nix +++ b/nixos/doc/manual/default.nix @@ -90,7 +90,9 @@ let fi ${buildPackages.libxslt.bin}/bin/xsltproc \ --stringparam revision '${revision}' \ - -o $out ${./options-to-docbook.xsl} $optionsXML + -o intermediate.xml ${./options-to-docbook.xsl} $optionsXML + ${buildPackages.libxslt.bin}/bin/xsltproc \ + -o "$out" ${./postprocess-option-descriptions.xsl} intermediate.xml ''; sources = lib.sourceFilesBySuffices ./. [".xml"]; @@ -250,7 +252,7 @@ in rec { ''; # */ # Generate the NixOS manual. - manual = runCommand "nixos-manual" + manualHTML = runCommand "nixos-manual-html" { inherit sources; nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ]; meta.description = "The NixOS manual in HTML format"; @@ -279,6 +281,11 @@ in rec { echo "doc manual $dst" >> $out/nix-support/hydra-build-products ''; # */ + # Alias for backward compatibility. TODO(@oxij): remove eventually. + manual = manualHTML; + + # Index page of the NixOS manual. + manualHTMLIndex = "${manualHTML}/share/doc/nixos/index.html"; manualEpub = runCommand "nixos-manual-epub" { inherit sources; diff --git a/nixos/doc/manual/development/building-parts.xml b/nixos/doc/manual/development/building-parts.xml index eaffc0ef47c2..b4791b72970f 100644 --- a/nixos/doc/manual/development/building-parts.xml +++ b/nixos/doc/manual/development/building-parts.xml @@ -34,7 +34,7 @@ $ nix-build -A system</screen> </varlistentry> <varlistentry> <term> - <varname>system.build.manual.manual</varname> + <varname>system.build.manual.manualHTML</varname> </term> <listitem> <para> diff --git a/nixos/doc/manual/development/debugging-nixos-tests.xml b/nixos/doc/manual/development/debugging-nixos-tests.xml new file mode 100644 index 000000000000..30e58e1e3554 --- /dev/null +++ b/nixos/doc/manual/development/debugging-nixos-tests.xml @@ -0,0 +1,37 @@ +<section 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="sec-debugging-nixos-tests"> + <title>Debugging NixOS tests</title> + + <para> + Tests may fail and infrastructure offers access to inspect machine state. + </para> + + <para> + To prevent test from stopping and cleaning up, insert a sleep command: + </para> + +<programlisting> +$machine->succeed("sleep 84000"); +</programlisting> + + <para> + As soon as machine starts run as root: + </para> + +<programlisting> +nix-shell -p socat --run "socat STDIO,raw,echo=0,escape=0x11 UNIX:/tmp/nix-build-vm-test-run-*.drv-0/vm-state-machine/backdoor" +</programlisting> + + <para> + You may need to find the correct path, replacing <literal>/tmp</literal>, + <literal>*</literal> or <literal>machine</literal>. + </para> + + <para> + Press "enter" to open up console and login as "root". After you're done, + press "ctrl-q" to exit the console. + </para> +</section> diff --git a/nixos/doc/manual/development/nixos-tests.xml b/nixos/doc/manual/development/nixos-tests.xml index 2695082e3867..d068887200a9 100644 --- a/nixos/doc/manual/development/nixos-tests.xml +++ b/nixos/doc/manual/development/nixos-tests.xml @@ -16,4 +16,5 @@ xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/tests">nixos/test <xi:include href="writing-nixos-tests.xml" /> <xi:include href="running-nixos-tests.xml" /> <xi:include href="running-nixos-tests-interactively.xml" /> + <xi:include href="debugging-nixos-tests.xml" /> </chapter> diff --git a/nixos/doc/manual/development/running-nixos-tests-interactively.xml b/nixos/doc/manual/development/running-nixos-tests-interactively.xml index 862b364a6d79..b25d3dcb9116 100644 --- a/nixos/doc/manual/development/running-nixos-tests-interactively.xml +++ b/nixos/doc/manual/development/running-nixos-tests-interactively.xml @@ -19,6 +19,7 @@ starting VDE switch for network 1 > startAll > testScript > $machine->succeed("touch /tmp/foo") +> print($machine->succeed("pwd"), "\n") # Show stdout of command </screen> The function <command>testScript</command> executes the entire test script and drops you back into the test driver command line upon its completion. @@ -33,8 +34,11 @@ $ nix-build nixos/tests/login.nix -A driver $ ./result/bin/nixos-run-vms </screen> The script <command>nixos-run-vms</command> starts the virtual machines - defined by test. The root file system of the VMs is created on the fly and - kept across VM restarts in - <filename>./</filename><varname>hostname</varname><filename>.qcow2</filename>. + defined by test. + </para> + + <para> + The machine state is kept across VM restarts in + <filename>/tmp/vm-state-</filename><varname>machinename</varname>. </para> </section> diff --git a/nixos/doc/manual/development/writing-nixos-tests.xml b/nixos/doc/manual/development/writing-nixos-tests.xml index 5935fbc049bd..983f8f9cbe3e 100644 --- a/nixos/doc/manual/development/writing-nixos-tests.xml +++ b/nixos/doc/manual/development/writing-nixos-tests.xml @@ -108,7 +108,7 @@ xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualis <programlisting> $machine->start; $machine->waitForUnit("default.target"); -$machine->succeed("uname") =~ /Linux/; +die unless $machine->succeed("uname") =~ /Linux/; </programlisting> The first line is actually unnecessary; machines are implicitly started when you first execute an action on them (such as <literal>waitForUnit</literal> diff --git a/nixos/doc/manual/installation/installing-behind-a-proxy.xml b/nixos/doc/manual/installation/installing-behind-a-proxy.xml index c59d073c61c7..8f9baff44b51 100644 --- a/nixos/doc/manual/installation/installing-behind-a-proxy.xml +++ b/nixos/doc/manual/installation/installing-behind-a-proxy.xml @@ -5,28 +5,29 @@ xml:id="sec-installing-behind-proxy"> <title>Installing behind a proxy</title> -<para> + <para> To install NixOS behind a proxy, do the following before running <literal>nixos-install</literal>. -</para> -<orderedlist numeration="arabic"> + </para> + + <orderedlist numeration="arabic"> <listitem> - <para> - Update proxy configuration in - <literal>/mnt/etc/nixos/configuration.nix</literal> to keep the - internet accessible after reboot. - </para> - <programlisting> + <para> + Update proxy configuration in + <literal>/mnt/etc/nixos/configuration.nix</literal> to keep the internet + accessible after reboot. + </para> +<programlisting> networking.proxy.default = "http://user:password@proxy:port/"; networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; </programlisting> </listitem> <listitem> - <para> - Setup the proxy environment variables in the shell where you are - running <literal>nixos-install</literal>. - </para> - <programlisting> + <para> + Setup the proxy environment variables in the shell where you are running + <literal>nixos-install</literal>. + </para> +<programlisting> # proxy_url="http://user:password@proxy:port/" # export http_proxy="$proxy_url" # export HTTP_PROXY="$proxy_url" @@ -34,14 +35,14 @@ networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; # export HTTPS_PROXY="$proxy_url" </programlisting> </listitem> -</orderedlist> + </orderedlist> -<note> -<para> - If you are switching networks with different proxy configurations, use the - <literal>nesting.clone</literal> option in - <literal>configuration.nix</literal> to switch proxies at runtime. - Refer to <xref linkend="ch-options" /> for more information. -</para> -</note> + <note> + <para> + If you are switching networks with different proxy configurations, use the + <literal>nesting.clone</literal> option in + <literal>configuration.nix</literal> to switch proxies at runtime. Refer to + <xref linkend="ch-options" /> for more information. + </para> + </note> </section> diff --git a/nixos/doc/manual/installation/installing-usb.xml b/nixos/doc/manual/installation/installing-usb.xml index c5934111749c..0b311189430c 100644 --- a/nixos/doc/manual/installation/installing-usb.xml +++ b/nixos/doc/manual/installation/installing-usb.xml @@ -9,13 +9,12 @@ For systems without CD drive, the NixOS live CD can be booted from a USB stick. You can use the <command>dd</command> utility to write the image: <command>dd if=<replaceable>path-to-image</replaceable> - of=<replaceable>/dev/sdb</replaceable></command>. Be careful about specifying + of=<replaceable>/dev/sdX</replaceable></command>. Be careful about specifying the correct drive; you can use the <command>lsblk</command> command to get a list of block devices. - </para> - - <para> - On macOS: + <note> + <title>On macOS</title> + <para> <programlisting> $ diskutil list [..] @@ -26,43 +25,16 @@ $ diskutil unmountDisk diskN Unmount of all volumes on diskN was successful $ sudo dd bs=1m if=nix.iso of=/dev/rdiskN </programlisting> - Using the 'raw' <command>rdiskN</command> device instead of - <command>diskN</command> completes in minutes instead of hours. After - <command>dd</command> completes, a GUI dialog "The disk you inserted was not - readable by this computer" will pop up, which can be ignored. + Using the 'raw' <command>rdiskN</command> device instead of + <command>diskN</command> completes in minutes instead of hours. After + <command>dd</command> completes, a GUI dialog "The disk you inserted was + not readable by this computer" will pop up, which can be ignored. + </para> + </note> </para> <para> The <command>dd</command> utility will write the image verbatim to the drive, making it the recommended option for both UEFI and non-UEFI installations. - For non-UEFI installations, you can alternatively use - <link xlink:href="http://unetbootin.sourceforge.net/">unetbootin</link>. If - you cannot use <command>dd</command> for a UEFI installation, you can also - mount the ISO, copy its contents verbatim to your drive, then either: - <itemizedlist> - <listitem> - <para> - Change the label of the disk partition to the label of the ISO (visible - with the blkid command), or - </para> - </listitem> - <listitem> - <para> - Edit <filename>loader/entries/nixos-livecd.conf</filename> on the drive - and change the <literal>root=</literal> field in the - <literal>options</literal> line to point to your drive (see the - documentation on <literal>root=</literal> in - <link xlink:href="https://www.kernel.org/doc/Documentation/admin-guide/kernel-parameters.txt"> - the kernel documentation</link> for more details). - </para> - </listitem> - <listitem> - <para> - If you want to load the contents of the ISO to ram after bootin (So you - can remove the stick after bootup) you can append the parameter - <literal>copytoram</literal> to the <literal>options</literal> field. - </para> - </listitem> - </itemizedlist> </para> </section> diff --git a/nixos/doc/manual/installation/installing.xml b/nixos/doc/manual/installation/installing.xml index 916384559e24..8e94f946c5ee 100644 --- a/nixos/doc/manual/installation/installing.xml +++ b/nixos/doc/manual/installation/installing.xml @@ -4,60 +4,46 @@ version="5.0" xml:id="sec-installation"> <title>Installing NixOS</title> - <para> - NixOS can be installed on BIOS or UEFI systems. The procedure for a UEFI - installation is by and large the same as a BIOS installation. The differences - are mentioned in the steps that follow. - </para> - <orderedlist> - <listitem> - <para> - Boot from the CD. - </para> - <variablelist> - <varlistentry> - <term> - UEFI systems - </term> - <listitem> - <para> - You should boot the live CD in UEFI mode (consult your specific - hardware's documentation for instructions). You may find the - <link xlink:href="http://www.rodsbooks.com/refind">rEFInd boot - manager</link> useful. - </para> - </listitem> - </varlistentry> - </variablelist> - </listitem> - <listitem> - <para> - The CD contains a basic NixOS installation. (It also contains Memtest86+, - useful if you want to test new hardware). When it’s finished booting, it - should have detected most of your hardware. - </para> - </listitem> - <listitem> - <para> - The NixOS manual is available on virtual console 8 (press Alt+F8 to access) - or by running <command>nixos-help</command>. - </para> - </listitem> - <listitem> - <para> - You get logged in as <literal>root</literal> (with empty password). - </para> - </listitem> - <listitem> - <para> - If you downloaded the graphical ISO image, you can run <command>systemctl - start display-manager</command> to start KDE. If you want to continue on - the terminal, you can use <command>loadkeys</command> to switch to your - preferred keyboard layout. (We even provide neo2 via <command>loadkeys de - neo</command>!) - </para> - </listitem> - <listitem> + <section xml:id="sec-installation-booting"> + <title>Booting the system</title> + + <para> + NixOS can be installed on BIOS or UEFI systems. The procedure for a UEFI + installation is by and large the same as a BIOS installation. The + differences are mentioned in the steps that follow. + </para> + + <para> + The installation media can be burned to a CD, or now more commonly, "burned" + to a USB drive (see <xref linkend="sec-booting-from-usb"/>). + </para> + + <para> + The installation media contains a basic NixOS installation. When it’s + finished booting, it should have detected most of your hardware. + </para> + + <para> + The NixOS manual is available on virtual console 8 (press Alt+F8 to access) + or by running <command>nixos-help</command>. + </para> + + <para> + You are logged-in automatically as <literal>root</literal>. (The + <literal>root</literal> user account has an empty password.) + </para> + + <para> + If you downloaded the graphical ISO image, you can run <command>systemctl + start display-manager</command> to start KDE. If you want to continue on the + terminal, you can use <command>loadkeys</command> to switch to your + preferred keyboard layout. (We even provide neo2 via <command>loadkeys de + neo</command>!) + </para> + + <section xml:id="sec-installation-booting-networking"> + <title>Networking in the installer</title> + <para> The boot process should have brought up networking (check <command>ip a</command>). Networking is necessary for the installer, since it will @@ -65,60 +51,167 @@ binaries). It’s best if you have a DHCP server on your network. Otherwise configure networking manually using <command>ifconfig</command>. </para> + <para> To manually configure the network on the graphical installer, first disable network-manager with <command>systemctl stop network-manager</command>. </para> + <para> To manually configure the wifi on the minimal installer, run <command>wpa_supplicant -B -i interface -c <(wpa_passphrase 'SSID' 'key')</command>. </para> - </listitem> - <listitem> + <para> If you would like to continue the installation from a different machine you need to activate the SSH daemon via <literal>systemctl start sshd</literal>. In order to be able to login you also need to set a password for <literal>root</literal> using <literal>passwd</literal>. </para> - </listitem> - <listitem> + </section> + </section> + <section xml:id="sec-installation-partitioning"> + <title>Partitioning and formatting</title> + + <para> + The NixOS installer doesn’t do any partitioning or formatting, so you need + to do that yourself. + </para> + + <para> + The NixOS installer ships with multiple partitioning tools. The examples + below use <command>parted</command>, but also provides + <command>fdisk</command>, <command>gdisk</command>, + <command>cfdisk</command>, and <command>cgdisk</command>. + </para> + + <para> + The recommended partition scheme differs depending if the computer uses + <emphasis>Legacy Boot</emphasis> or <emphasis>UEFI</emphasis>. + </para> + + <section xml:id="sec-installation-partitioning-UEFI"> + <title>UEFI (GPT)</title> + <para> - The NixOS installer doesn’t do any partitioning or formatting yet, so you - need to do that yourself. Use the following commands: - <itemizedlist> + Here's an example partition scheme for UEFI, using + <filename>/dev/sda</filename> as the device. + <note> + <para> + You can safely ignore <command>parted</command>'s informational message + about needing to update /etc/fstab. + </para> + </note> + </para> + + <para> + <orderedlist> <listitem> <para> - For partitioning: <command>fdisk</command>. -<screen> -# fdisk /dev/sda # <lineannotation>(or whatever device you want to install on)</lineannotation> --- for UEFI systems only -> n # <lineannotation>(create a new partition for /boot)</lineannotation> -> 3 # <lineannotation>(make it a partition number 3)</lineannotation> -> # <lineannotation>(press enter to accept the default)</lineannotation> -> +512M # <lineannotation>(the size of the UEFI boot partition)</lineannotation> -> t # <lineannotation>(change the partition type ...)</lineannotation> -> 3 # <lineannotation>(... of the boot partition ...)</lineannotation> -> 1 # <lineannotation>(... to 'UEFI System')</lineannotation> --- for BIOS or UEFI systems -> n # <lineannotation>(create a new partition for /swap)</lineannotation> -> 2 # <lineannotation>(make it a partition number 2)</lineannotation> -> # <lineannotation>(press enter to accept the default)</lineannotation> -> +8G # <lineannotation>(the size of the swap partition, set to whatever you like)</lineannotation> -> n # <lineannotation>(create a new partition for /)</lineannotation> -> 1 # <lineannotation>(make it a partition number 1)</lineannotation> -> # <lineannotation>(press enter to accept the default)</lineannotation> -> # <lineannotation>(press enter to accept the default and use the rest of the remaining space)</lineannotation> -> a # <lineannotation>(make the partition bootable)</lineannotation> -> x # <lineannotation>(enter expert mode)</lineannotation> -> f # <lineannotation>(fix up the partition ordering)</lineannotation> -> r # <lineannotation>(exit expert mode)</lineannotation> -> w # <lineannotation>(write the partition table to disk and exit)</lineannotation></screen> + Create a <emphasis>GPT</emphasis> partition table. +<screen language="commands"># parted /dev/sda -- mklabel gpt</screen> </para> </listitem> <listitem> <para> + Add the <emphasis>root</emphasis> partition. This will fill the disk + except for the end part, where the swap will live, and the space left in + front (512MiB) which will be used by the boot partition. +<screen language="commands"># parted /dev/sda -- mkpart primary 512MiB -8GiB</screen> + </para> + </listitem> + <listitem> + <para> + Next, add a <emphasis>swap</emphasis> partition. The size required will + vary according to needs, here a 8GiB one is created. +<screen language="commands"># parted /dev/sda -- mkpart primary linux-swap -8GiB 100%</screen> + <note> + <para> + The swap partition size rules are no different than for other Linux + distributions. + </para> + </note> + </para> + </listitem> + <listitem> + <para> + Finally, the <emphasis>boot</emphasis> partition. NixOS by default uses + the ESP (EFI system partition) as its <emphasis>/boot</emphasis> + partition. It uses the initially reserved 512MiB at the start of the + disk. +<screen language="commands"># parted /dev/sda -- mkpart ESP fat32 1MiB 512MiB +# parted /dev/sda -- set 3 boot on</screen> + </para> + </listitem> + </orderedlist> + </para> + + <para> + Once complete, you can follow with + <xref linkend="sec-installation-partitioning-formatting"/>. + </para> + </section> + + <section xml:id="sec-installation-partitioning-MBR"> + <title>Legacy Boot (MBR)</title> + + <para> + Here's an example partition scheme for Legacy Boot, using + <filename>/dev/sda</filename> as the device. + <note> + <para> + You can safely ignore <command>parted</command>'s informational message + about needing to update /etc/fstab. + </para> + </note> + </para> + + <para> + <orderedlist> + <listitem> + <para> + Create a <emphasis>MBR</emphasis> partition table. +<screen language="commands"># parted /dev/sda -- mklabel msdos</screen> + </para> + </listitem> + <listitem> + <para> + Add the <emphasis>root</emphasis> partition. This will fill the the disk + except for the end part, where the swap will live. +<screen language="commands"># parted /dev/sda -- mkpart primary 1MiB -8GiB</screen> + </para> + </listitem> + <listitem> + <para> + Finally, add a <emphasis>swap</emphasis> partition. The size required + will vary according to needs, here a 8GiB one is created. +<screen language="commands"># parted /dev/sda -- mkpart primary linux-swap -8GiB 100%</screen> + <note> + <para> + The swap partition size rules are no different than for other Linux + distributions. + </para> + </note> + </para> + </listitem> + </orderedlist> + </para> + + <para> + Once complete, you can follow with + <xref linkend="sec-installation-partitioning-formatting"/>. + </para> + </section> + + <section xml:id="sec-installation-partitioning-formatting"> + <title>Formatting</title> + + <para> + Use the following commands: + <itemizedlist> + <listitem> + <para> For initialising Ext4 partitions: <command>mkfs.ext4</command>. It is recommended that you assign a unique symbolic label to the file system using the option <option>-L <replaceable>label</replaceable></option>, @@ -169,242 +262,249 @@ </listitem> </itemizedlist> </para> - </listitem> - <listitem> - <para> - Mount the target file system on which NixOS should be installed on - <filename>/mnt</filename>, e.g. + </section> + </section> + <section xml:id="sec-installation-installing"> + <title>Installing</title> + + <orderedlist> + <listitem> + <para> + Mount the target file system on which NixOS should be installed on + <filename>/mnt</filename>, e.g. <screen> # mount /dev/disk/by-label/nixos /mnt </screen> - </para> - </listitem> - <listitem> - <variablelist> - <varlistentry> - <term> - UEFI systems - </term> - <listitem> - <para> - Mount the boot file system on <filename>/mnt/boot</filename>, e.g. + </para> + </listitem> + <listitem> + <variablelist> + <varlistentry> + <term> + UEFI systems + </term> + <listitem> + <para> + Mount the boot file system on <filename>/mnt/boot</filename>, e.g. <screen> # mkdir -p /mnt/boot # mount /dev/disk/by-label/boot /mnt/boot </screen> - </para> - </listitem> - </varlistentry> - </variablelist> - </listitem> - <listitem> - <para> - If your machine has a limited amount of memory, you may want to activate - swap devices now (<command>swapon - <replaceable>device</replaceable></command>). The installer (or rather, the - build actions that it may spawn) may need quite a bit of RAM, depending on - your configuration. + </para> + </listitem> + </varlistentry> + </variablelist> + </listitem> + <listitem> + <para> + If your machine has a limited amount of memory, you may want to activate + swap devices now (<command>swapon + <replaceable>device</replaceable></command>). The installer (or rather, + the build actions that it may spawn) may need quite a bit of RAM, + depending on your configuration. <screen> # swapon /dev/sda2</screen> - </para> - </listitem> - <listitem> - <para> - You now need to create a file - <filename>/mnt/etc/nixos/configuration.nix</filename> that specifies the - intended configuration of the system. This is because NixOS has a - <emphasis>declarative</emphasis> configuration model: you create or edit a - description of the desired configuration of your system, and then NixOS - takes care of making it happen. The syntax of the NixOS configuration file - is described in <xref linkend="sec-configuration-syntax"/>, while a list of - available configuration options appears in - <xref + </para> + </listitem> + <listitem> + <para> + You now need to create a file + <filename>/mnt/etc/nixos/configuration.nix</filename> that specifies the + intended configuration of the system. This is because NixOS has a + <emphasis>declarative</emphasis> configuration model: you create or edit a + description of the desired configuration of your system, and then NixOS + takes care of making it happen. The syntax of the NixOS configuration file + is described in <xref linkend="sec-configuration-syntax"/>, while a list + of available configuration options appears in + <xref linkend="ch-options"/>. A minimal example is shown in - <xref + <xref linkend="ex-config"/>. - </para> - <para> - The command <command>nixos-generate-config</command> can generate an - initial configuration file for you: + </para> + <para> + The command <command>nixos-generate-config</command> can generate an + initial configuration file for you: <screen> # nixos-generate-config --root /mnt</screen> - You should then edit <filename>/mnt/etc/nixos/configuration.nix</filename> - to suit your needs: + You should then edit <filename>/mnt/etc/nixos/configuration.nix</filename> + to suit your needs: <screen> # nano /mnt/etc/nixos/configuration.nix </screen> - If you’re using the graphical ISO image, other editors may be available - (such as <command>vim</command>). If you have network access, you can also - install other editors — for instance, you can install Emacs by running - <literal>nix-env -i emacs</literal>. - </para> - <variablelist> - <varlistentry> - <term> - BIOS systems - </term> - <listitem> - <para> - You <emphasis>must</emphasis> set the option - <xref linkend="opt-boot.loader.grub.device"/> to specify on which disk - the GRUB boot loader is to be installed. Without it, NixOS cannot boot. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term> - UEFI systems - </term> - <listitem> - <para> - You <emphasis>must</emphasis> set the option - <xref linkend="opt-boot.loader.systemd-boot.enable"/> to - <literal>true</literal>. <command>nixos-generate-config</command> should - do this automatically for new configurations when booted in UEFI mode. - </para> - <para> - You may want to look at the options starting with - <option><link linkend="opt-boot.loader.efi.canTouchEfiVariables">boot.loader.efi</link></option> - and - <option><link linkend="opt-boot.loader.systemd-boot.enable">boot.loader.systemd</link></option> - as well. - </para> - </listitem> - </varlistentry> - </variablelist> - <para> - If there are other operating systems running on the machine before - installing NixOS, the <xref linkend="opt-boot.loader.grub.useOSProber"/> - option can be set to <literal>true</literal> to automatically add them to - the grub menu. - </para> - <para> - Another critical option is <option>fileSystems</option>, specifying the - file systems that need to be mounted by NixOS. However, you typically - don’t need to set it yourself, because - <command>nixos-generate-config</command> sets it automatically in - <filename>/mnt/etc/nixos/hardware-configuration.nix</filename> from your - currently mounted file systems. (The configuration file - <filename>hardware-configuration.nix</filename> is included from - <filename>configuration.nix</filename> and will be overwritten by future - invocations of <command>nixos-generate-config</command>; thus, you - generally should not modify it.) - </para> - <note> + If you’re using the graphical ISO image, other editors may be available + (such as <command>vim</command>). If you have network access, you can also + install other editors — for instance, you can install Emacs by running + <literal>nix-env -i emacs</literal>. + </para> + <variablelist> + <varlistentry> + <term> + BIOS systems + </term> + <listitem> + <para> + You <emphasis>must</emphasis> set the option + <xref linkend="opt-boot.loader.grub.device"/> to specify on which disk + the GRUB boot loader is to be installed. Without it, NixOS cannot boot. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + UEFI systems + </term> + <listitem> + <para> + You <emphasis>must</emphasis> set the option + <xref linkend="opt-boot.loader.systemd-boot.enable"/> to + <literal>true</literal>. <command>nixos-generate-config</command> + should do this automatically for new configurations when booted in UEFI + mode. + </para> + <para> + You may want to look at the options starting with + <option><link linkend="opt-boot.loader.efi.canTouchEfiVariables">boot.loader.efi</link></option> + and + <option><link linkend="opt-boot.loader.systemd-boot.enable">boot.loader.systemd</link></option> + as well. + </para> + </listitem> + </varlistentry> + </variablelist> <para> - Depending on your hardware configuration or type of file system, you may - need to set the option <option>boot.initrd.kernelModules</option> to - include the kernel modules that are necessary for mounting the root file - system, otherwise the installed system will not be able to boot. (If this - happens, boot from the CD again, mount the target file system on - <filename>/mnt</filename>, fix - <filename>/mnt/etc/nixos/configuration.nix</filename> and rerun - <filename>nixos-install</filename>.) In most cases, - <command>nixos-generate-config</command> will figure out the required - modules. + If there are other operating systems running on the machine before + installing NixOS, the <xref linkend="opt-boot.loader.grub.useOSProber"/> + option can be set to <literal>true</literal> to automatically add them to + the grub menu. </para> - </note> - </listitem> - <listitem> - <para> - Do the installation: + <para> + Another critical option is <option>fileSystems</option>, specifying the + file systems that need to be mounted by NixOS. However, you typically + don’t need to set it yourself, because + <command>nixos-generate-config</command> sets it automatically in + <filename>/mnt/etc/nixos/hardware-configuration.nix</filename> from your + currently mounted file systems. (The configuration file + <filename>hardware-configuration.nix</filename> is included from + <filename>configuration.nix</filename> and will be overwritten by future + invocations of <command>nixos-generate-config</command>; thus, you + generally should not modify it.) + </para> + <note> + <para> + Depending on your hardware configuration or type of file system, you may + need to set the option <option>boot.initrd.kernelModules</option> to + include the kernel modules that are necessary for mounting the root file + system, otherwise the installed system will not be able to boot. (If this + happens, boot from the installation media again, mount the target file + system on <filename>/mnt</filename>, fix + <filename>/mnt/etc/nixos/configuration.nix</filename> and rerun + <filename>nixos-install</filename>.) In most cases, + <command>nixos-generate-config</command> will figure out the required + modules. + </para> + </note> + </listitem> + <listitem> + <para> + Do the installation: <screen> # nixos-install</screen> - Cross fingers. If this fails due to a temporary problem (such as a network - issue while downloading binaries from the NixOS binary cache), you can just - re-run <command>nixos-install</command>. Otherwise, fix your - <filename>configuration.nix</filename> and then re-run - <command>nixos-install</command>. - </para> - <para> - As the last step, <command>nixos-install</command> will ask you to set the - password for the <literal>root</literal> user, e.g. + Cross fingers. If this fails due to a temporary problem (such as a network + issue while downloading binaries from the NixOS binary cache), you can + just re-run <command>nixos-install</command>. Otherwise, fix your + <filename>configuration.nix</filename> and then re-run + <command>nixos-install</command>. + </para> + <para> + As the last step, <command>nixos-install</command> will ask you to set the + password for the <literal>root</literal> user, e.g. <screen> setting root password... Enter new UNIX password: *** -Retype new UNIX password: *** - </screen> - <note> - <para> - For unattended installations, it is possible to use - <command>nixos-install --no-root-passwd</command> - in order to disable the password prompt entirely. - </para> - </note> - </para> - </listitem> - <listitem> - <para> - If everything went well: +Retype new UNIX password: ***</screen> + <note> + <para> + For unattended installations, it is possible to use + <command>nixos-install --no-root-passwd</command> in order to disable + the password prompt entirely. + </para> + </note> + </para> + </listitem> + <listitem> + <para> + If everything went well: <screen> - # reboot</screen> - </para> - </listitem> - <listitem> - <para> - You should now be able to boot into the installed NixOS. The GRUB boot menu - shows a list of <emphasis>available configurations</emphasis> (initially - just one). Every time you change the NixOS configuration (see - <link +# reboot</screen> + </para> + </listitem> + <listitem> + <para> + You should now be able to boot into the installed NixOS. The GRUB boot + menu shows a list of <emphasis>available configurations</emphasis> + (initially just one). Every time you change the NixOS configuration (see + <link linkend="sec-changing-config">Changing Configuration</link> - ), a new item is added to the menu. This allows you to easily roll back to - a previous configuration if something goes wrong. - </para> - <para> - You should log in and change the <literal>root</literal> password with - <command>passwd</command>. - </para> - <para> - You’ll probably want to create some user accounts as well, which can be - done with <command>useradd</command>: + ), a new item is added to the menu. This allows you to easily roll back to + a previous configuration if something goes wrong. + </para> + <para> + You should log in and change the <literal>root</literal> password with + <command>passwd</command>. + </para> + <para> + You’ll probably want to create some user accounts as well, which can be + done with <command>useradd</command>: <screen> $ useradd -c 'Eelco Dolstra' -m eelco $ passwd eelco</screen> - </para> - <para> - You may also want to install some software. For instance, + </para> + <para> + You may also want to install some software. For instance, <screen> $ nix-env -qa \*</screen> - shows what packages are available, and + shows what packages are available, and <screen> $ nix-env -i w3m</screen> - install the <literal>w3m</literal> browser. - </para> - </listitem> - </orderedlist> - <para> - To summarise, <xref linkend="ex-install-sequence" /> shows a typical sequence - of commands for installing NixOS on an empty hard drive (here - <filename>/dev/sda</filename>). <xref linkend="ex-config" + install the <literal>w3m</literal> browser. + </para> + </listitem> + </orderedlist> + </section> + <section xml:id="sec-installation-summary"> + <title>Installation summary</title> + + <para> + To summarise, <xref linkend="ex-install-sequence" /> shows a typical + sequence of commands for installing NixOS on an empty hard drive (here + <filename>/dev/sda</filename>). <xref linkend="ex-config" /> shows a - corresponding configuration Nix expression. - </para> - <example xml:id='ex-install-sequence'> - <title>Commands for Installing NixOS on <filename>/dev/sda</filename></title> -<screen> -# fdisk /dev/sda # <lineannotation>(or whatever device you want to install on)</lineannotation> --- for UEFI systems only -> n # <lineannotation>(create a new partition for /boot)</lineannotation> -> 3 # <lineannotation>(make it a partition number 3)</lineannotation> -> # <lineannotation>(press enter to accept the default)</lineannotation> -> +512M # <lineannotation>(the size of the UEFI boot partition)</lineannotation> -> t # <lineannotation>(change the partition type ...)</lineannotation> -> 3 # <lineannotation>(... of the boot partition ...)</lineannotation> -> 1 # <lineannotation>(... to 'UEFI System')</lineannotation> --- for BIOS or UEFI systems -> n # <lineannotation>(create a new partition for /swap)</lineannotation> -> 2 # <lineannotation>(make it a partition number 2)</lineannotation> -> # <lineannotation>(press enter to accept the default)</lineannotation> -> +8G # <lineannotation>(the size of the swap partition)</lineannotation> -> n # <lineannotation>(create a new partition for /)</lineannotation> -> 1 # <lineannotation>(make it a partition number 1)</lineannotation> -> # <lineannotation>(press enter to accept the default)</lineannotation> -> # <lineannotation>(press enter to accept the default and use the rest of the remaining space)</lineannotation> -> a # <lineannotation>(make the partition bootable)</lineannotation> -> x # <lineannotation>(enter expert mode)</lineannotation> -> f # <lineannotation>(fix up the partition ordering)</lineannotation> -> r # <lineannotation>(exit expert mode)</lineannotation> -> w # <lineannotation>(write the partition table to disk and exit)</lineannotation> + corresponding configuration Nix expression. + </para> + + <example xml:id="ex-partition-scheme-MBR"> + <title>Example partition schemes for NixOS on <filename>/dev/sda</filename> (MBR)</title> +<screen language="commands"> +# parted /dev/sda -- mklabel msdos +# parted /dev/sda -- mkpart primary 1MiB -8GiB +# parted /dev/sda -- mkpart primary linux-swap -8GiB 100%</screen> + </example> + + <example xml:id="ex-partition-scheme-UEFI"> + <title>Example partition schemes for NixOS on <filename>/dev/sda</filename> (UEFI)</title> +<screen language="commands"> +# parted /dev/sda -- mklabel gpt +# parted /dev/sda -- mkpart primary 512MiB -8GiB +# parted /dev/sda -- mkpart primary linux-swap -8GiB 100% +# parted /dev/sda -- mkpart ESP fat32 1MiB 512MiB +# parted /dev/sda -- set 3 boot on</screen> + </example> + + <example xml:id="ex-install-sequence"> + <title>Commands for Installing NixOS on <filename>/dev/sda</filename></title> + <para> + With a partitioned disk. +<screen language="commands"> # mkfs.ext4 -L nixos /dev/sda1 # mkswap -L swap /dev/sda2 # swapon /dev/sda2 @@ -416,9 +516,11 @@ $ nix-env -i w3m</screen> # nano /mnt/etc/nixos/configuration.nix # nixos-install # reboot</screen> - </example> - <example xml:id='ex-config'> - <title>NixOS Configuration</title> + </para> + </example> + + <example xml:id='ex-config'> + <title>NixOS Configuration</title> <screen> { config, pkgs, ... }: { imports = [ @@ -438,10 +540,19 @@ $ nix-env -i w3m</screen> services.sshd.enable = true; } </screen> - </example> - <xi:include href="installing-usb.xml" /> - <xi:include href="installing-pxe.xml" /> - <xi:include href="installing-virtualbox-guest.xml" /> - <xi:include href="installing-from-other-distro.xml" /> - <xi:include href="installing-behind-a-proxy.xml" /> + </example> + </section> + <section xml:id="sec-installation-additional-notes"> + <title>Additional installation notes</title> + + <xi:include href="installing-usb.xml" /> + + <xi:include href="installing-pxe.xml" /> + + <xi:include href="installing-virtualbox-guest.xml" /> + + <xi:include href="installing-from-other-distro.xml" /> + + <xi:include href="installing-behind-a-proxy.xml" /> + </section> </chapter> diff --git a/nixos/doc/manual/installation/upgrading.xml b/nixos/doc/manual/installation/upgrading.xml index 85e5082575d3..69668b1d4bd6 100644 --- a/nixos/doc/manual/installation/upgrading.xml +++ b/nixos/doc/manual/installation/upgrading.xml @@ -52,10 +52,13 @@ </listitem> </itemizedlist> To see what channels are available, go to - <link -xlink:href="https://nixos.org/channels"/>. (Note that the URIs of the + <link xlink:href="https://nixos.org/channels"/>. (Note that the URIs of the various channels redirect to a directory that contains the channel’s latest - version and includes ISO images and VirtualBox appliances.) + version and includes ISO images and VirtualBox appliances.) Please note that + during the release process, channels that are not yet released will be + present here as well. See the Getting NixOS page + <link xlink:href="https://nixos.org/nixos/download.html"/> to find the newest + supported stable release. </para> <para> When you first install NixOS, you’re automatically subscribed to the NixOS diff --git a/nixos/doc/manual/manual.xml b/nixos/doc/manual/manual.xml index a5efde32885c..12f52e1997c8 100644 --- a/nixos/doc/manual/manual.xml +++ b/nixos/doc/manual/manual.xml @@ -17,8 +17,8 @@ <para> If you encounter problems, please report them on the <literal - xlink:href="https://discourse.nixos.org">Discourse</literal> - or on the <link + xlink:href="https://discourse.nixos.org">Discourse</literal> or + on the <link xlink:href="irc://irc.freenode.net/#nixos"> <literal>#nixos</literal> channel on Freenode</link>. Bugs should be reported in diff --git a/nixos/doc/manual/options-to-docbook.xsl b/nixos/doc/manual/options-to-docbook.xsl index 2038b0dff63e..72ac89d4ff62 100644 --- a/nixos/doc/manual/options-to-docbook.xsl +++ b/nixos/doc/manual/options-to-docbook.xsl @@ -4,6 +4,7 @@ xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:str="http://exslt.org/strings" xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:nixos="tag:nixos.org" xmlns="http://docbook.org/ns/docbook" extension-element-prefixes="str" > @@ -30,10 +31,12 @@ <listitem> - <para> - <xsl:value-of disable-output-escaping="yes" - select="attr[@name = 'description']/string/@value" /> - </para> + <nixos:option-description> + <para> + <xsl:value-of disable-output-escaping="yes" + select="attr[@name = 'description']/string/@value" /> + </para> + </nixos:option-description> <xsl:if test="attr[@name = 'type']"> <para> diff --git a/nixos/doc/manual/postprocess-option-descriptions.xsl b/nixos/doc/manual/postprocess-option-descriptions.xsl new file mode 100644 index 000000000000..1201c7612c2e --- /dev/null +++ b/nixos/doc/manual/postprocess-option-descriptions.xsl @@ -0,0 +1,115 @@ +<?xml version="1.0"?> + +<xsl:stylesheet version="1.0" + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:str="http://exslt.org/strings" + xmlns:exsl="http://exslt.org/common" + xmlns:db="http://docbook.org/ns/docbook" + xmlns:nixos="tag:nixos.org" + extension-element-prefixes="str exsl"> + <xsl:output method='xml' encoding="UTF-8" /> + + <xsl:template match="@*|node()"> + <xsl:copy> + <xsl:apply-templates select="@*|node()" /> + </xsl:copy> + </xsl:template> + + <xsl:template name="break-up-description"> + <xsl:param name="input" /> + <xsl:param name="buffer" /> + + <!-- Every time we have two newlines following each other, we want to + break it into </para><para>. --> + <xsl:variable name="parbreak" select="'

'" /> + + <!-- Similar to "(head:tail) = input" in Haskell. --> + <xsl:variable name="head" select="$input[1]" /> + <xsl:variable name="tail" select="$input[position() > 1]" /> + + <xsl:choose> + <xsl:when test="$head/self::text() and contains($head, $parbreak)"> + <!-- If the haystack provided to str:split() directly starts or + ends with $parbreak, it doesn't generate a <token/> for that, + so we are doing this here. --> + <xsl:variable name="splitted-raw"> + <xsl:if test="starts-with($head, $parbreak)"><token /></xsl:if> + <xsl:for-each select="str:split($head, $parbreak)"> + <token><xsl:value-of select="node()" /></token> + </xsl:for-each> + <!-- Something like ends-with($head, $parbreak), but there is + no ends-with() in XSLT, so we need to use substring(). --> + <xsl:if test=" + substring($head, string-length($head) - + string-length($parbreak) + 1) = $parbreak + "><token /></xsl:if> + </xsl:variable> + <xsl:variable name="splitted" + select="exsl:node-set($splitted-raw)/token" /> + <!-- The buffer we had so far didn't contain any text nodes that + contain a $parbreak, so we can put the buffer along with the + first token of $splitted into a para element. --> + <para xmlns="http://docbook.org/ns/docbook"> + <xsl:apply-templates select="exsl:node-set($buffer)" /> + <xsl:apply-templates select="$splitted[1]/node()" /> + </para> + <!-- We have already emitted the first splitted result, so the + last result is going to be set as the new $buffer later + because its contents may not be directly followed up by a + $parbreak. --> + <xsl:for-each select="$splitted[position() > 1 + and position() < last()]"> + <para xmlns="http://docbook.org/ns/docbook"> + <xsl:apply-templates select="node()" /> + </para> + </xsl:for-each> + <xsl:call-template name="break-up-description"> + <xsl:with-param name="input" select="$tail" /> + <xsl:with-param name="buffer" select="$splitted[last()]/node()" /> + </xsl:call-template> + </xsl:when> + <!-- Either non-text node or one without $parbreak, which we just + want to buffer and continue recursing. --> + <xsl:when test="$input"> + <xsl:call-template name="break-up-description"> + <xsl:with-param name="input" select="$tail" /> + <!-- This essentially appends $head to $buffer. --> + <xsl:with-param name="buffer"> + <xsl:if test="$buffer"> + <xsl:for-each select="exsl:node-set($buffer)"> + <xsl:apply-templates select="." /> + </xsl:for-each> + </xsl:if> + <xsl:apply-templates select="$head" /> + </xsl:with-param> + </xsl:call-template> + </xsl:when> + <!-- No more $input, just put the remaining $buffer in a para. --> + <xsl:otherwise> + <para xmlns="http://docbook.org/ns/docbook"> + <xsl:apply-templates select="exsl:node-set($buffer)" /> + </para> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template match="nixos:option-description"> + <xsl:choose> + <!-- + Only process nodes that are comprised of a single <para/> element, + because if that's not the case the description already contains + </para><para> in between and we need no further processing. + --> + <xsl:when test="count(db:para) > 1"> + <xsl:apply-templates select="node()" /> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="break-up-description"> + <xsl:with-param name="input" + select="exsl:node-set(db:para/node())" /> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + +</xsl:stylesheet> diff --git a/nixos/doc/manual/release-notes/release-notes.xml b/nixos/doc/manual/release-notes/release-notes.xml index 94f176186b6e..a222bfa29d5a 100644 --- a/nixos/doc/manual/release-notes/release-notes.xml +++ b/nixos/doc/manual/release-notes/release-notes.xml @@ -8,6 +8,7 @@ This section lists the release notes for each stable version of NixOS and current unstable revision. </para> + <xi:include href="rl-1903.xml" /> <xi:include href="rl-1809.xml" /> <xi:include href="rl-1803.xml" /> <xi:include href="rl-1709.xml" /> diff --git a/nixos/doc/manual/release-notes/rl-1509.xml b/nixos/doc/manual/release-notes/rl-1509.xml index 4eb2f9aa0a95..e500c9d63422 100644 --- a/nixos/doc/manual/release-notes/rl-1509.xml +++ b/nixos/doc/manual/release-notes/rl-1509.xml @@ -435,11 +435,11 @@ system.autoUpgrade.enable = true; <programlisting> system.stateVersion = "14.12"; </programlisting> - The new option <option>system.stateVersion</option> ensures that - certain configuration changes that could break existing systems (such as - the <command>sshd</command> host key setting) will maintain compatibility - with the specified NixOS release. NixOps sets the state version of - existing deployments automatically. + The new option <option>system.stateVersion</option> ensures that certain + configuration changes that could break existing systems (such as the + <command>sshd</command> host key setting) will maintain compatibility with + the specified NixOS release. NixOps sets the state version of existing + deployments automatically. </para> </listitem> <listitem> diff --git a/nixos/doc/manual/release-notes/rl-1809.xml b/nixos/doc/manual/release-notes/rl-1809.xml index 92a7223e0412..8715a05f508b 100644 --- a/nixos/doc/manual/release-notes/rl-1809.xml +++ b/nixos/doc/manual/release-notes/rl-1809.xml @@ -3,7 +3,7 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="sec-release-18.09"> - <title>Release 18.09 (“Jellyfish”, 2018/09/??)</title> + <title>Release 18.09 (“Jellyfish”, 2018/10/05)</title> <section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" @@ -14,18 +14,56 @@ <para> In addition to numerous new and upgraded packages, this release has the - following highlights: + following notable updates: </para> <itemizedlist> <listitem> - <para> - Support for wrapping binaries using <literal>firejail</literal> has been - added through <varname>programs.firejail.wrappedBinaries</varname>. - </para> - <para> - For example - </para> + <para> + End of support is planned for end of April 2019, handing over to 19.03. + </para> + </listitem> + <listitem> + <para> + Platform support: x86_64-linux and x86_64-darwin as always. Support for + aarch64-linux is as with the previous releases, not equivalent to the + x86-64-linux release, but with efforts to reach parity. + </para> + </listitem> + <listitem> + <para> + Nix has been updated to 2.1; see its + <link xlink:href="https://nixos.org/nix/manual/#ssec-relnotes-2.1">release + notes</link>. + </para> + </listitem> + <listitem> + <para> + Core versions: linux: 4.14 LTS (unchanged), glibc: 2.26 → 2.27, gcc: 7 + (unchanged), systemd: 237 → 239. + </para> + </listitem> + <listitem> + <para> + Desktop version changes: gnome: 3.26 → 3.28, (KDE) plasma-desktop: 5.12 + → 5.13. + </para> + </listitem> + </itemizedlist> + + <para> + Notable changes and additions for 18.09 include: + </para> + + <itemizedlist> + <listitem> + <para> + Support for wrapping binaries using <literal>firejail</literal> has been + added through <varname>programs.firejail.wrappedBinaries</varname>. + </para> + <para> + For example + </para> <programlisting> programs.firejail = { enable = true; @@ -35,9 +73,10 @@ programs.firejail = { }; }; </programlisting> - <para> - This will place <literal>firefox</literal> and <literal>mpv</literal> binaries in the global path wrapped by firejail. - </para> + <para> + This will place <literal>firefox</literal> and <literal>mpv</literal> + binaries in the global path wrapped by firejail. + </para> </listitem> <listitem> <para> @@ -69,52 +108,355 @@ $ nix-instantiate -E '(import <nixpkgsunstable> {}).gitFull' <title>New Services</title> <para> - The following new services were added since the last release: + A curated selection of new services that were added since the last release: </para> <itemizedlist> <listitem> <para> - The <varname>services.cassandra</varname> module has been reworked and - was rewritten from scratch. The service has succeeding tests for - the versions 2.1, 2.2, 3.0 and 3.11 of <link - xlink:href="https://cassandra.apache.org/">Apache Cassandra</link>. + The <varname>services.cassandra</varname> module has been reworked and was + rewritten from scratch. The service has succeeding tests for the versions + 2.1, 2.2, 3.0 and 3.11 of + <link + xlink:href="https://cassandra.apache.org/">Apache + Cassandra</link>. </para> </listitem> <listitem> <para> - There is a new <varname>services.foundationdb</varname> module for deploying - <link xlink:href="https://www.foundationdb.org">FoundationDB</link> clusters. + There is a new <varname>services.foundationdb</varname> module for + deploying + <link xlink:href="https://www.foundationdb.org">FoundationDB</link> + clusters. </para> </listitem> <listitem> <para> When enabled the <literal>iproute2</literal> will copy the files expected by ip route (e.g., <filename>rt_tables</filename>) in - <filename>/run/iproute2</filename>. This allows to write aliases for + <filename>/etc/iproute2</filename>. This allows to write aliases for routing tables for instance. </para> </listitem> <listitem> <para> - <varname>services.strongswan-swanctl</varname> - is a modern replacement for <varname>services.strongswan</varname>. - You can use either one of them to setup IPsec VPNs but not both at the same time. + <varname>services.strongswan-swanctl</varname> is a modern replacement for + <varname>services.strongswan</varname>. You can use either one of them to + setup IPsec VPNs but not both at the same time. </para> <para> - <varname>services.strongswan-swanctl</varname> uses the - <link xlink:href="https://wiki.strongswan.org/projects/strongswan/wiki/swanctl">swanctl</link> - command which uses the modern - <link xlink:href="https://github.com/strongswan/strongswan/blob/master/src/libcharon/plugins/vici/README.md">vici</link> - <emphasis>Versatile IKE Configuration Interface</emphasis>. - The deprecated <literal>ipsec</literal> command used in <varname>services.strongswan</varname> is using the legacy - <link xlink:href="https://github.com/strongswan/strongswan/blob/master/README_LEGACY.md">stroke configuration interface</link>. + <varname>services.strongswan-swanctl</varname> uses the + <link xlink:href="https://wiki.strongswan.org/projects/strongswan/wiki/swanctl">swanctl</link> + command which uses the modern + <link xlink:href="https://github.com/strongswan/strongswan/blob/master/src/libcharon/plugins/vici/README.md">vici</link> + <emphasis>Versatile IKE Configuration Interface</emphasis>. The deprecated + <literal>ipsec</literal> command used in + <varname>services.strongswan</varname> is using the legacy + <link xlink:href="https://github.com/strongswan/strongswan/blob/master/README_LEGACY.md">stroke + configuration interface</link>. </para> </listitem> <listitem> <para> - The new <varname>services.elasticsearch-curator</varname> service - periodically curates or manages, your Elasticsearch indices and snapshots. + The new <varname>services.elasticsearch-curator</varname> service + periodically curates or manages, your Elasticsearch indices and snapshots. + </para> + </listitem> + </itemizedlist> + + <para> + Every new services: + </para> + + <itemizedlist> + <listitem> + <para> + <literal>./config/xdg/autostart.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./config/xdg/icons.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./config/xdg/menus.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./config/xdg/mime.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./hardware/brightnessctl.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./hardware/onlykey.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./hardware/video/uvcvideo/default.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./misc/documentation.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./programs/firejail.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./programs/iftop.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./programs/sedutil.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./programs/singularity.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./programs/xss-lock.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./programs/zsh/zsh-autosuggestions.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/admin/oxidized.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/backup/duplicati.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/backup/restic.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/backup/restic-rest-server.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/cluster/hadoop/default.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/databases/aerospike.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/databases/monetdb.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/desktops/bamf.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/desktops/flatpak.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/desktops/zeitgeist.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/development/bloop.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/development/jupyter/default.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/hardware/lcd.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/hardware/undervolt.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/misc/clipmenu.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/misc/gitweb.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/misc/serviio.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/misc/safeeyes.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/misc/sysprof.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/misc/weechat.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/monitoring/datadog-agent.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/monitoring/incron.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/networking/dnsdist.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/networking/freeradius.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/networking/hans.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/networking/morty.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/networking/ndppd.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/networking/ocserv.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/networking/owamp.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/networking/quagga.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/networking/shadowsocks.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/networking/stubby.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/networking/zeronet.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/security/certmgr.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/security/cfssl.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/security/oauth2_proxy_nginx.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/web-apps/virtlyst.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/web-apps/youtrack.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/web-servers/hitch/default.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/web-servers/hydron.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/web-servers/meguca.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./services/web-servers/nginx/gitweb.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./virtualisation/kvmgt.nix</literal> + </para> + </listitem> + <listitem> + <para> + <literal>./virtualisation/qemu-guest-agent.nix</literal> </para> </listitem> </itemizedlist> @@ -135,8 +477,50 @@ $ nix-instantiate -E '(import <nixpkgsunstable> {}).gitFull' <itemizedlist> <listitem> <para> - The deprecated <varname>services.cassandra</varname> module has - seen a complete rewrite. (See above.) + Some licenses that were incorrectly not marked as unfree now are. This is + the case for: + <itemizedlist> + <listitem> + <para> + cc-by-nc-sa-20: Creative Commons Attribution Non Commercial Share Alike + 2.0 + </para> + </listitem> + <listitem> + <para> + cc-by-nc-sa-25: Creative Commons Attribution Non Commercial Share Alike + 2.5 + </para> + </listitem> + <listitem> + <para> + cc-by-nc-sa-30: Creative Commons Attribution Non Commercial Share Alike + 3.0 + </para> + </listitem> + <listitem> + <para> + cc-by-nc-sa-40: Creative Commons Attribution Non Commercial Share Alike + 4.0 + </para> + </listitem> + <listitem> + <para> + cc-by-nd-30: Creative Commons Attribution-No Derivative Works v3.00 + </para> + </listitem> + <listitem> + <para> + msrla: Microsoft Research License Agreement + </para> + </listitem> + </itemizedlist> + </para> + </listitem> + <listitem> + <para> + The deprecated <varname>services.cassandra</varname> module has seen a + complete rewrite. (See above.) </para> </listitem> <listitem> @@ -186,41 +570,44 @@ $ nix-instantiate -E '(import <nixpkgsunstable> {}).gitFull' </listitem> <listitem> <para> - <varname>services.munge</varname> now runs as user (and group) <literal>munge</literal> instead of root. - Make sure the key file is accessible to the daemon. + <varname>services.munge</varname> now runs as user (and group) + <literal>munge</literal> instead of root. Make sure the key file is + accessible to the daemon. </para> </listitem> <listitem> <para> - <varname>dockerTools.buildImage</varname> now uses <literal>null</literal> as default value for <varname>tag</varname>, - which indicates that the nix output hash will be used as tag. + <varname>dockerTools.buildImage</varname> now uses <literal>null</literal> + as default value for <varname>tag</varname>, which indicates that the nix + output hash will be used as tag. </para> </listitem> <listitem> <para> - The ELK stack: <varname>elasticsearch</varname>, <varname>logstash</varname> and <varname>kibana</varname> - has been upgraded from 2.* to 6.3.*. - The 2.* versions have been <link xlink:href="https://www.elastic.co/support/eol">unsupported since last year</link> - so they have been removed. You can still use the 5.* versions under the names - <varname>elasticsearch5</varname>, <varname>logstash5</varname> and - <varname>kibana5</varname>. + The ELK stack: <varname>elasticsearch</varname>, + <varname>logstash</varname> and <varname>kibana</varname> has been + upgraded from 2.* to 6.3.*. The 2.* versions have been + <link xlink:href="https://www.elastic.co/support/eol">unsupported since + last year</link> so they have been removed. You can still use the 5.* + versions under the names <varname>elasticsearch5</varname>, + <varname>logstash5</varname> and <varname>kibana5</varname>. </para> <para> - The elastic beats: - <varname>filebeat</varname>, <varname>heartbeat</varname>, - <varname>metricbeat</varname> and <varname>packetbeat</varname> - have had the same treatment: they now target 6.3.* as well. - The 5.* versions are available under the names: + The elastic beats: <varname>filebeat</varname>, + <varname>heartbeat</varname>, <varname>metricbeat</varname> and + <varname>packetbeat</varname> have had the same treatment: they now target + 6.3.* as well. The 5.* versions are available under the names: <varname>filebeat5</varname>, <varname>heartbeat5</varname>, <varname>metricbeat5</varname> and <varname>packetbeat5</varname> </para> <para> The ELK-6.3 stack now comes with - <link xlink:href="https://www.elastic.co/products/x-pack/open">X-Pack by default</link>. - Since X-Pack is licensed under the - <link xlink:href="https://github.com/elastic/elasticsearch/blob/master/licenses/ELASTIC-LICENSE.txt">Elastic License</link> - the ELK packages now have an unfree license. To use them you need to specify - <literal>allowUnfree = true;</literal> in your nixpkgs configuration. + <link xlink:href="https://www.elastic.co/products/x-pack/open">X-Pack by + default</link>. Since X-Pack is licensed under the + <link xlink:href="https://github.com/elastic/elasticsearch/blob/master/licenses/ELASTIC-LICENSE.txt">Elastic + License</link> the ELK packages now have an unfree license. To use them + you need to specify <literal>allowUnfree = true;</literal> in your nixpkgs + configuration. </para> <para> Fortunately there is also a free variant of the ELK stack without X-Pack. @@ -231,20 +618,28 @@ $ nix-instantiate -E '(import <nixpkgsunstable> {}).gitFull' </listitem> <listitem> <para> - Options - <literal>boot.initrd.luks.devices.<replaceable>name</replaceable>.yubikey.ramfsMountPoint</literal> - <literal>boot.initrd.luks.devices.<replaceable>name</replaceable>.yubikey.storage.mountPoint</literal> - were removed. <literal>luksroot.nix</literal> module never supported more than one YubiKey at - a time anyway, hence those options never had any effect. You should be able to remove them - from your config without any issues. + Options + <literal>boot.initrd.luks.devices.<replaceable>name</replaceable>.yubikey.ramfsMountPoint</literal> + <literal>boot.initrd.luks.devices.<replaceable>name</replaceable>.yubikey.storage.mountPoint</literal> + were removed. <literal>luksroot.nix</literal> module never supported more + than one YubiKey at a time anyway, hence those options never had any + effect. You should be able to remove them from your config without any + issues. + </para> + </listitem> + <listitem> + <para> + <literal>stdenv.system</literal> and <literal>system</literal> in nixpkgs + now refer to the host platform instead of the build platform. For native + builds this is not change, let alone a breaking one. For cross builds, it + is a breaking change, and <literal>stdenv.buildPlatform.system</literal> + can be used instead for the old behavior. They should be using that + anyways for clarity. </para> </listitem> <listitem> <para> - <literal>stdenv.system</literal> and <literal>system</literal> in nixpkgs now refer to the host platform instead of the build platform. - For native builds this is not change, let alone a breaking one. - For cross builds, it is a breaking change, and <literal>stdenv.buildPlatform.system</literal> can be used instead for the old behavior. - They should be using that anyways for clarity. + Groups <literal>kvm</literal> and <literal>render</literal> are introduced now, as systemd requires them. </para> </listitem> </itemizedlist> @@ -298,26 +693,33 @@ $ nix-instantiate -E '(import <nixpkgsunstable> {}).gitFull' </listitem> <listitem> <para> - The <literal>pkgs</literal> argument to NixOS modules can now be set directly using <literal>nixpkgs.pkgs</literal>. Previously, only the <literal>system</literal>, <literal>config</literal> and <literal>overlays</literal> arguments could be used to influence <literal>pkgs</literal>. + The <literal>pkgs</literal> argument to NixOS modules can now be set + directly using <literal>nixpkgs.pkgs</literal>. Previously, only the + <literal>system</literal>, <literal>config</literal> and + <literal>overlays</literal> arguments could be used to influence + <literal>pkgs</literal>. </para> </listitem> <listitem> <para> - A NixOS system can now be constructed more easily based on a preexisting invocation of Nixpkgs. For example: - <programlisting> + A NixOS system can now be constructed more easily based on a preexisting + invocation of Nixpkgs. For example: +<programlisting> inherit (pkgs.nixos { boot.loader.grub.enable = false; fileSystems."/".device = "/dev/xvda1"; }) toplevel kernel initialRamdisk manual; </programlisting> - - This benefits evaluation performance, lets you write Nixpkgs packages that depend on NixOS images and is consistent with a deployment architecture that would be centered around Nixpkgs overlays. + This benefits evaluation performance, lets you write Nixpkgs packages that + depend on NixOS images and is consistent with a deployment architecture + that would be centered around Nixpkgs overlays. </para> </listitem> <listitem> <para> - <literal>lib.traceValIfNot</literal> has been deprecated. Use - <literal>if/then/else</literal> and <literal>lib.traceValSeq</literal> instead. + <literal>lib.traceValIfNot</literal> has been deprecated. Use + <literal>if/then/else</literal> and <literal>lib.traceValSeq</literal> + instead. </para> </listitem> <listitem> @@ -336,9 +738,9 @@ inherit (pkgs.nixos { </listitem> <listitem> <para> - <literal>lib.recursiveUpdateUntil</literal> was not acting according to its - specification. It has been fixed to act according to the docstring, and a - test has been added. + <literal>lib.recursiveUpdateUntil</literal> was not acting according to + its specification. It has been fixed to act according to the docstring, + and a test has been added. </para> </listitem> <listitem> @@ -408,11 +810,11 @@ inherit (pkgs.nixos { </para> </listitem> <listitem> - <para> - The Kubernetes package has been bumped to major version 1.11. - Please consult the - <link xlink:href="https://github.com/kubernetes/kubernetes/blob/release-1.11/CHANGELOG-1.11.md">release notes</link> - for details on new features and api changes. + <para> + The Kubernetes package has been bumped to major version 1.11. Please + consult the + <link xlink:href="https://github.com/kubernetes/kubernetes/blob/release-1.11/CHANGELOG-1.11.md">release + notes</link> for details on new features and api changes. </para> </listitem> <listitem> @@ -432,8 +834,8 @@ inherit (pkgs.nixos { </listitem> <listitem> <para> - The option <varname>services.kubernetes.apiserver.address</varname> - was renamed to <varname>services.kubernetes.apiserver.bindAddress</varname>. + The option <varname>services.kubernetes.apiserver.address</varname> was + renamed to <varname>services.kubernetes.apiserver.bindAddress</varname>. Note that the default value has changed from 127.0.0.1 to 0.0.0.0. </para> </listitem> @@ -445,76 +847,86 @@ inherit (pkgs.nixos { </listitem> <listitem> <para> - The option <varname>services.kubernetes.addons.dashboard.enableRBAC</varname> - was renamed to <varname>services.kubernetes.addons.dashboard.rbac.enable</varname>. + The option + <varname>services.kubernetes.addons.dashboard.enableRBAC</varname> was + renamed to + <varname>services.kubernetes.addons.dashboard.rbac.enable</varname>. </para> </listitem> <listitem> <para> The Kubernetes Dashboard now has only minimal RBAC permissions by default. - If dashboard cluster-admin rights are desired, - set <varname>services.kubernetes.addons.dashboard.rbac.clusterAdmin</varname> to true. - On existing clusters, in order for the revocation of privileges to take effect, - the current ClusterRoleBinding for kubernetes-dashboard must be manually removed: - <literal>kubectl delete clusterrolebinding kubernetes-dashboard</literal> + If dashboard cluster-admin rights are desired, set + <varname>services.kubernetes.addons.dashboard.rbac.clusterAdmin</varname> + to true. On existing clusters, in order for the revocation of privileges + to take effect, the current ClusterRoleBinding for kubernetes-dashboard + must be manually removed: <literal>kubectl delete clusterrolebinding + kubernetes-dashboard</literal> </para> </listitem> <listitem> <para> The <varname>programs.screen</varname> module provides allows to configure - <literal>/etc/screenrc</literal>, however the module behaved fairly counterintuitive as - the config exists, but the package wasn't available. Since 18.09 <literal>pkgs.screen</literal> - will be added to <literal>environment.systemPackages</literal>. + <literal>/etc/screenrc</literal>, however the module behaved fairly + counterintuitive as the config exists, but the package wasn't available. + Since 18.09 <literal>pkgs.screen</literal> will be added to + <literal>environment.systemPackages</literal>. </para> </listitem> <listitem> <para> - The module <option>services.networking.hostapd</option> now uses WPA2 by default. + The module <option>services.networking.hostapd</option> now uses WPA2 by + default. </para> </listitem> <listitem> <para> - <varname>s6Dns</varname>, <varname>s6Networking</varname>, - <varname>s6LinuxUtils</varname> and <varname>s6PortableUtils</varname> - renamed to - <varname>s6-dns</varname>, <varname>s6-networking</varname>, - <varname>s6-linux-utils</varname> and <varname>s6-portable-utils</varname> respectively. + <varname>s6Dns</varname>, <varname>s6Networking</varname>, + <varname>s6LinuxUtils</varname> and <varname>s6PortableUtils</varname> + renamed to <varname>s6-dns</varname>, <varname>s6-networking</varname>, + <varname>s6-linux-utils</varname> and <varname>s6-portable-utils</varname> + respectively. </para> - </listitem> - <listitem> + </listitem> + <listitem> <para> - The module option <option>nix.useSandbox</option> is now defaulted to <literal>true</literal>. + The module option <option>nix.useSandbox</option> is now defaulted to + <literal>true</literal>. </para> - </listitem> - <listitem> + </listitem> + <listitem> <para> - The config activation script of <literal>nixos-rebuild</literal> now - <link xlink:href="https://www.freedesktop.org/software/systemd/man/systemctl.html#Manager%20Lifecycle%20Commands">reloads</link> - all user units for each authenticated user. + The config activation script of <literal>nixos-rebuild</literal> now + <link xlink:href="https://www.freedesktop.org/software/systemd/man/systemctl.html#Manager%20Lifecycle%20Commands">reloads</link> + all user units for each authenticated user. </para> - </listitem> - <listitem> + </listitem> + <listitem> <para> - The default display manager is now LightDM. - To use SLiM set <literal>services.xserver.displayManager.slim.enable</literal> - to <literal>true</literal>. + The default display manager is now LightDM. To use SLiM set + <literal>services.xserver.displayManager.slim.enable</literal> to + <literal>true</literal>. </para> - </listitem> - <listitem> + </listitem> + <listitem> <para> - NixOS option descriptions are now automatically broken up into individual - paragraphs if the text contains two consecutive newlines, so it's no - longer necessary to use <code></para><para></code> to start - a new paragraph. + NixOS option descriptions are now automatically broken up into individual + paragraphs if the text contains two consecutive newlines, so it's no + longer necessary to use <code></para><para></code> to start a + new paragraph. </para> - </listitem> - <listitem> + </listitem> + <listitem> <para> - Top-level <literal>buildPlatform</literal>, <literal>hostPlatform</literal>, and <literal>targetPlatform</literal> in Nixpkgs are deprecated. - Please use their equivalents in <literal>stdenv</literal> instead: - <literal>stdenv.buildPlatform</literal>, <literal>stdenv.hostPlatform</literal>, and <literal>stdenv.targetPlatform</literal>. + Top-level <literal>buildPlatform</literal>, + <literal>hostPlatform</literal>, and <literal>targetPlatform</literal> in + Nixpkgs are deprecated. Please use their equivalents in + <literal>stdenv</literal> instead: + <literal>stdenv.buildPlatform</literal>, + <literal>stdenv.hostPlatform</literal>, and + <literal>stdenv.targetPlatform</literal>. </para> - </listitem> + </listitem> </itemizedlist> </section> </section> diff --git a/nixos/doc/manual/release-notes/rl-1903.xml b/nixos/doc/manual/release-notes/rl-1903.xml new file mode 100644 index 000000000000..1d9b6ecc0e2e --- /dev/null +++ b/nixos/doc/manual/release-notes/rl-1903.xml @@ -0,0 +1,204 @@ +<section 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="sec-release-19.03"> + <title>Release 19.03 (“Koi”, 2019/03/??)</title> + + <section 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="sec-release-19.03-highlights"> + <title>Highlights</title> + + <para> + In addition to numerous new and upgraded packages, this release has the + following highlights: + </para> + + <itemizedlist> + <listitem> + <para /> + </listitem> + </itemizedlist> + </section> + + <section 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="sec-release-19.03-new-services"> + <title>New Services</title> + + <para> + The following new services were added since the last release: + </para> + + <itemizedlist> + <listitem> + <para /> + </listitem> + </itemizedlist> + </section> + + <section 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="sec-release-19.03-incompatibilities"> + <title>Backward Incompatibilities</title> + + <para> + When upgrading from a previous release, please be aware of the following + incompatible changes: + </para> + + <itemizedlist> + <listitem> + <para> + The minimum version of Nix required to evaluate Nixpkgs is now 2.0. + </para> + <itemizedlist> + <listitem> + <para> + For users of NixOS 18.03 and 19.03, NixOS defaults to Nix 2.0, but + supports using Nix 1.11 by setting <literal>nix.package = + pkgs.nix1;</literal>. If this option is set to a Nix 1.11 package, you + will need to either unset the option or upgrade it to Nix 2.0. + </para> + </listitem> + <listitem> + <para> + For users of NixOS 17.09, you will first need to upgrade Nix by setting + <literal>nix.package = pkgs.nixStable2;</literal> and run + <command>nixos-rebuild switch</command> as the <literal>root</literal> + user. + </para> + </listitem> + <listitem> + <para> + For users of a daemon-less Nix installation on Linux or macOS, you can + upgrade Nix by running <command>curl https://nixos.org/nix/install | + sh</command>, or prior to doing a channel update, running + <command>nix-env -iA nix</command>. + </para> + <para> + If you have already run a channel update and Nix is no longer able to + evaluate Nixpkgs, the error message printed should provide adequate + directions for upgrading Nix. + </para> + </listitem> + <listitem> + <para> + For users of the Nix daemon on macOS, you can upgrade Nix by running + <command>sudo -i sh -c 'nix-channel --update && nix-env -iA + nixpkgs.nix'; sudo launchctl stop org.nixos.nix-daemon; sudo launchctl + start org.nixos.nix-daemon</command>. + </para> + </listitem> + </itemizedlist> + </listitem> + <listitem> + <para> + Package <varname>rabbitmq_server</varname> is renamed to + <varname>rabbitmq-server</varname>. + </para> + </listitem> + <listitem> + <para> + The <literal>light</literal> module no longer uses setuid binaries, but + udev rules. As a consequence users of that module have to belong to the + <literal>video</literal> group in order to use the executable (i.e. + <literal>users.users.yourusername.extraGroups = ["video"];</literal>). + </para> + </listitem> + <listitem> + <para> + Buildbot now supports Python 3 and its packages have been moved to + <literal>pythonPackages</literal>. The options + <option>services.buildbot-master.package</option> and + <option>services.buildbot-worker.package</option> can be used to select + the Python 2 or 3 version of the package. + </para> + </listitem> + <listitem> + <para> + Options + <literal>services.znc.confOptions.networks.<replaceable>name</replaceable>.userName</literal> and + <literal>services.znc.confOptions.networks.<replaceable>name</replaceable>.modulePackages</literal> + were removed. They were never used for anything and can therefore safely be removed. + </para> + </listitem> + <listitem> + <para> + Package <literal>wasm</literal> has been renamed <literal>proglodyte-wasm</literal>. The package + <literal>wasm</literal> will be pointed to <literal>ocamlPackages.wasm</literal> in 19.09, so + make sure to update your configuration if you want to keep <literal>proglodyte-wasm</literal> + </para> + </listitem> + <listitem> + <para> + OpenSMTPD has been upgraded to version 6.4.0p1. This release makes + backwards-incompatible changes to the configuration file format. See + <command>man smtpd.conf</command> for more information on the new file + format. + </para> + </listitem> + <listitem> + <para> + The versioned <varname>postgresql</varname> have been renamed to use + underscore number seperators. For example, <varname>postgresql96</varname> + has been renamed to <varname>postgresql_9_6</varname>. + </para> + </listitem> + <listitem> + <para> + Slurm introduces the new option + <literal>services.slurm.stateSaveLocation</literal>, + which is now set to <literal>/var/spool/slurm</literal> by default + (instead of <literal>/var/spool</literal>). + Make sure to move all files to the new directory or to set the option accordingly. + </para> + <para> + The slurmctld now runs as user <literal>slurm</literal> instead of <literal>root</literal>. + If you want to keep slurmctld running as <literal>root</literal>, set + <literal>services.slurm.user = root</literal>. + </para> + <para> + The options <literal>services.slurm.nodeName</literal> and + <literal>services.slurm.partitionName</literal> are now sets of + strings to correctly reflect that fact that each of these + options can occour more than once in the configuration. + </para> + </listitem> + </itemizedlist> + </section> + + <section 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="sec-release-19.03-notable-changes"> + <title>Other Notable Changes</title> + + <itemizedlist> + <listitem> + <para> + The <option>services.matomo</option> module gained the option + <option>services.matomo.package</option> which determines the used + Matomo version. + </para> + </listitem> + <listitem> + <para> + The deprecated <literal>truecrypt</literal> package has been removed + and <literal>truecrypt</literal> attribute is now an alias for + <literal>veracrypt</literal>. VeraCrypt is backward-compatible with + TrueCrypt volumes. Note that <literal>cryptsetup</literal> also + supports loading TrueCrypt volumes. + </para> + </listitem> + </itemizedlist> + </section> +</section> diff --git a/nixos/lib/build-vms.nix b/nixos/lib/build-vms.nix index 48288cf5962c..4f65501f89c6 100644 --- a/nixos/lib/build-vms.nix +++ b/nixos/lib/build-vms.nix @@ -28,7 +28,7 @@ rec { modules = configurations ++ [ ../modules/virtualisation/qemu-vm.nix ../modules/testing/test-instrumentation.nix # !!! should only get added for automated test runs - { key = "no-manual"; services.nixosManual.enable = false; } + { key = "no-manual"; documentation.nixos.enable = false; } { key = "qemu"; system.build.qemu = qemu; } ] ++ optional minimal ../modules/testing/minimal-kernel.nix; extraArgs = { inherit nodes; }; diff --git a/nixos/lib/eval-config.nix b/nixos/lib/eval-config.nix index ef685949ae1f..5f05b037bdde 100644 --- a/nixos/lib/eval-config.nix +++ b/nixos/lib/eval-config.nix @@ -28,7 +28,7 @@ let extraArgs_ = extraArgs; pkgs_ = pkgs; extraModules = let e = builtins.getEnv "NIXOS_EXTRA_MODULE_PATH"; - in if e == "" then [] else [(import (builtins.toPath e))]; + in if e == "" then [] else [(import e)]; in let @@ -53,7 +53,8 @@ in rec { inherit prefix check; modules = modules ++ extraModules ++ baseModules ++ [ pkgsModule ]; args = extraArgs; - specialArgs = { modulesPath = ../modules; } // specialArgs; + specialArgs = + { modulesPath = builtins.toString ../modules; } // specialArgs; }) config options; # These are the extra arguments passed to every module. In diff --git a/nixos/lib/test-driver/Machine.pm b/nixos/lib/test-driver/Machine.pm index b18f48464cee..abcc1c50d4d8 100644 --- a/nixos/lib/test-driver/Machine.pm +++ b/nixos/lib/test-driver/Machine.pm @@ -155,8 +155,10 @@ sub start { $ENV{USE_TMPDIR} = 1; $ENV{QEMU_OPTS} = ($self->{allowReboot} ? "" : "-no-reboot ") . - "-monitor unix:./monitor -chardev socket,id=shell,path=./shell " . - "-device virtio-serial -device virtconsole,chardev=shell " . + "-monitor unix:./monitor " . + "-chardev socket,id=shell,path=./shell -device virtio-serial -device virtconsole,chardev=shell " . + # socket backdoor, see "Debugging NixOS tests" section in NixOS manual + "-chardev socket,id=backdoor,path=./backdoor,server,nowait -device virtio-serial -device virtconsole,chardev=backdoor " . "-device virtio-rng-pci " . ($showGraphics ? "-serial stdio" : "-nographic") . " " . ($ENV{QEMU_OPTS} || ""); chdir $self->{stateDir} or die; @@ -248,7 +250,8 @@ sub connect { $self->start; local $SIG{ALRM} = sub { die "timed out waiting for the VM to connect\n"; }; - alarm 300; + # 50 minutes -- increased as a test, see #49441 + alarm 3000; readline $self->{socket} or die "the VM quit before connecting\n"; alarm 0; diff --git a/nixos/modules/config/iproute2.nix b/nixos/modules/config/iproute2.nix index 881ad671a627..a1d9ebcec66b 100644 --- a/nixos/modules/config/iproute2.nix +++ b/nixos/modules/config/iproute2.nix @@ -4,20 +4,29 @@ with lib; let cfg = config.networking.iproute2; - confDir = "/run/iproute2"; in { - options.networking.iproute2.enable = mkEnableOption "copy IP route configuration files"; - - config = mkMerge [ - ({ nixpkgs.config.iproute2.confDir = confDir; }) - - (mkIf cfg.enable { - system.activationScripts.iproute2 = '' - cp -R ${pkgs.iproute}/etc/iproute2 ${confDir} - chmod -R 664 ${confDir} - chmod +x ${confDir} + options.networking.iproute2 = { + enable = mkEnableOption "copy IP route configuration files"; + rttablesExtraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Verbatim lines to add to /etc/iproute2/rt_tables ''; - }) - ]; + }; + }; + + config = mkIf cfg.enable { + environment.etc."iproute2/bpf_pinning" = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/bpf_pinning"; }; + environment.etc."iproute2/ematch_map" = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/ematch_map"; }; + environment.etc."iproute2/group" = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/group"; }; + environment.etc."iproute2/nl_protos" = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/nl_protos"; }; + environment.etc."iproute2/rt_dsfield" = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/rt_dsfield"; }; + environment.etc."iproute2/rt_protos" = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/rt_protos"; }; + environment.etc."iproute2/rt_realms" = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/rt_realms"; }; + environment.etc."iproute2/rt_scopes" = { mode = "0644"; text = fileContents "${pkgs.iproute}/etc/iproute2/rt_scopes"; }; + environment.etc."iproute2/rt_tables" = { mode = "0644"; text = (fileContents "${pkgs.iproute}/etc/iproute2/rt_tables") + + (optionalString (cfg.rttablesExtraConfig != "") "\n\n${cfg.rttablesExtraConfig}"); }; + }; } diff --git a/nixos/modules/config/krb5/default.nix b/nixos/modules/config/krb5/default.nix index c22e99a0a2f1..87021a27d34f 100644 --- a/nixos/modules/config/krb5/default.nix +++ b/nixos/modules/config/krb5/default.nix @@ -79,7 +79,7 @@ in { options = { krb5 = { - enable = mkEnableOption "Whether to enable Kerberos V."; + enable = mkEnableOption "building krb5.conf, configuration file for Kerberos V"; kerberos = mkOption { type = types.package; diff --git a/nixos/modules/config/networking.nix b/nixos/modules/config/networking.nix index 1ef5313d3fdd..627cce67e97d 100644 --- a/nixos/modules/config/networking.nix +++ b/nixos/modules/config/networking.nix @@ -16,6 +16,13 @@ let resolvconfOptions = cfg.resolvconfOptions ++ optional cfg.dnsSingleRequest "single-request" ++ optional cfg.dnsExtensionMechanism "edns0"; + + + localhostMapped4 = cfg.hosts ? "127.0.0.1" && elem "localhost" cfg.hosts."127.0.0.1"; + localhostMapped6 = cfg.hosts ? "::1" && elem "localhost" cfg.hosts."::1"; + + localhostMultiple = any (elem "localhost") (attrValues (removeAttrs cfg.hosts [ "127.0.0.1" "::1" ])); + in { @@ -23,8 +30,7 @@ in options = { networking.hosts = lib.mkOption { - type = types.attrsOf ( types.listOf types.str ); - default = {}; + type = types.attrsOf (types.listOf types.str); example = literalExample '' { "127.0.0.1" = [ "foo.bar.baz" ]; @@ -192,6 +198,29 @@ in config = { + assertions = [{ + assertion = localhostMapped4; + message = ''`networking.hosts` doesn't map "127.0.0.1" to "localhost"''; + } { + assertion = !cfg.enableIPv6 || localhostMapped6; + message = ''`networking.hosts` doesn't map "::1" to "localhost"''; + } { + assertion = !localhostMultiple; + message = '' + `networking.hosts` maps "localhost" to something other than "127.0.0.1" + or "::1". This will break some applications. Please use + `networking.extraHosts` if you really want to add such a mapping. + ''; + }]; + + networking.hosts = { + "127.0.0.1" = [ "localhost" ]; + } // optionalAttrs (cfg.hostName != "") { + "127.0.1.1" = [ cfg.hostName ]; + } // optionalAttrs cfg.enableIPv6 { + "::1" = [ "localhost" ]; + }; + environment.etc = { # /etc/services: TCP/UDP port assignments. "services".source = pkgs.iana-etc + "/etc/services"; @@ -199,29 +228,14 @@ in # /etc/protocols: IP protocol numbers. "protocols".source = pkgs.iana-etc + "/etc/protocols"; - # /etc/rpc: RPC program numbers. - "rpc".source = pkgs.glibc.out + "/etc/rpc"; - # /etc/hosts: Hostname-to-IP mappings. - "hosts".text = - let oneToString = set : ip : ip + " " + concatStringsSep " " ( getAttr ip set ); - allToString = set : concatMapStringsSep "\n" ( oneToString set ) ( attrNames set ); - userLocalHosts = optionalString - ( builtins.hasAttr "127.0.0.1" cfg.hosts ) - ( concatStringsSep " " ( remove "localhost" cfg.hosts."127.0.0.1" )); - userLocalHosts6 = optionalString - ( builtins.hasAttr "::1" cfg.hosts ) - ( concatStringsSep " " ( remove "localhost" cfg.hosts."::1" )); - otherHosts = allToString ( removeAttrs cfg.hosts [ "127.0.0.1" "::1" ]); - in - '' - 127.0.0.1 ${userLocalHosts} localhost - ${optionalString cfg.enableIPv6 '' - ::1 ${userLocalHosts6} localhost - ''} - ${otherHosts} - ${cfg.extraHosts} - ''; + "hosts".text = let + oneToString = set: ip: ip + " " + concatStringsSep " " set.${ip}; + allToString = set: concatMapStringsSep "\n" (oneToString set) (attrNames set); + in '' + ${allToString cfg.hosts} + ${cfg.extraHosts} + ''; # /etc/host.conf: resolver configuration file "host.conf".text = cfg.hostConf; @@ -251,6 +265,9 @@ in "resolv.conf".source = "${pkgs.systemd}/lib/systemd/resolv.conf"; } // optionalAttrs (config.services.resolved.enable && dnsmasqResolve) { "dnsmasq-resolv.conf".source = "/run/systemd/resolve/resolv.conf"; + } // optionalAttrs (pkgs.stdenv.hostPlatform.libc == "glibc") { + # /etc/rpc: RPC program numbers. + "rpc".source = pkgs.glibc.out + "/etc/rpc"; }; networking.proxy.envVars = @@ -296,4 +313,4 @@ in }; - } +} diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix index e16a021ec20b..d4aa59506295 100644 --- a/nixos/modules/config/pulseaudio.nix +++ b/nixos/modules/config/pulseaudio.nix @@ -154,6 +154,18 @@ in { ''; }; + extraModules = mkOption { + type = types.listOf types.package; + default = []; + example = literalExample "[ pkgs.pulseaudio-modules-bt ]"; + description = '' + Extra pulseaudio modules to use. This is intended for out-of-tree + pulseaudio modules like extra bluetooth codecs. + + Extra modules take precedence over built-in pulseaudio modules. + ''; + }; + daemon = { logLevel = mkOption { type = types.str; @@ -236,6 +248,18 @@ in { systemd.packages = [ overriddenPackage ]; }) + (mkIf (cfg.extraModules != []) { + hardware.pulseaudio.daemon.config.dl-search-path = let + overriddenModules = builtins.map + (drv: drv.override { pulseaudio = overriddenPackage; }) + cfg.extraModules; + modulePaths = builtins.map + (drv: "${drv}/lib/pulse-${overriddenPackage.version}/modules") + # User-provided extra modules take precedence + (overriddenModules ++ [ overriddenPackage ]); + in lib.concatStringsSep ":" modulePaths; + }) + (mkIf hasZeroconf { services.avahi.enable = true; }) diff --git a/nixos/modules/config/shells-environment.nix b/nixos/modules/config/shells-environment.nix index 31adc9b82620..6379b52870ea 100644 --- a/nixos/modules/config/shells-environment.nix +++ b/nixos/modules/config/shells-environment.nix @@ -108,14 +108,14 @@ in }; environment.shellAliases = mkOption { - default = {}; - example = { ll = "ls -l"; }; + example = { l = null; ll = "ls -l"; }; description = '' An attribute set that maps aliases (the top level attribute names in this option) to command strings or directly to build outputs. The aliases are added to all users' shells. + Aliases mapped to <code>null</code> are ignored. ''; - type = types.attrs; # types.attrsOf types.stringOrPath; + type = with types; attrsOf (nullOr (either str path)); }; environment.binsh = mkOption { @@ -157,21 +157,36 @@ in # terminal instead of logging out of X11). environment.variables = config.environment.sessionVariables; + environment.shellAliases = mapAttrs (name: mkDefault) { + ls = "ls --color=tty"; + ll = "ls -l"; + l = "ls -alh"; + }; + environment.etc."shells".text = '' ${concatStringsSep "\n" (map utils.toShellPath cfg.shells)} /bin/sh ''; + # For resetting environment with `. /etc/set-environment` when needed + # and discoverability (see motivation of #30418). + environment.etc."set-environment".source = config.system.build.setEnvironment; + system.build.setEnvironment = pkgs.writeText "set-environment" - '' - ${exportedEnvVars} + '' + # DO NOT EDIT -- this file has been generated automatically. + + # Prevent this file from being sourced by child shells. + export __NIXOS_SET_ENVIRONMENT_DONE=1 - ${cfg.extraInit} + ${exportedEnvVars} - # ~/bin if it exists overrides other bin directories. - export PATH="$HOME/bin:$PATH" - ''; + ${cfg.extraInit} + + # ~/bin if it exists overrides other bin directories. + export PATH="$HOME/bin:$PATH" + ''; system.activationScripts.binsh = stringAfter [ "stdio" ] '' diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix index ffb437491f6c..1793dc628edf 100644 --- a/nixos/modules/config/system-path.nix +++ b/nixos/modules/config/system-path.nix @@ -13,13 +13,15 @@ let pkgs.attr pkgs.bashInteractive # bash with ncurses support pkgs.bzip2 - pkgs.coreutils + pkgs.coreutils-full pkgs.cpio pkgs.curl pkgs.diffutils pkgs.findutils pkgs.gawk - pkgs.glibc # for ldd, getent + pkgs.stdenv.cc.libc + pkgs.getent + pkgs.getconf pkgs.gnugrep pkgs.gnupatch pkgs.gnused @@ -140,7 +142,7 @@ in if [ -x $out/bin/glib-compile-schemas -a -w $out/share/glib-2.0/schemas ]; then $out/bin/glib-compile-schemas $out/share/glib-2.0/schemas fi - + ${config.environment.extraSetup} ''; }; diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index 426e1666a814..137ee243813d 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -266,7 +266,7 @@ let (mkIf config.isNormalUser { group = mkDefault "users"; createHome = mkDefault true; - home = mkDefault "/home/${name}"; + home = mkDefault "/home/${config.name}"; useDefaultShell = mkDefault true; isSystemUser = mkDefault false; }) diff --git a/nixos/modules/config/xdg/mime.nix b/nixos/modules/config/xdg/mime.nix index f1b672234a34..cd1064630fbc 100644 --- a/nixos/modules/config/xdg/mime.nix +++ b/nixos/modules/config/xdg/mime.nix @@ -7,7 +7,7 @@ with lib; type = types.bool; default = true; description = '' - Whether to install files to support the + Whether to install files to support the <link xlink:href="https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html">XDG Shared MIME-info specification</link> and the <link xlink:href="https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html">XDG MIME Applications specification</link>. ''; @@ -17,18 +17,18 @@ with lib; config = mkIf config.xdg.mime.enable { environment.pathsToLink = [ "/share/mime" ]; - environment.systemPackages = [ - # this package also installs some useful data, as well as its utilities - pkgs.shared-mime-info + environment.systemPackages = [ + # this package also installs some useful data, as well as its utilities + pkgs.shared-mime-info ]; environment.extraSetup = '' - if [ -w $out/share/mime ]; then - XDG_DATA_DIRS=$out/share ${pkgs.shared-mime-info}/bin/update-mime-database -V $out/share/mime > /dev/null + if [ -w $out/share/mime ] && [ -d $out/share/mime/packages ]; then + XDG_DATA_DIRS=$out/share ${pkgs.buildPackages.shared-mime-info}/bin/update-mime-database -V $out/share/mime > /dev/null fi if [ -w $out/share/applications ]; then - ${pkgs.desktop-file-utils}/bin/update-desktop-database $out/share/applications + ${pkgs.buildPackages.desktop-file-utils}/bin/update-desktop-database $out/share/applications fi ''; }; diff --git a/nixos/modules/hardware/opengl.nix b/nixos/modules/hardware/opengl.nix index b371af353cf9..46d06d71333a 100644 --- a/nixos/modules/hardware/opengl.nix +++ b/nixos/modules/hardware/opengl.nix @@ -129,17 +129,17 @@ in message = "Option driSupport32Bit only makes sense on a 64-bit system."; }; - system.activationScripts.setup-opengl = - '' - ln -sfn ${package} /run/opengl-driver - ${if pkgs.stdenv.isi686 then '' - ln -sfn opengl-driver /run/opengl-driver-32 - '' else if cfg.driSupport32Bit then '' - ln -sfn ${package32} /run/opengl-driver-32 - '' else '' - rm -f /run/opengl-driver-32 - ''} - ''; + systemd.tmpfiles.rules = [ + "L+ /run/opengl-driver - - - - ${package}" + ( + if pkgs.stdenv.isi686 then + "L+ /run/opengl-driver-32 - - - - opengl-driver" + else if cfg.driSupport32Bit then + "L+ /run/opengl-driver-32 - - - - ${package32}" + else + "r /run/opengl-driver-32" + ) + ]; environment.sessionVariables.LD_LIBRARY_PATH = [ "/run/opengl-driver/lib" ] ++ optional cfg.driSupport32Bit "/run/opengl-driver-32/lib"; diff --git a/nixos/modules/hardware/steam-hardware.nix b/nixos/modules/hardware/steam-hardware.nix new file mode 100644 index 000000000000..378aeffe71b5 --- /dev/null +++ b/nixos/modules/hardware/steam-hardware.nix @@ -0,0 +1,25 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.hardware.steam-hardware; + +in + +{ + options.hardware.steam-hardware = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable udev rules for Steam hardware such as the Steam Controller, other supported controllers and the HTC Vive"; + }; + }; + + config = mkIf cfg.enable { + services.udev.packages = [ + pkgs.steamPackages.steam + ]; + }; +} diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix index eb1952280331..f8524ab99e8a 100644 --- a/nixos/modules/hardware/video/nvidia.nix +++ b/nixos/modules/hardware/video/nvidia.nix @@ -1,6 +1,6 @@ # This module provides the proprietary NVIDIA X11 / OpenGL drivers. -{ config, lib, pkgs, pkgs_i686, ... }: +{ stdenv, config, lib, pkgs, pkgs_i686, ... }: with lib; @@ -23,35 +23,149 @@ let else null; nvidia_x11 = nvidiaForKernel config.boot.kernelPackages; - nvidia_libs32 = (nvidiaForKernel pkgs_i686.linuxPackages).override { libsOnly = true; kernel = null; }; + nvidia_libs32 = + if versionOlder nvidia_x11.version "391" then + ((nvidiaForKernel pkgs_i686.linuxPackages).override { libsOnly = true; kernel = null; }).out + else + (nvidiaForKernel config.boot.kernelPackages).lib32; enabled = nvidia_x11 != null; + + cfg = config.hardware.nvidia; + optimusCfg = cfg.optimus_prime; in { + options = { + hardware.nvidia.modesetting.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable kernel modesetting when using the NVIDIA proprietary driver. + + Enabling this fixes screen tearing when using Optimus via PRIME (see + <option>hardware.nvidia.optimus_prime.enable</option>. This is not enabled + by default because it is not officially supported by NVIDIA and would not + work with SLI. + ''; + }; + + hardware.nvidia.optimus_prime.enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable NVIDIA Optimus support using the NVIDIA proprietary driver via PRIME. + If enabled, the NVIDIA GPU will be always on and used for all rendering, + while enabling output to displays attached only to the integrated Intel GPU + without a multiplexer. + + Note that this option only has any effect if the "nvidia" driver is specified + in <option>services.xserver.videoDrivers</option>, and it should preferably + be the only driver there. + + If this is enabled, then the bus IDs of the NVIDIA and Intel GPUs have to be + specified (<option>hardware.nvidia.optimus_prime.nvidiaBusId</option> and + <option>hardware.nvidia.optimus_prime.intelBusId</option>). + + If you enable this, you may want to also enable kernel modesetting for the + NVIDIA driver (<option>hardware.nvidia.modesetting.enable</option>) in order + to prevent tearing. + + Note that this configuration will only be successful when a display manager + for which the <option>services.xserver.displayManager.setupCommands</option> + option is supported is used; notably, SLiM is not supported. + ''; + }; + + hardware.nvidia.optimus_prime.nvidiaBusId = lib.mkOption { + type = lib.types.string; + default = ""; + example = "PCI:1:0:0"; + description = '' + Bus ID of the NVIDIA GPU. You can find it using lspci; for example if lspci + shows the NVIDIA GPU at "01:00.0", set this option to "PCI:1:0:0". + ''; + }; + + hardware.nvidia.optimus_prime.intelBusId = lib.mkOption { + type = lib.types.string; + default = ""; + example = "PCI:0:2:0"; + description = '' + Bus ID of the Intel GPU. You can find it using lspci; for example if lspci + shows the Intel GPU at "00:02.0", set this option to "PCI:0:2:0". + ''; + }; + }; config = mkIf enabled { assertions = [ { assertion = config.services.xserver.displayManager.gdm.wayland; - message = "NVidia drivers don't support wayland"; + message = "NVIDIA drivers don't support wayland"; + } + { + assertion = !optimusCfg.enable || + (optimusCfg.nvidiaBusId != "" && optimusCfg.intelBusId != ""); + message = '' + When NVIDIA Optimus via PRIME is enabled, the GPU bus IDs must configured. + ''; } ]; - services.xserver.drivers = singleton - { name = "nvidia"; modules = [ nvidia_x11.bin ]; libPath = [ nvidia_x11 ]; }; + # If Optimus/PRIME is enabled, we: + # - Specify the configured NVIDIA GPU bus ID in the Device section for the + # "nvidia" driver. + # - Add the AllowEmptyInitialConfiguration option to the Screen section for the + # "nvidia" driver, in order to allow the X server to start without any outputs. + # - Add a separate Device section for the Intel GPU, using the "modesetting" + # driver and with the configured BusID. + # - Reference that Device section from the ServerLayout section as an inactive + # device. + # - Configure the display manager to run specific `xrandr` commands which will + # configure/enable displays connected to the Intel GPU. + + services.xserver.drivers = singleton { + name = "nvidia"; + modules = [ nvidia_x11.bin ]; + libPath = [ nvidia_x11 ]; + deviceSection = optionalString optimusCfg.enable + '' + BusID "${optimusCfg.nvidiaBusId}" + ''; + screenSection = + '' + Option "RandRRotation" "on" + ${optionalString optimusCfg.enable "Option \"AllowEmptyInitialConfiguration\""} + ''; + }; - services.xserver.screenSection = + services.xserver.extraConfig = optionalString optimusCfg.enable + '' + Section "Device" + Identifier "nvidia-optimus-intel" + Driver "modesetting" + BusID "${optimusCfg.intelBusId}" + Option "AccelMethod" "none" + EndSection + ''; + services.xserver.serverLayoutSection = optionalString optimusCfg.enable '' - Option "RandRRotation" "on" + Inactive "nvidia-optimus-intel" ''; + services.xserver.displayManager.setupCommands = optionalString optimusCfg.enable '' + # Added by nvidia configuration module for Optimus/PRIME. + ${pkgs.xorg.xrandr}/bin/xrandr --setprovideroutputsource modesetting NVIDIA-0 + ${pkgs.xorg.xrandr}/bin/xrandr --auto + ''; + environment.etc."nvidia/nvidia-application-profiles-rc" = mkIf nvidia_x11.useProfiles { source = "${nvidia_x11.bin}/share/nvidia/nvidia-application-profiles-rc"; }; hardware.opengl.package = nvidia_x11.out; - hardware.opengl.package32 = nvidia_libs32.out; + hardware.opengl.package32 = nvidia_libs32; environment.systemPackages = [ nvidia_x11.bin nvidia_x11.settings ] ++ lib.filter (p: p != null) [ nvidia_x11.persistenced ]; @@ -62,6 +176,8 @@ in boot.kernelModules = [ "nvidia-uvm" ] ++ lib.optionals config.services.xserver.enable [ "nvidia" "nvidia_modeset" "nvidia_drm" ]; + # If requested enable modesetting via kernel parameter. + boot.kernelParams = optional cfg.modesetting.enable "nvidia-drm.modeset=1"; # Create /dev/nvidia-uvm when the nvidia-uvm module is loaded. services.udev.extraRules = diff --git a/nixos/modules/i18n/input-method/default.xml b/nixos/modules/i18n/input-method/default.xml index ab918a9fb23e..117482fb0d57 100644 --- a/nixos/modules/i18n/input-method/default.xml +++ b/nixos/modules/i18n/input-method/default.xml @@ -3,32 +3,50 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="module-services-input-methods"> - -<title>Input Methods</title> - -<para>Input methods are an operating system component that allows any data, such - as keyboard strokes or mouse movements, to be received as input. In this way - users can enter characters and symbols not found on their input devices. Using - an input method is obligatory for any language that has more graphemes than - there are keys on the keyboard.</para> - -<para>The following input methods are available in NixOS:</para> - -<itemizedlist> - <listitem><para>IBus: The intelligent input bus.</para></listitem> - <listitem><para>Fcitx: A customizable lightweight input - method.</para></listitem> - <listitem><para>Nabi: A Korean input method based on XIM.</para></listitem> - <listitem><para>Uim: The universal input method, is a library with a XIM - bridge.</para></listitem> -</itemizedlist> - -<section xml:id="module-services-input-methods-ibus"><title>IBus</title> - -<para>IBus is an Intelligent Input Bus. It provides full featured and user - friendly input method user interface.</para> - -<para>The following snippet can be used to configure IBus:</para> + <title>Input Methods</title> + <para> + Input methods are an operating system component that allows any data, such as + keyboard strokes or mouse movements, to be received as input. In this way + users can enter characters and symbols not found on their input devices. + Using an input method is obligatory for any language that has more graphemes + than there are keys on the keyboard. + </para> + <para> + The following input methods are available in NixOS: + </para> + <itemizedlist> + <listitem> + <para> + IBus: The intelligent input bus. + </para> + </listitem> + <listitem> + <para> + Fcitx: A customizable lightweight input method. + </para> + </listitem> + <listitem> + <para> + Nabi: A Korean input method based on XIM. + </para> + </listitem> + <listitem> + <para> + Uim: The universal input method, is a library with a XIM bridge. + </para> + </listitem> + </itemizedlist> + <section xml:id="module-services-input-methods-ibus"> + <title>IBus</title> + + <para> + IBus is an Intelligent Input Bus. It provides full featured and user + friendly input method user interface. + </para> + + <para> + The following snippet can be used to configure IBus: + </para> <programlisting> i18n.inputMethod = { @@ -37,57 +55,89 @@ i18n.inputMethod = { }; </programlisting> -<para><literal>i18n.inputMethod.ibus.engines</literal> is optional and can be - used to add extra IBus engines.</para> - -<para>Available extra IBus engines are:</para> - -<itemizedlist> - <listitem><para>Anthy (<literal>ibus-engines.anthy</literal>): Anthy is a - system for Japanese input method. It converts Hiragana text to Kana Kanji - mixed text.</para></listitem> - <listitem><para>Hangul (<literal>ibus-engines.hangul</literal>): Korean input - method.</para></listitem> - <listitem><para>m17n (<literal>ibus-engines.m17n</literal>): m17n is an input - method that uses input methods and corresponding icons in the m17n - database.</para></listitem> - <listitem><para>mozc (<literal>ibus-engines.mozc</literal>): A Japanese input - method from Google.</para></listitem> - <listitem><para>Table (<literal>ibus-engines.table</literal>): An input method - that load tables of input methods.</para></listitem> - <listitem><para>table-others (<literal>ibus-engines.table-others</literal>): - Various table-based input methods. To use this, and any other table-based - input methods, it must appear in the list of engines along with - <literal>table</literal>. For example: + <para> + <literal>i18n.inputMethod.ibus.engines</literal> is optional and can be used + to add extra IBus engines. + </para> + + <para> + Available extra IBus engines are: + </para> + + <itemizedlist> + <listitem> + <para> + Anthy (<literal>ibus-engines.anthy</literal>): Anthy is a system for + Japanese input method. It converts Hiragana text to Kana Kanji mixed text. + </para> + </listitem> + <listitem> + <para> + Hangul (<literal>ibus-engines.hangul</literal>): Korean input method. + </para> + </listitem> + <listitem> + <para> + m17n (<literal>ibus-engines.m17n</literal>): m17n is an input method that + uses input methods and corresponding icons in the m17n database. + </para> + </listitem> + <listitem> + <para> + mozc (<literal>ibus-engines.mozc</literal>): A Japanese input method from + Google. + </para> + </listitem> + <listitem> + <para> + Table (<literal>ibus-engines.table</literal>): An input method that load + tables of input methods. + </para> + </listitem> + <listitem> + <para> + table-others (<literal>ibus-engines.table-others</literal>): Various + table-based input methods. To use this, and any other table-based input + methods, it must appear in the list of engines along with + <literal>table</literal>. For example: <programlisting> ibus.engines = with pkgs.ibus-engines; [ table table-others ]; </programlisting> - </para></listitem> -</itemizedlist> - -<para>To use any input method, the package must be added in the configuration, - as shown above, and also (after running <literal>nixos-rebuild</literal>) the - input method must be added from IBus' preference dialog.</para> - -<simplesect xml:id="module-services-input-methods-troubleshooting"> - <title>Troubleshooting</title> - <para>If IBus works in some applications but not others, a likely cause of - this is that IBus is depending on a different version of - <literal>glib</literal> to what the applications are depending on. This can - be checked by running <literal>nix-store -q --requisites <path> | grep - glib</literal>, where <literal><path></literal> is the path of either - IBus or an application in the Nix store. The <literal>glib</literal> - packages must match exactly. If they do not, uninstalling and reinstalling - the application is a likely fix.</para> -</simplesect> -</section> - -<section xml:id="module-services-input-methods-fcitx"><title>Fcitx</title> - -<para>Fcitx is an input method framework with extension support. It has three - built-in Input Method Engine, Pinyin, QuWei and Table-based input - methods.</para> -<para>The following snippet can be used to configure Fcitx:</para> + </para> + </listitem> + </itemizedlist> + + <para> + To use any input method, the package must be added in the configuration, as + shown above, and also (after running <literal>nixos-rebuild</literal>) the + input method must be added from IBus' preference dialog. + </para> + + <simplesect xml:id="module-services-input-methods-troubleshooting"> + <title>Troubleshooting</title> + <para> + If IBus works in some applications but not others, a likely cause of this + is that IBus is depending on a different version of <literal>glib</literal> + to what the applications are depending on. This can be checked by running + <literal>nix-store -q --requisites <path> | grep glib</literal>, + where <literal><path></literal> is the path of either IBus or an + application in the Nix store. The <literal>glib</literal> packages must + match exactly. If they do not, uninstalling and reinstalling the + application is a likely fix. + </para> + </simplesect> + </section> + <section xml:id="module-services-input-methods-fcitx"> + <title>Fcitx</title> + + <para> + Fcitx is an input method framework with extension support. It has three + built-in Input Method Engine, Pinyin, QuWei and Table-based input methods. + </para> + + <para> + The following snippet can be used to configure Fcitx: + </para> <programlisting> i18n.inputMethod = { @@ -96,51 +146,89 @@ i18n.inputMethod = { }; </programlisting> -<para><literal>i18n.inputMethod.fcitx.engines</literal> is optional and can be - used to add extra Fcitx engines.</para> - -<para>Available extra Fcitx engines are:</para> - -<itemizedlist> - <listitem><para>Anthy (<literal>fcitx-engines.anthy</literal>): Anthy is a - system for Japanese input method. It converts Hiragana text to Kana Kanji - mixed text.</para></listitem> - <listitem><para>Chewing (<literal>fcitx-engines.chewing</literal>): Chewing is - an intelligent Zhuyin input method. It is one of the most popular input - methods among Traditional Chinese Unix users.</para></listitem> - <listitem><para>Hangul (<literal>fcitx-engines.hangul</literal>): Korean input - method.</para></listitem> - <listitem><para>Unikey (<literal>fcitx-engines.unikey</literal>): Vietnamese input - method.</para></listitem> - <listitem><para>m17n (<literal>fcitx-engines.m17n</literal>): m17n is an input - method that uses input methods and corresponding icons in the m17n - database.</para></listitem> - <listitem><para>mozc (<literal>fcitx-engines.mozc</literal>): A Japanese input - method from Google.</para></listitem> - <listitem><para>table-others (<literal>fcitx-engines.table-others</literal>): - Various table-based input methods.</para></listitem> -</itemizedlist> -</section> - -<section xml:id="module-services-input-methods-nabi"><title>Nabi</title> - -<para>Nabi is an easy to use Korean X input method. It allows you to enter - phonetic Korean characters (hangul) and pictographic Korean characters - (hanja).</para> -<para>The following snippet can be used to configure Nabi:</para> + <para> + <literal>i18n.inputMethod.fcitx.engines</literal> is optional and can be + used to add extra Fcitx engines. + </para> + + <para> + Available extra Fcitx engines are: + </para> + + <itemizedlist> + <listitem> + <para> + Anthy (<literal>fcitx-engines.anthy</literal>): Anthy is a system for + Japanese input method. It converts Hiragana text to Kana Kanji mixed text. + </para> + </listitem> + <listitem> + <para> + Chewing (<literal>fcitx-engines.chewing</literal>): Chewing is an + intelligent Zhuyin input method. It is one of the most popular input + methods among Traditional Chinese Unix users. + </para> + </listitem> + <listitem> + <para> + Hangul (<literal>fcitx-engines.hangul</literal>): Korean input method. + </para> + </listitem> + <listitem> + <para> + Unikey (<literal>fcitx-engines.unikey</literal>): Vietnamese input method. + </para> + </listitem> + <listitem> + <para> + m17n (<literal>fcitx-engines.m17n</literal>): m17n is an input method that + uses input methods and corresponding icons in the m17n database. + </para> + </listitem> + <listitem> + <para> + mozc (<literal>fcitx-engines.mozc</literal>): A Japanese input method from + Google. + </para> + </listitem> + <listitem> + <para> + table-others (<literal>fcitx-engines.table-others</literal>): Various + table-based input methods. + </para> + </listitem> + </itemizedlist> + </section> + <section xml:id="module-services-input-methods-nabi"> + <title>Nabi</title> + + <para> + Nabi is an easy to use Korean X input method. It allows you to enter + phonetic Korean characters (hangul) and pictographic Korean characters + (hanja). + </para> + + <para> + The following snippet can be used to configure Nabi: + </para> <programlisting> i18n.inputMethod = { <link linkend="opt-i18n.inputMethod.enabled">enabled</link> = "nabi"; }; </programlisting> -</section> + </section> + <section xml:id="module-services-input-methods-uim"> + <title>Uim</title> -<section xml:id="module-services-input-methods-uim"><title>Uim</title> + <para> + Uim (short for "universal input method") is a multilingual input method + framework. Applications can use it through so-called bridges. + </para> -<para>Uim (short for "universal input method") is a multilingual input method - framework. Applications can use it through so-called bridges.</para> -<para>The following snippet can be used to configure uim:</para> + <para> + The following snippet can be used to configure uim: + </para> <programlisting> i18n.inputMethod = { @@ -148,8 +236,9 @@ i18n.inputMethod = { }; </programlisting> -<para>Note: The <xref linkend="opt-i18n.inputMethod.uim.toolbar"/> option can be - used to choose uim toolbar.</para> - -</section> + <para> + Note: The <xref linkend="opt-i18n.inputMethod.uim.toolbar"/> option can be + used to choose uim toolbar. + </para> + </section> </chapter> diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix new file mode 100644 index 000000000000..228ef371d252 --- /dev/null +++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-base.nix @@ -0,0 +1,49 @@ +# This module contains the basic configuration for building a graphical NixOS +# installation CD. + +{ config, lib, pkgs, ... }: + +with lib; + +{ + imports = [ ./installation-cd-base.nix ]; + + services.xserver = { + enable = true; + + # Don't start the X server by default. + autorun = mkForce false; + + # Automatically login as root. + displayManager.slim = { + enable = true; + defaultUser = "root"; + autoLogin = true; + }; + + }; + + # Provide networkmanager for easy wireless configuration. + networking.networkmanager.enable = true; + networking.wireless.enable = mkForce false; + + # KDE complains if power management is disabled (to be precise, if + # there is no power management backend such as upower). + powerManagement.enable = true; + + environment.systemPackages = [ + # Include gparted for partitioning disks. + pkgs.gparted + + # Include some editors. + pkgs.vim + pkgs.bvi # binary editor + pkgs.joe + + # Firefox for reading the manual. + pkgs.firefox + + pkgs.glxinfo + ]; + +} diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix index 4c4e69d60d9c..42b5ec882272 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-gnome.nix @@ -6,47 +6,11 @@ with lib; { - imports = [ ./installation-cd-base.nix ]; + imports = [ ./installation-cd-graphical-base.nix ]; - services.xserver = { - enable = true; - # GDM doesn't start in virtual machines with ISO - displayManager.slim = { - enable = true; - defaultUser = "root"; - autoLogin = true; - }; - desktopManager.gnome3 = { - enable = true; - extraGSettingsOverrides = '' - [org.gnome.desktop.background] - show-desktop-icons=true - - [org.gnome.nautilus.desktop] - trash-icon-visible=false - volumes-visible=false - home-icon-visible=false - network-icon-visible=false - ''; - - extraGSettingsOverridePackages = [ pkgs.gnome3.nautilus ]; - }; - }; - - environment.systemPackages = - [ # Include gparted for partitioning disks. - pkgs.gparted + services.xserver.desktopManager.gnome3.enable = true; - # Include some editors. - pkgs.vim - pkgs.bvi # binary editor - pkgs.joe - - pkgs.glxinfo - ]; - - # Don't start the X server by default. - services.xserver.autorun = mkForce false; + services.xserver.displayManager.slim.enable = mkForce false; # Auto-login as root. services.xserver.displayManager.gdm.autoLogin = { @@ -54,25 +18,4 @@ with lib; user = "root"; }; - system.activationScripts.installerDesktop = let - # Must be executable - desktopFile = pkgs.writeScript "nixos-manual.desktop" '' - [Desktop Entry] - Version=1.0 - Type=Link - Name=NixOS Manual - URL=${config.system.build.manual.manual}/share/doc/nixos/index.html - Icon=system-help - ''; - - # use cp and chmod +x, we must be sure the apps are in the nix store though - in '' - mkdir -p /root/Desktop - ln -sfT ${desktopFile} /root/Desktop/nixos-manual.desktop - cp ${pkgs.gnome3.gnome-terminal}/share/applications/gnome-terminal.desktop /root/Desktop/gnome-terminal.desktop - chmod a+rx /root/Desktop/gnome-terminal.desktop - cp ${pkgs.gparted}/share/applications/gparted.desktop /root/Desktop/gparted.desktop - chmod a+rx /root/Desktop/gparted.desktop - ''; - } diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix index 63227d573495..1c3c9cb30b41 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-kde.nix @@ -1,23 +1,14 @@ # This module defines a NixOS installation CD that contains X11 and -# KDE 5. +# Plasma5. { config, lib, pkgs, ... }: with lib; { - imports = [ ./installation-cd-base.nix ]; + imports = [ ./installation-cd-graphical-base.nix ]; services.xserver = { - enable = true; - - # Automatically login as root. - displayManager.slim = { - enable = true; - defaultUser = "root"; - autoLogin = true; - }; - desktopManager.plasma5 = { enable = true; enableQt4Support = false; @@ -27,45 +18,25 @@ with lib; synaptics.enable = true; }; - environment.systemPackages = - [ pkgs.glxinfo - - # Include gparted for partitioning disks. - pkgs.gparted - - # Firefox for reading the manual. - pkgs.firefox - - # Include some editors. - pkgs.vim - pkgs.bvi # binary editor - pkgs.joe - ]; - - # Provide networkmanager for easy wireless configuration. - networking.networkmanager.enable = true; - networking.wireless.enable = mkForce false; - - # KDE complains if power management is disabled (to be precise, if - # there is no power management backend such as upower). - powerManagement.enable = true; - - # Don't start the X server by default. - services.xserver.autorun = mkForce false; + environment.systemPackages = with pkgs; [ + # Graphical text editor + kate + ]; system.activationScripts.installerDesktop = let - desktopFile = pkgs.writeText "nixos-manual.desktop" '' + + manualDesktopFile = pkgs.writeScript "nixos-manual.desktop" '' [Desktop Entry] Version=1.0 Type=Application Name=NixOS Manual - Exec=firefox ${config.system.build.manual.manual}/share/doc/nixos/index.html + Exec=firefox ${config.system.build.manual.manualHTMLIndex} Icon=text-html ''; in '' mkdir -p /root/Desktop - ln -sfT ${desktopFile} /root/Desktop/nixos-manual.desktop + ln -sfT ${manualDesktopFile} /root/Desktop/nixos-manual.desktop ln -sfT ${pkgs.konsole}/share/applications/org.kde.konsole.desktop /root/Desktop/org.kde.konsole.desktop ln -sfT ${pkgs.gparted}/share/applications/gparted.desktop /root/Desktop/gparted.desktop ''; diff --git a/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix b/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix index 3dc0f606bf60..bcdbffdc20b7 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix @@ -7,4 +7,6 @@ imports = [ ./installation-cd-base.nix ]; + + fonts.fontconfig.enable = false; } diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index 98712f0759a9..96fdb997b2c0 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -233,7 +233,7 @@ let " # Make our own efi program, we can't rely on "grub-install" since it seems to # probe for devices, even with --skip-fs-probe. - ${pkgs.grub2_efi}/bin/grub-mkimage -o $out/EFI/boot/${if targetArch == "x64" then "bootx64" else "bootx32"}.efi -p /EFI/boot -O ${if targetArch == "x64" then "x86_64" else "i386"}-efi \ + ${pkgs.grub2_efi}/bin/grub-mkimage -o $out/EFI/boot/${if targetArch == "x64" then "bootx64" else "bootia32"}.efi -p /EFI/boot -O ${if targetArch == "x64" then "x86_64" else "i386"}-efi \ $MODULES cp ${pkgs.grub2_efi}/share/grub/unicode.pf2 $out/EFI/boot/ diff --git a/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix b/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix index 7ec09acd5919..90a5128c02a5 100644 --- a/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix +++ b/nixos/modules/installer/cd-dvd/system-tarball-sheevaplug.nix @@ -137,7 +137,7 @@ in # Setting vesa, we don't get the nvidia driver, which can't work in arm. services.xserver.videoDrivers = [ "vesa" ]; - services.nixosManual.enable = false; + documentation.nixos.enable = false; # Include the firmware for various wireless cards. networking.enableRalinkFirmware = true; diff --git a/nixos/modules/installer/tools/nix-fallback-paths.nix b/nixos/modules/installer/tools/nix-fallback-paths.nix index 7c5414257b46..1cfc8ff8612e 100644 --- a/nixos/modules/installer/tools/nix-fallback-paths.nix +++ b/nixos/modules/installer/tools/nix-fallback-paths.nix @@ -1,6 +1,6 @@ { - x86_64-linux = "/nix/store/0d60i73mcv8z1m8d2m74yfn84980gfsa-nix-2.0.4"; - i686-linux = "/nix/store/6ssafj2s5a2g9x28yld7b70vwd6vw6lb-nix-2.0.4"; - aarch64-linux = "/nix/store/3wwch7bp7n7xsl8apgy2a4b16yzyij1z-nix-2.0.4"; - x86_64-darwin = "/nix/store/771l8i0mz4c8kry8cz3sz8rr3alalckg-nix-2.0.4"; + x86_64-linux = "/nix/store/cdcia67siabmj6li7vyffgv2cry86fq8-nix-2.1.3"; + i686-linux = "/nix/store/6q3xi6y5qnsv7d62b8n00hqfxi8rs2xs-nix-2.1.3"; + aarch64-linux = "/nix/store/2v93d0vimlm28jg0ms6v1i6lc0fq13pn-nix-2.1.3"; + x86_64-darwin = "/nix/store/dkjlfkrknmxbjmpfk3dg4q3nmb7m3zvk-nix-2.1.3"; } diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl index 359caad89a72..b70faa380e54 100644 --- a/nixos/modules/installer/tools/nixos-generate-config.pl +++ b/nixos/modules/installer/tools/nixos-generate-config.pl @@ -277,8 +277,7 @@ if ($virt eq "qemu" || $virt eq "kvm" || $virt eq "bochs") { # Also for Hyper-V. if ($virt eq "microsoft") { - push @initrdAvailableKernelModules, "hv_storvsc"; - $videoDriver = "fbdev"; + push @attrs, "virtualisation.hypervGuest.enable = true;" } diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh index 22c1e0fe9a34..defc46ad2a72 100644 --- a/nixos/modules/installer/tools/nixos-install.sh +++ b/nixos/modules/installer/tools/nixos-install.sh @@ -13,6 +13,7 @@ extraBuildFlags=() mountPoint=/mnt channelPath= +system= while [ "$#" -gt 0 ]; do i="$1"; shift 1 diff --git a/nixos/modules/installer/tools/nixos-option.sh b/nixos/modules/installer/tools/nixos-option.sh index 3f1e591b97b0..327e3e6989f7 100644 --- a/nixos/modules/installer/tools/nixos-option.sh +++ b/nixos/modules/installer/tools/nixos-option.sh @@ -82,7 +82,7 @@ evalNix(){ set -e if test $exit_code -eq 0; then - cat <<EOF + sed '/^warning: Nix search path/d' <<EOF $result EOF return 0; @@ -90,7 +90,7 @@ EOF sed -n ' /^error/ { s/, at (string):[0-9]*:[0-9]*//; p; }; /^warning: Nix search path/ { p; }; -' <<EOF +' >&2 <<EOF $result EOF exit_code=1 diff --git a/nixos/modules/installer/virtualbox-demo.nix b/nixos/modules/installer/virtualbox-demo.nix index 8ca3592f3800..2e1b4b3998b5 100644 --- a/nixos/modules/installer/virtualbox-demo.nix +++ b/nixos/modules/installer/virtualbox-demo.nix @@ -22,4 +22,42 @@ with lib; powerManagement.enable = false; system.stateVersion = mkDefault "18.03"; + + installer.cloneConfigExtra = '' + # Let demo build as a trusted user. + # nix.trustedUsers = [ "demo" ]; + + # Mount a VirtualBox shared folder. + # This is configurable in the VirtualBox menu at + # Machine / Settings / Shared Folders. + # fileSystems."/mnt" = { + # fsType = "vboxsf"; + # device = "nameofdevicetomount"; + # options = [ "rw" ]; + # }; + + # By default, the NixOS VirtualBox demo image includes SDDM and Plasma. + # If you prefer another desktop manager or display manager, you may want + # to disable the default. + # services.xserver.desktopManager.plasma5.enable = lib.mkForce false; + # services.xserver.displayManager.sddm.enable = lib.mkForce false; + + # Enable GDM/GNOME by uncommenting above two lines and two lines below. + # services.xserver.displayManager.gdm.enable = true; + # services.xserver.desktopManager.gnome3.enable = true; + + # Set your time zone. + # time.timeZone = "Europe/Amsterdam"; + + # List packages installed in system profile. To search, run: + # \$ nix search wget + # environment.systemPackages = with pkgs; [ + # wget vim + # ]; + + # Enable the OpenSSH daemon. + # services.openssh.enable = true; + + system.stateVersion = mkDefault "18.03"; + ''; } diff --git a/nixos/modules/misc/documentation.nix b/nixos/modules/misc/documentation.nix index e6ccda5d7f40..09d53c322fb3 100644 --- a/nixos/modules/misc/documentation.nix +++ b/nixos/modules/misc/documentation.nix @@ -1,8 +1,72 @@ -{ config, lib, pkgs, ... }: +{ config, lib, pkgs, baseModules, ... }: with lib; -let cfg = config.documentation; in +let + + cfg = config.documentation; + + /* For the purpose of generating docs, evaluate options with each derivation + in `pkgs` (recursively) replaced by a fake with path "\${pkgs.attribute.path}". + It isn't perfect, but it seems to cover a vast majority of use cases. + Caveat: even if the package is reached by a different means, + the path above will be shown and not e.g. `${config.services.foo.package}`. */ + manual = import ../../doc/manual rec { + inherit pkgs config; + version = config.system.nixos.release; + revision = "release-${version}"; + options = + let + scrubbedEval = evalModules { + modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ baseModules; + args = (config._module.args) // { modules = [ ]; }; + specialArgs = { pkgs = scrubDerivations "pkgs" pkgs; }; + }; + scrubDerivations = namePrefix: pkgSet: mapAttrs + (name: value: + let wholeName = "${namePrefix}.${name}"; in + if isAttrs value then + scrubDerivations wholeName value + // (optionalAttrs (isDerivation value) { outPath = "\${${wholeName}}"; }) + else value + ) + pkgSet; + in scrubbedEval.options; + }; + + helpScript = pkgs.writeScriptBin "nixos-help" + '' + #! ${pkgs.runtimeShell} -e + # Finds first executable browser in a colon-separated list. + # (see how xdg-open defines BROWSER) + browser="$( + IFS=: ; for b in $BROWSER; do + [ -n "$(type -P "$b" || true)" ] && echo "$b" && break + done + )" + if [ -z "$browser" ]; then + browser="$(type -P xdg-open || true)" + if [ -z "$browser" ]; then + browser="$(type -P w3m || true)" + if [ -z "$browser" ]; then + echo "$0: unable to start a web browser; please set \$BROWSER" + exit 1 + fi + fi + fi + exec "$browser" ${manual.manualHTMLIndex} + ''; + + desktopItem = pkgs.makeDesktopItem { + name = "nixos-manual"; + desktopName = "NixOS Manual"; + genericName = "View NixOS documentation in a web browser"; + icon = "nix-snowflake"; + exec = "${helpScript}/bin/nixos-help"; + categories = "System"; + }; + +in { @@ -66,6 +130,22 @@ let cfg = config.documentation; in ''; }; + nixos.enable = mkOption { + type = types.bool; + default = true; + description = '' + Whether to install NixOS's own documentation. + <itemizedlist> + <listitem><para>This includes man pages like + <citerefentry><refentrytitle>configuration.nix</refentrytitle> + <manvolnum>5</manvolnum></citerefentry> if <option>man.enable</option> is + set.</para></listitem> + <listitem><para>This includes the HTML manual and the <command>nixos-help</command> command if + <option>doc.enable</option> is set.</para></listitem> + </itemizedlist> + ''; + }; + }; }; @@ -86,7 +166,7 @@ let cfg = config.documentation; in if [ -w $out/share/info ]; then shopt -s nullglob for i in $out/share/info/*.info $out/share/info/*.info.gz; do - ${pkgs.texinfo}/bin/install-info $i $out/share/info/dir + ${pkgs.buildPackages.texinfo}/bin/install-info $i $out/share/info/dir done fi ''; @@ -99,6 +179,21 @@ let cfg = config.documentation; in environment.extraOutputsToInstall = [ "doc" ] ++ optional cfg.dev.enable "devdoc"; }) + (mkIf cfg.nixos.enable { + system.build.manual = manual; + + environment.systemPackages = [] + ++ optional cfg.man.enable manual.manpages + ++ optionals cfg.doc.enable ([ manual.manualHTML helpScript ] + ++ optionals config.services.xserver.enable [ desktopItem pkgs.nixos-icons ]); + + services.mingetty.helpLine = mkIf cfg.doc.enable ( + "\nRun `nixos-help` " + + optionalString config.services.nixosManual.showManual "or press <Alt-F${toString config.services.nixosManual.ttyNumber}> " + + "for the NixOS manual." + ); + }) + ]); } diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 8292cdc995e0..a32e4fe3f7c8 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -53,7 +53,7 @@ tomcat = 16; #audio = 17; # unused #floppy = 18; # unused - #uucp = 19; # unused + uucp = 19; #lp = 20; # unused #proc = 21; # unused pulseaudio = 22; # must match `pulseaudio' GID @@ -289,7 +289,7 @@ stanchion = 262; riak-cs = 263; infinoted = 264; - # keystone = 265; # unused, removed 2017-12-13 + sickbeard = 265; # glance = 266; # unused, removed 2017-12-13 couchpotato = 267; gogs = 268; @@ -329,6 +329,9 @@ # kvm = 302; # unused # render = 303; # unused zeronet = 304; + lirc = 305; + lidarr = 306; + slurm = 307; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -383,7 +386,7 @@ virtuoso = 44; #rtkit = 45; # unused dovecot2 = 46; - #dovenull = 47; # unused + dovenull2 = 47; prayer = 49; mpd = 50; clamav = 51; @@ -579,7 +582,7 @@ stanchion = 262; riak-cs = 263; infinoted = 264; - # keystone = 265; # unused, removed 2017-12-13 + sickbeard = 265; # glance = 266; # unused, removed 2017-12-13 couchpotato = 267; gogs = 268; @@ -618,6 +621,9 @@ kvm = 302; # default udev rules from systemd requires these render = 303; # default udev rules from systemd requires these zeronet = 304; + lirc = 305; + lidarr = 306; + slurm = 307; # 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/version.nix b/nixos/modules/misc/version.nix index 63717e0c6a81..6d78b7c593f8 100644 --- a/nixos/modules/misc/version.nix +++ b/nixos/modules/misc/version.nix @@ -5,7 +5,6 @@ with lib; let cfg = config.system.nixos; - revisionFile = "${toString pkgs.path}/.git-revision"; gitRepo = "${toString pkgs.path}/.git"; gitCommitId = lib.substring 0 7 (commitIdFromGitRepo gitRepo); in @@ -37,9 +36,7 @@ in nixos.revision = mkOption { internal = true; type = types.str; - default = if pathIsDirectory gitRepo then commitIdFromGitRepo gitRepo - else if pathExists revisionFile then fileContents revisionFile - else "master"; + default = lib.trivial.revisionWithDefault "master"; description = "The Git revision from which this NixOS configuration was built."; }; @@ -84,7 +81,7 @@ in versionSuffix = mkIf (pathIsDirectory gitRepo) (mkDefault (".git." + gitCommitId)); # Note: the first letter is bumped on every release. It's an animal. - codeName = "Jellyfish"; + codeName = "Koi"; }; # Generate /etc/os-release. See diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 4795922abcfb..660644eade8d 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -46,6 +46,7 @@ ./hardware/opengl.nix ./hardware/pcmcia.nix ./hardware/raid/hpsa.nix + ./hardware/steam-hardware.nix ./hardware/usb-wwan.nix ./hardware/onlykey.nix ./hardware/video/amdgpu.nix @@ -107,7 +108,6 @@ ./programs/oblogout.nix ./programs/plotinus.nix ./programs/qt5ct.nix - ./programs/rootston.nix ./programs/screen.nix ./programs/sedutil.nix ./programs/slock.nix @@ -120,11 +120,13 @@ ./programs/sysdig.nix ./programs/systemtap.nix ./programs/sway.nix + ./programs/sway-beta.nix ./programs/thefuck.nix ./programs/tmux.nix ./programs/udevil.nix ./programs/venus.nix ./programs/vim.nix + ./programs/wavemon.nix ./programs/way-cooler.nix ./programs/wireshark.nix ./programs/xfs_quota.nix @@ -148,6 +150,7 @@ ./security/duosec.nix ./security/hidepid.nix ./security/lock-kernel-modules.nix + ./security/misc.nix ./security/oath.nix ./security/pam.nix ./security/pam_usb.nix @@ -232,6 +235,7 @@ ./services/desktops/dleyna-server.nix ./services/desktops/flatpak.nix ./services/desktops/geoclue2.nix + ./services/desktops/gsignond.nix ./services/desktops/pipewire.nix ./services/desktops/gnome3/at-spi2-core.nix ./services/desktops/gnome3/chrome-gnome-shell.nix @@ -245,6 +249,7 @@ ./services/desktops/gnome3/gnome-user-share.nix ./services/desktops/gnome3/gpaste.nix ./services/desktops/gnome3/gvfs.nix + ./services/desktops/gnome3/rygel.nix ./services/desktops/gnome3/seahorse.nix ./services/desktops/gnome3/sushi.nix ./services/desktops/gnome3/tracker.nix @@ -271,15 +276,18 @@ ./services/hardware/interception-tools.nix ./services/hardware/irqbalance.nix ./services/hardware/lcd.nix + ./services/hardware/lirc.nix ./services/hardware/nvidia-optimus.nix ./services/hardware/pcscd.nix ./services/hardware/pommed.nix + ./services/hardware/ratbagd.nix ./services/hardware/sane.nix ./services/hardware/sane_extra_backends/brscan4.nix ./services/hardware/tcsd.nix ./services/hardware/tlp.nix ./services/hardware/thinkfan.nix ./services/hardware/trezord.nix + ./services/hardware/triggerhappy.nix ./services/hardware/u2f.nix ./services/hardware/udev.nix ./services/hardware/udisks2.nix @@ -362,6 +370,7 @@ ./services/misc/jackett.nix ./services/misc/logkeys.nix ./services/misc/leaps.nix + ./services/misc/lidarr.nix ./services/misc/mantisbt.nix ./services/misc/mathics.nix ./services/misc/matrix-synapse.nix @@ -392,6 +401,7 @@ ./services/misc/rogue.nix ./services/misc/serviio.nix ./services/misc/safeeyes.nix + ./services/misc/sickbeard.nix ./services/misc/siproxd.nix ./services/misc/snapper.nix ./services/misc/sonarr.nix @@ -406,6 +416,7 @@ ./services/misc/taskserver ./services/misc/tzupdate.nix ./services/misc/uhub.nix + ./services/misc/weechat.nix ./services/misc/xmr-stak.nix ./services/misc/zookeeper.nix ./services/monitoring/apcupsd.nix @@ -494,6 +505,8 @@ ./services/networking/dnsdist.nix ./services/networking/dnsmasq.nix ./services/networking/ejabberd.nix + ./services/networking/epmd.nix + ./services/networking/eternal-terminal.nix ./services/networking/fakeroute.nix ./services/networking/ferm.nix ./services/networking/firefox/sync-server.nix @@ -515,9 +528,11 @@ ./services/networking/heyefi.nix ./services/networking/hostapd.nix ./services/networking/htpdate.nix + ./services/networking/hylafax/default.nix ./services/networking/i2pd.nix ./services/networking/i2p.nix ./services/networking/iodine.nix + ./services/networking/iperf3.nix ./services/networking/ircd-hybrid/default.nix ./services/networking/iwd.nix ./services/networking/keepalived/default.nix @@ -552,6 +567,7 @@ ./services/networking/nsd.nix ./services/networking/ntopng.nix ./services/networking/ntpd.nix + ./services/networking/nullidentdmod.nix ./services/networking/nylon.nix ./services/networking/ocserv.nix ./services/networking/oidentd.nix @@ -622,7 +638,7 @@ ./services/networking/zerobin.nix ./services/networking/zeronet.nix ./services/networking/zerotierone.nix - ./services/networking/znc.nix + ./services/networking/znc/default.nix ./services/printing/cupsd.nix ./services/scheduling/atd.nix ./services/scheduling/chronos.nix @@ -676,8 +692,10 @@ ./services/web-apps/atlassian/confluence.nix ./services/web-apps/atlassian/crowd.nix ./services/web-apps/atlassian/jira.nix + ./services/web-apps/codimd.nix ./services/web-apps/frab.nix ./services/web-apps/mattermost.nix + ./services/web-apps/nextcloud.nix ./services/web-apps/nexus.nix ./services/web-apps/pgpkeyserver-lite.nix ./services/web-apps/matomo.nix @@ -721,12 +739,14 @@ ./services/x11/display-managers/lightdm.nix ./services/x11/display-managers/sddm.nix ./services/x11/display-managers/slim.nix + ./services/x11/display-managers/startx.nix ./services/x11/display-managers/xpra.nix ./services/x11/fractalart.nix ./services/x11/hardware/libinput.nix ./services/x11/hardware/multitouch.nix ./services/x11/hardware/synaptics.nix ./services/x11/hardware/wacom.nix + ./services/x11/gdk-pixbuf.nix ./services/x11/redshift.nix ./services/x11/urxvtd.nix ./services/x11/window-managers/awesome.nix diff --git a/nixos/modules/profiles/base.nix b/nixos/modules/profiles/base.nix index 5aaffa4f1f2a..7e14b0e21143 100644 --- a/nixos/modules/profiles/base.nix +++ b/nixos/modules/profiles/base.nix @@ -7,7 +7,7 @@ # Include some utilities that are useful for installing or repairing # the system. environment.systemPackages = [ - pkgs.w3m-nox # needed for the manual anyway + pkgs.w3m-nographics # needed for the manual anyway pkgs.testdisk # useful for repairing boot problems pkgs.ms-sys # for writing Microsoft boot sectors / MBRs pkgs.efibootmgr @@ -19,6 +19,9 @@ pkgs.cryptsetup # needed for dm-crypt volumes pkgs.mkpasswd # for generating password files + # Some text editors. + pkgs.vim + # Some networking tools. pkgs.fuse pkgs.fuse3 diff --git a/nixos/modules/profiles/clone-config.nix b/nixos/modules/profiles/clone-config.nix index 99d4774584f1..3f669ba7d2e1 100644 --- a/nixos/modules/profiles/clone-config.nix +++ b/nixos/modules/profiles/clone-config.nix @@ -48,6 +48,8 @@ let { imports = [ ${toString config.installer.cloneConfigIncludes} ]; + + ${config.installer.cloneConfigExtra} } ''; @@ -73,6 +75,13 @@ in ''; }; + installer.cloneConfigExtra = mkOption { + default = ""; + description = '' + Extra text to include in the cloned configuration.nix included in this + installer. + ''; + }; }; config = { diff --git a/nixos/modules/profiles/graphical.nix b/nixos/modules/profiles/graphical.nix index 332cf58aa538..fba756391b11 100644 --- a/nixos/modules/profiles/graphical.nix +++ b/nixos/modules/profiles/graphical.nix @@ -7,9 +7,12 @@ services.xserver = { enable = true; displayManager.sddm.enable = true; - desktopManager.plasma5.enable = true; + desktopManager.plasma5 = { + enable = true; + enableQt4Support = false; + }; libinput.enable = true; # for touchpad support on many laptops }; - environment.systemPackages = [ pkgs.glxinfo ]; + environment.systemPackages = [ pkgs.glxinfo pkgs.firefox ]; } diff --git a/nixos/modules/profiles/hardened.nix b/nixos/modules/profiles/hardened.nix index 2af8bf1f8e30..d712fb2514b1 100644 --- a/nixos/modules/profiles/hardened.nix +++ b/nixos/modules/profiles/hardened.nix @@ -6,12 +6,18 @@ with lib; { + meta = { + maintainers = [ maintainers.joachifm ]; + }; + boot.kernelPackages = mkDefault pkgs.linuxPackages_hardened; security.hideProcessInformation = mkDefault true; security.lockKernelModules = mkDefault true; + security.allowUserNamespaces = mkDefault false; + security.apparmor.enable = mkDefault true; boot.kernelParams = [ @@ -55,18 +61,6 @@ with lib; # ... or at least apply some hardening to it boot.kernel.sysctl."net.core.bpf_jit_harden" = mkDefault true; - # A recurring problem with user namespaces is that there are - # still code paths where the kernel's permission checking logic - # fails to account for namespacing, instead permitting a - # namespaced process to act outside the namespace with the - # same privileges as it would have inside it. This is particularly - # bad in the common case of running as root within the namespace. - # - # Setting the number of allowed user namespaces to 0 effectively disables - # the feature at runtime. Attempting to create a user namespace - # with unshare will then fail with "no space left on device". - boot.kernel.sysctl."user.max_user_namespaces" = mkDefault 0; - # Raise ASLR entropy for 64bit & 32bit, respectively. # # Note: mmap_rnd_compat_bits may not exist on 64bit. diff --git a/nixos/modules/profiles/installation-device.nix b/nixos/modules/profiles/installation-device.nix index ff4a23a18d06..580ea4a58e5b 100644 --- a/nixos/modules/profiles/installation-device.nix +++ b/nixos/modules/profiles/installation-device.nix @@ -22,9 +22,10 @@ with lib; config = { # Enable in installer, even if the minimal profile disables it. - services.nixosManual.enable = mkForce true; + documentation.enable = mkForce true; # Show the manual. + documentation.nixos.enable = mkForce true; services.nixosManual.showManual = true; # Let the user play Rogue on TTY 8 during the installation. @@ -62,7 +63,7 @@ with lib; # Tell the Nix evaluator to garbage collect more aggressively. # This is desirable in memory-constrained environments that don't # (yet) have swap set up. - environment.variables.GC_INITIAL_HEAP_SIZE = "100000"; + environment.variables.GC_INITIAL_HEAP_SIZE = "1M"; # Make the installer more likely to succeed in low memory # environments. The kernel's overcommit heustistics bite us @@ -86,9 +87,6 @@ with lib; # console less cumbersome if the machine has a public IP. networking.firewall.logRefusedConnections = mkDefault false; - environment.systemPackages = [ pkgs.vim ]; - - # Allow the user to log in as root without a password. users.users.root.initialHashedPassword = ""; }; diff --git a/nixos/modules/profiles/minimal.nix b/nixos/modules/profiles/minimal.nix index ed04e46c77d1..138eda117c74 100644 --- a/nixos/modules/profiles/minimal.nix +++ b/nixos/modules/profiles/minimal.nix @@ -12,7 +12,6 @@ with lib; i18n.supportedLocales = [ (config.i18n.defaultLocale + "/UTF-8") ]; documentation.enable = mkDefault false; - services.nixosManual.enable = mkDefault false; sound.enable = mkDefault false; } diff --git a/nixos/modules/programs/bash/bash.nix b/nixos/modules/programs/bash/bash.nix index 69a1a482d074..0fbc77ea44cf 100644 --- a/nixos/modules/programs/bash/bash.nix +++ b/nixos/modules/programs/bash/bash.nix @@ -33,7 +33,8 @@ let ''; bashAliases = concatStringsSep "\n" ( - mapAttrsFlatten (k: v: "alias ${k}='${v}'") cfg.shellAliases + mapAttrsFlatten (k: v: "alias ${k}=${escapeShellArg v}") + (filterAttrs (k: v: !isNull v) cfg.shellAliases) ); in @@ -59,12 +60,12 @@ in */ shellAliases = mkOption { - default = config.environment.shellAliases; + default = {}; description = '' - Set of aliases for bash shell. See <option>environment.shellAliases</option> - for an option format description. + Set of aliases for bash shell, which overrides <option>environment.shellAliases</option>. + See <option>environment.shellAliases</option> for an option format description. ''; - type = types.attrs; # types.attrsOf types.stringOrPath; + type = with types; attrsOf (nullOr (either str path)); }; shellInit = mkOption { @@ -125,8 +126,12 @@ in programs.bash = { + shellAliases = mapAttrs (name: mkDefault) cfge.shellAliases; + shellInit = '' - ${config.system.build.setEnvironment.text} + if [ -z "$__NIXOS_SET_ENVIRONMENT_DONE" ]; then + . ${config.system.build.setEnvironment} + fi ${cfge.shellInit} ''; @@ -166,11 +171,11 @@ in # Read system-wide modifications. if test -f /etc/profile.local; then - . /etc/profile.local + . /etc/profile.local fi if [ -n "''${BASH_VERSION:-}" ]; then - . /etc/bashrc + . /etc/bashrc fi ''; @@ -191,12 +196,12 @@ in # We are not always an interactive shell. if [ -n "$PS1" ]; then - ${cfg.interactiveShellInit} + ${cfg.interactiveShellInit} fi # Read system-wide modifications. if test -f /etc/bashrc.local; then - . /etc/bashrc.local + . /etc/bashrc.local fi ''; diff --git a/nixos/modules/programs/dconf.nix b/nixos/modules/programs/dconf.nix index b7d8a345e65c..9c9765b06b6f 100644 --- a/nixos/modules/programs/dconf.nix +++ b/nixos/modules/programs/dconf.nix @@ -32,6 +32,8 @@ in environment.etc = optionals (cfg.profiles != {}) (mapAttrsToList mkDconfProfile cfg.profiles); + services.dbus.packages = [ pkgs.gnome3.dconf ]; + environment.variables.GIO_EXTRA_MODULES = optional cfg.enable "${pkgs.gnome3.dconf.lib}/lib/gio/modules"; # https://github.com/NixOS/nixpkgs/pull/31891 diff --git a/nixos/modules/programs/digitalbitbox/doc.xml b/nixos/modules/programs/digitalbitbox/doc.xml index a26653dda535..c63201628dbd 100644 --- a/nixos/modules/programs/digitalbitbox/doc.xml +++ b/nixos/modules/programs/digitalbitbox/doc.xml @@ -3,75 +3,64 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="module-programs-digitalbitbox"> - - <title>Digital Bitbox</title> - - <para> - Digital Bitbox is a hardware wallet and second-factor authenticator. - </para> - - <para> - The <literal>digitalbitbox</literal> programs module may be - installed by setting <literal>programs.digitalbitbox</literal> - to <literal>true</literal> in a manner similar to - + <title>Digital Bitbox</title> + <para> + Digital Bitbox is a hardware wallet and second-factor authenticator. + </para> + <para> + The <literal>digitalbitbox</literal> programs module may be installed by + setting <literal>programs.digitalbitbox</literal> to <literal>true</literal> + in a manner similar to <programlisting> <xref linkend="opt-programs.digitalbitbox.enable"/> = true; </programlisting> - - and bundles the <literal>digitalbitbox</literal> package (see <xref + and bundles the <literal>digitalbitbox</literal> package (see + <xref linkend="sec-digitalbitbox-package" />), which contains the - <literal>dbb-app</literal> and <literal>dbb-cli</literal> binaries, - along with the hardware module (see <xref + <literal>dbb-app</literal> and <literal>dbb-cli</literal> binaries, along + with the hardware module (see + <xref linkend="sec-digitalbitbox-hardware-module" />) which sets up the - necessary udev rules to access the device. - </para> - - <para> - Enabling the digitalbitbox module is pretty much the easiest way to - get a Digital Bitbox device working on your system. - </para> + necessary udev rules to access the device. + </para> + <para> + Enabling the digitalbitbox module is pretty much the easiest way to get a + Digital Bitbox device working on your system. + </para> + <para> + For more information, see + <link xlink:href="https://digitalbitbox.com/start_linux" />. + </para> + <section xml:id="sec-digitalbitbox-package"> + <title>Package</title> <para> - For more information, see - <link xlink:href="https://digitalbitbox.com/start_linux" />. - </para> - - <section xml:id="sec-digitalbitbox-package"> - <title>Package</title> - - <para> - The binaries, <literal>dbb-app</literal> (a GUI tool) and - <literal>dbb-cli</literal> (a CLI tool), are available through the - <literal>digitalbitbox</literal> package which could be installed - as follows: - + The binaries, <literal>dbb-app</literal> (a GUI tool) and + <literal>dbb-cli</literal> (a CLI tool), are available through the + <literal>digitalbitbox</literal> package which could be installed as + follows: <programlisting> <xref linkend="opt-environment.systemPackages"/> = [ pkgs.digitalbitbox ]; </programlisting> - </para> - </section> - - - <section xml:id="sec-digitalbitbox-hardware-module"> - <title>Hardware</title> - - <para> - The digitalbitbox hardware package enables the udev rules for - Digital Bitbox devices and may be installed as follows: + </para> + </section> + <section xml:id="sec-digitalbitbox-hardware-module"> + <title>Hardware</title> + <para> + The digitalbitbox hardware package enables the udev rules for Digital Bitbox + devices and may be installed as follows: <programlisting> <xref linkend="opt-hardware.digitalbitbox.enable"/> = true; </programlisting> - </para> - - <para> - In order to alter the udev rules, one may provide different values for - the <literal>udevRule51</literal> and <literal>udevRule52</literal> - attributes by means of overriding as follows: + </para> + <para> + In order to alter the udev rules, one may provide different values for the + <literal>udevRule51</literal> and <literal>udevRule52</literal> attributes + by means of overriding as follows: <programlisting> programs.digitalbitbox = { <link linkend="opt-programs.digitalbitbox.enable">enable</link> = true; @@ -80,6 +69,6 @@ programs.digitalbitbox = { }; }; </programlisting> - </para> - </section> + </para> + </section> </chapter> diff --git a/nixos/modules/programs/fish.nix b/nixos/modules/programs/fish.nix index c8d94a47be28..b38af07b92c3 100644 --- a/nixos/modules/programs/fish.nix +++ b/nixos/modules/programs/fish.nix @@ -9,7 +9,8 @@ let cfg = config.programs.fish; fishAliases = concatStringsSep "\n" ( - mapAttrsFlatten (k: v: "alias ${k} '${v}'") cfg.shellAliases + mapAttrsFlatten (k: v: "alias ${k} ${escapeShellArg v}") + (filterAttrs (k: v: !isNull v) cfg.shellAliases) ); in @@ -27,7 +28,7 @@ in ''; type = types.bool; }; - + vendor.config.enable = mkOption { type = types.bool; default = true; @@ -43,7 +44,7 @@ in Whether fish should use completion files provided by other packages. ''; }; - + vendor.functions.enable = mkOption { type = types.bool; default = true; @@ -53,12 +54,12 @@ in }; shellAliases = mkOption { - default = config.environment.shellAliases; + default = {}; description = '' - Set of aliases for fish shell. See <option>environment.shellAliases</option> - for an option format description. + Set of aliases for fish shell, which overrides <option>environment.shellAliases</option>. + See <option>environment.shellAliases</option> for an option format description. ''; - type = types.attrs; + type = with types; attrsOf (nullOr (either str path)); }; shellInit = mkOption { @@ -99,6 +100,8 @@ in config = mkIf cfg.enable { + programs.fish.shellAliases = mapAttrs (name: mkDefault) cfge.shellAliases; + environment.etc."fish/foreign-env/shellInit".text = cfge.shellInit; environment.etc."fish/foreign-env/loginShellInit".text = cfge.loginShellInit; environment.etc."fish/foreign-env/interactiveShellInit".text = cfge.interactiveShellInit; @@ -107,9 +110,11 @@ in # This happens before $__fish_datadir/config.fish sets fish_function_path, so it is currently # unset. We set it and then completely erase it, leaving its configuration to $__fish_datadir/config.fish set fish_function_path ${pkgs.fish-foreign-env}/share/fish-foreign-env/functions $__fish_datadir/functions - + # source the NixOS environment config - fenv source ${config.system.build.setEnvironment} + if [ -z "$__NIXOS_SET_ENVIRONMENT_DONE" ] + fenv source ${config.system.build.setEnvironment} + end # clear fish_function_path so that it will be correctly set when we return to $__fish_datadir/config.fish set -e fish_function_path @@ -123,7 +128,7 @@ in set fish_function_path ${pkgs.fish-foreign-env}/share/fish-foreign-env/functions $fish_function_path fenv source /etc/fish/foreign-env/shellInit > /dev/null set -e fish_function_path[1] - + ${cfg.shellInit} # and leave a note so we don't source this config section again from @@ -137,7 +142,7 @@ in set fish_function_path ${pkgs.fish-foreign-env}/share/fish-foreign-env/functions $fish_function_path fenv source /etc/fish/foreign-env/loginShellInit > /dev/null set -e fish_function_path[1] - + ${cfg.loginShellInit} # and leave a note so we don't source this config section again from @@ -149,12 +154,11 @@ in status --is-interactive; and not set -q __fish_nixos_interactive_config_sourced and begin ${fishAliases} - set fish_function_path ${pkgs.fish-foreign-env}/share/fish-foreign-env/functions $fish_function_path fenv source /etc/fish/foreign-env/interactiveShellInit > /dev/null set -e fish_function_path[1] - + ${cfg.promptInit} ${cfg.interactiveShellInit} @@ -170,7 +174,7 @@ in ++ optional cfg.vendor.config.enable "/share/fish/vendor_conf.d" ++ optional cfg.vendor.completions.enable "/share/fish/vendor_completions.d" ++ optional cfg.vendor.functions.enable "/share/fish/vendor_functions.d"; - + environment.systemPackages = [ pkgs.fish ]; environment.shells = [ diff --git a/nixos/modules/programs/light.nix b/nixos/modules/programs/light.nix index 6f8c389acc97..9f2a03e7e763 100644 --- a/nixos/modules/programs/light.nix +++ b/nixos/modules/programs/light.nix @@ -13,7 +13,8 @@ in default = false; type = types.bool; description = '' - Whether to install Light backlight control with setuid wrapper. + Whether to install Light backlight control command + and udev rules granting access to members of the "video" group. ''; }; }; @@ -21,6 +22,6 @@ in config = mkIf cfg.enable { environment.systemPackages = [ pkgs.light ]; - security.wrappers.light.source = "${pkgs.light.out}/bin/light"; + services.udev.packages = [ pkgs.light ]; }; } diff --git a/nixos/modules/programs/plotinus.xml b/nixos/modules/programs/plotinus.xml index 91740ee16ec2..902cd89e0c49 100644 --- a/nixos/modules/programs/plotinus.xml +++ b/nixos/modules/programs/plotinus.xml @@ -3,23 +3,28 @@ 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>: - + <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> <xref linkend="opt-programs.plotinus.enable"/> = true; </programlisting> - -</para> - + </para> </chapter> diff --git a/nixos/modules/programs/rootston.nix b/nixos/modules/programs/rootston.nix deleted file mode 100644 index 842d9e6cfb48..000000000000 --- a/nixos/modules/programs/rootston.nix +++ /dev/null @@ -1,103 +0,0 @@ -{ config, pkgs, lib, ... }: - -with lib; - -let - cfg = config.programs.rootston; - - rootstonWrapped = pkgs.writeScriptBin "rootston" '' - #! ${pkgs.runtimeShell} - if [[ "$#" -ge 1 ]]; then - exec ${pkgs.rootston}/bin/rootston "$@" - else - ${cfg.extraSessionCommands} - exec ${pkgs.rootston}/bin/rootston -C ${cfg.configFile} - fi - ''; -in { - options.programs.rootston = { - enable = mkEnableOption '' - rootston, the reference compositor for wlroots. The purpose of rootston - is to test and demonstrate the features of wlroots (if you want a real - Wayland compositor you should e.g. use Sway instead). You can manually - start the compositor by running "rootston" from a terminal''; - - extraSessionCommands = mkOption { - type = types.lines; - default = ""; - example = '' - # Define a keymap (US QWERTY is the default) - export XKB_DEFAULT_LAYOUT=de,us - export XKB_DEFAULT_VARIANT=nodeadkeys - export XKB_DEFAULT_OPTIONS=grp:alt_shift_toggle,caps:escape - ''; - description = '' - Shell commands executed just before rootston is started. - ''; - }; - - extraPackages = mkOption { - type = with types; listOf package; - default = with pkgs; [ - westonLite xwayland rofi - ]; - defaultText = literalExample '' - with pkgs; [ - westonLite xwayland rofi - ] - ''; - example = literalExample "[ ]"; - description = '' - Extra packages to be installed system wide. - ''; - }; - - config = mkOption { - type = types.str; - default = '' - [keyboard] - meta-key = Logo - - # Sway/i3 like Keybindings - # Maps key combinations with commands to execute - # Commands include: - # - "exit" to stop the compositor - # - "exec" to execute a shell command - # - "close" to close the current view - # - "next_window" to cycle through windows - [bindings] - Logo+Shift+e = exit - Logo+q = close - Logo+m = maximize - Alt+Tab = next_window - Logo+Return = exec weston-terminal - Logo+d = exec rofi -show run - ''; - description = '' - Default configuration for rootston (used when called without any - parameters). - ''; - }; - - configFile = mkOption { - type = types.path; - default = "/etc/rootston.ini"; - example = literalExample "${pkgs.rootston}/etc/rootston.ini"; - description = '' - Path to the default rootston configuration file (the "config" option - will have no effect if you change the path). - ''; - }; - }; - - config = mkIf cfg.enable { - environment.etc."rootston.ini".text = cfg.config; - environment.systemPackages = [ rootstonWrapped ] ++ cfg.extraPackages; - - hardware.opengl.enable = mkDefault true; - fonts.enableDefaultFonts = mkDefault true; - programs.dconf.enable = mkDefault true; - }; - - meta.maintainers = with lib.maintainers; [ primeos gnidorah ]; -} diff --git a/nixos/modules/programs/shell.nix b/nixos/modules/programs/shell.nix index 944a8bdf16fc..9842e2bef643 100644 --- a/nixos/modules/programs/shell.nix +++ b/nixos/modules/programs/shell.nix @@ -8,18 +8,12 @@ with lib; config = { - environment.shellAliases = - { ls = "ls --color=tty"; - ll = "ls -l"; - l = "ls -alh"; - }; - environment.shellInit = '' # Set up the per-user profile. mkdir -m 0755 -p "$NIX_USER_PROFILE_DIR" if [ "$(stat --printf '%u' "$NIX_USER_PROFILE_DIR")" != "$(id -u)" ]; then - echo "WARNING: bad ownership on $NIX_USER_PROFILE_DIR, should be $(id -u)" >&2 + echo "WARNING: the per-user profile dir $NIX_USER_PROFILE_DIR should belong to user id $(id -u)" >&2 fi if [ -w "$HOME" ]; then @@ -41,7 +35,7 @@ with lib; NIX_USER_GCROOTS_DIR="/nix/var/nix/gcroots/per-user/$USER" mkdir -m 0755 -p "$NIX_USER_GCROOTS_DIR" if [ "$(stat --printf '%u' "$NIX_USER_GCROOTS_DIR")" != "$(id -u)" ]; then - echo "WARNING: bad ownership on $NIX_USER_GCROOTS_DIR, should be $(id -u)" >&2 + echo "WARNING: the per-user gcroots dir $NIX_USER_GCROOTS_DIR should belong to user id $(id -u)" >&2 fi # Set up a default Nix expression from which to install stuff. diff --git a/nixos/modules/programs/sway-beta.nix b/nixos/modules/programs/sway-beta.nix new file mode 100644 index 000000000000..04f2e0662b86 --- /dev/null +++ b/nixos/modules/programs/sway-beta.nix @@ -0,0 +1,54 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.programs.sway-beta; + swayPackage = cfg.package; +in { + options.programs.sway-beta = { + enable = mkEnableOption '' + Sway, the i3-compatible tiling Wayland compositor. This module will be removed after the final release of Sway 1.0 + ''; + + package = mkOption { + type = types.package; + default = pkgs.sway-beta; + defaultText = "pkgs.sway-beta"; + description = '' + The package to be used for `sway`. + ''; + }; + + extraPackages = mkOption { + type = with types; listOf package; + default = with pkgs; [ + xwayland dmenu + ]; + defaultText = literalExample '' + with pkgs; [ xwayland dmenu ]; + ''; + example = literalExample '' + with pkgs; [ + xwayland + i3status i3status-rust + termite rofi light + ] + ''; + description = '' + Extra packages to be installed system wide. + ''; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ swayPackage ] ++ cfg.extraPackages; + security.pam.services.swaylock = {}; + hardware.opengl.enable = mkDefault true; + fonts.enableDefaultFonts = mkDefault true; + programs.dconf.enable = mkDefault true; + }; + + meta.maintainers = with lib.maintainers; [ gnidorah primeos colemickens ]; +} + diff --git a/nixos/modules/programs/thefuck.nix b/nixos/modules/programs/thefuck.nix index f4ae52934760..21ed6603c1bd 100644 --- a/nixos/modules/programs/thefuck.nix +++ b/nixos/modules/programs/thefuck.nix @@ -29,8 +29,8 @@ in config = mkIf cfg.enable { environment.systemPackages = with pkgs; [ thefuck ]; - environment.shellInit = initScript; + programs.bash.interactiveShellInit = initScript; programs.zsh.interactiveShellInit = mkIf prg.zsh.enable initScript; programs.fish.interactiveShellInit = mkIf prg.fish.enable '' ${pkgs.thefuck}/bin/thefuck --alias | source diff --git a/nixos/modules/programs/wavemon.nix b/nixos/modules/programs/wavemon.nix new file mode 100644 index 000000000000..ac665fe4a023 --- /dev/null +++ b/nixos/modules/programs/wavemon.nix @@ -0,0 +1,28 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.wavemon; +in { + options = { + programs.wavemon = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to add wavemon to the global environment and configure a + setcap wrapper for it. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = with pkgs; [ wavemon ]; + security.wrappers.wavemon = { + source = "${pkgs.wavemon}/bin/wavemon"; + capabilities = "cap_net_admin+ep"; + }; + }; +} diff --git a/nixos/modules/programs/yabar.nix b/nixos/modules/programs/yabar.nix index a01083c3ace9..db085211366e 100644 --- a/nixos/modules/programs/yabar.nix +++ b/nixos/modules/programs/yabar.nix @@ -44,10 +44,23 @@ in enable = mkEnableOption "yabar"; package = mkOption { - default = pkgs.yabar; - example = literalExample "pkgs.yabar-unstable"; + default = pkgs.yabar-unstable; + example = literalExample "pkgs.yabar"; type = types.package; + # `yabar-stable` segfaults under certain conditions. + apply = x: if x == pkgs.yabar-unstable then x else flip warn x '' + It's not recommended to use `yabar' with `programs.yabar', the (old) stable release + tends to segfault under certain circumstances: + + * https://github.com/geommer/yabar/issues/86 + * https://github.com/geommer/yabar/issues/68 + * https://github.com/geommer/yabar/issues/143 + + Most of them don't occur on master anymore, until a new release is published, it's recommended + to use `yabar-unstable'. + ''; + description = '' The package which contains the `yabar` binary. diff --git a/nixos/modules/programs/zsh/oh-my-zsh.xml b/nixos/modules/programs/zsh/oh-my-zsh.xml index 6567d4a42fac..5cf690c1a560 100644 --- a/nixos/modules/programs/zsh/oh-my-zsh.xml +++ b/nixos/modules/programs/zsh/oh-my-zsh.xml @@ -3,18 +3,20 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="module-programs-zsh-ohmyzsh"> - -<title>Oh my ZSH</title> - -<para><literal><link xlink:href="https://ohmyz.sh/">oh-my-zsh</link></literal> is a framework -to manage your <link xlink:href="https://www.zsh.org/">ZSH</link> configuration -including completion scripts for several CLI tools or custom prompt themes.</para> - -<section xml:id="module-programs-oh-my-zsh-usage"><title>Basic usage</title> -<para>The module uses the <literal>oh-my-zsh</literal> package with all available features. The -initial setup using Nix expressions is fairly similar to the configuration format -of <literal>oh-my-zsh</literal>. - + <title>Oh my ZSH</title> + <para> + <literal><link xlink:href="https://ohmyz.sh/">oh-my-zsh</link></literal> is a + framework to manage your <link xlink:href="https://www.zsh.org/">ZSH</link> + configuration including completion scripts for several CLI tools or custom + prompt themes. + </para> + <section xml:id="module-programs-oh-my-zsh-usage"> + <title>Basic usage</title> + + <para> + The module uses the <literal>oh-my-zsh</literal> package with all available + features. The initial setup using Nix expressions is fairly similar to the + configuration format of <literal>oh-my-zsh</literal>. <programlisting> { programs.ohMyZsh = { @@ -24,39 +26,50 @@ of <literal>oh-my-zsh</literal>. }; } </programlisting> - -For a detailed explanation of these arguments please refer to the -<link xlink:href="https://github.com/robbyrussell/oh-my-zsh/wiki"><literal>oh-my-zsh</literal> docs</link>. -</para> -<para>The expression generates the needed -configuration and writes it into your <literal>/etc/zshrc</literal>. -</para></section> - -<section xml:id="module-programs-oh-my-zsh-additions"><title>Custom additions</title> - -<para>Sometimes third-party or custom scripts such as a modified theme may be needed. -<literal>oh-my-zsh</literal> provides the -<link xlink:href="https://github.com/robbyrussell/oh-my-zsh/wiki/Customization#overriding-internals"><literal>ZSH_CUSTOM</literal></link> -environment variable for this which points to a directory with additional scripts.</para> - -<para>The module can do this as well: - + For a detailed explanation of these arguments please refer to the + <link xlink:href="https://github.com/robbyrussell/oh-my-zsh/wiki"><literal>oh-my-zsh</literal> + docs</link>. + </para> + + <para> + The expression generates the needed configuration and writes it into your + <literal>/etc/zshrc</literal>. + </para> + </section> + <section xml:id="module-programs-oh-my-zsh-additions"> + <title>Custom additions</title> + + <para> + Sometimes third-party or custom scripts such as a modified theme may be + needed. <literal>oh-my-zsh</literal> provides the + <link xlink:href="https://github.com/robbyrussell/oh-my-zsh/wiki/Customization#overriding-internals"><literal>ZSH_CUSTOM</literal></link> + environment variable for this which points to a directory with additional + scripts. + </para> + + <para> + The module can do this as well: <programlisting> { programs.ohMyZsh.custom = "~/path/to/custom/scripts"; } </programlisting> -</para></section> - -<section xml:id="module-programs-oh-my-zsh-environments"><title>Custom environments</title> - -<para>There are several extensions for <literal>oh-my-zsh</literal> packaged in <literal>nixpkgs</literal>. -One of them is <link xlink:href="https://github.com/spwhitt/nix-zsh-completions">nix-zsh-completions</link> -which bundles completion scripts and a plugin for <literal>oh-my-zsh</literal>.</para> - -<para>Rather than using a single mutable path for <literal>ZSH_CUSTOM</literal>, it's also possible to -generate this path from a list of Nix packages: - + </para> + </section> + <section xml:id="module-programs-oh-my-zsh-environments"> + <title>Custom environments</title> + + <para> + There are several extensions for <literal>oh-my-zsh</literal> packaged in + <literal>nixpkgs</literal>. One of them is + <link xlink:href="https://github.com/spwhitt/nix-zsh-completions">nix-zsh-completions</link> + which bundles completion scripts and a plugin for + <literal>oh-my-zsh</literal>. + </para> + + <para> + Rather than using a single mutable path for <literal>ZSH_CUSTOM</literal>, + it's also possible to generate this path from a list of Nix packages: <programlisting> { pkgs, ... }: { @@ -66,42 +79,59 @@ generate this path from a list of Nix packages: ]; } </programlisting> - -Internally a single store path will be created using <literal>buildEnv</literal>. -Please refer to the docs of -<link xlink:href="https://nixos.org/nixpkgs/manual/#sec-building-environment"><literal>buildEnv</literal></link> -for further reference.</para> - -<para><emphasis>Please keep in mind that this is not compatible with <literal>programs.ohMyZsh.custom</literal> -as it requires an immutable store path while <literal>custom</literal> shall remain mutable! An evaluation failure -will be thrown if both <literal>custom</literal> and <literal>customPkgs</literal> are set.</emphasis> -</para></section> - -<section xml:id="module-programs-oh-my-zsh-packaging-customizations"><title>Package your own customizations</title> - -<para>If third-party customizations (e.g. new themes) are supposed to be added to <literal>oh-my-zsh</literal> -there are several pitfalls to keep in mind:</para> - -<itemizedlist> - <listitem> - <para>To comply with the default structure of <literal>ZSH</literal> the entire output needs to be written to - <literal>$out/share/zsh.</literal></para> - </listitem> - <listitem> - <para>Completion scripts are supposed to be stored at <literal>$out/share/zsh/site-functions</literal>. This directory - is part of the <literal><link xlink:href="http://zsh.sourceforge.net/Doc/Release/Functions.html">fpath</link></literal> - and the package should be compatible with pure <literal>ZSH</literal> setups. The module will automatically link - the contents of <literal>site-functions</literal> to completions directory in the proper store path.</para> - </listitem> - <listitem> - <para>The <literal>plugins</literal> directory needs the structure <literal>pluginname/pluginname.plugin.zsh</literal> - as structured in the <link xlink:href="https://github.com/robbyrussell/oh-my-zsh/tree/91b771914bc7c43dd7c7a43b586c5de2c225ceb7/plugins">upstream repo.</link> + Internally a single store path will be created using + <literal>buildEnv</literal>. Please refer to the docs of + <link xlink:href="https://nixos.org/nixpkgs/manual/#sec-building-environment"><literal>buildEnv</literal></link> + for further reference. + </para> + + <para> + <emphasis>Please keep in mind that this is not compatible with + <literal>programs.ohMyZsh.custom</literal> as it requires an immutable store + path while <literal>custom</literal> shall remain mutable! An evaluation + failure will be thrown if both <literal>custom</literal> and + <literal>customPkgs</literal> are set.</emphasis> + </para> + </section> + <section xml:id="module-programs-oh-my-zsh-packaging-customizations"> + <title>Package your own customizations</title> + + <para> + If third-party customizations (e.g. new themes) are supposed to be added to + <literal>oh-my-zsh</literal> there are several pitfalls to keep in mind: + </para> + + <itemizedlist> + <listitem> + <para> + To comply with the default structure of <literal>ZSH</literal> the entire + output needs to be written to <literal>$out/share/zsh.</literal> + </para> + </listitem> + <listitem> + <para> + Completion scripts are supposed to be stored at + <literal>$out/share/zsh/site-functions</literal>. This directory is part + of the + <literal><link xlink:href="http://zsh.sourceforge.net/Doc/Release/Functions.html">fpath</link></literal> + and the package should be compatible with pure <literal>ZSH</literal> + setups. The module will automatically link the contents of + <literal>site-functions</literal> to completions directory in the proper + store path. + </para> + </listitem> + <listitem> + <para> + The <literal>plugins</literal> directory needs the structure + <literal>pluginname/pluginname.plugin.zsh</literal> as structured in the + <link xlink:href="https://github.com/robbyrussell/oh-my-zsh/tree/91b771914bc7c43dd7c7a43b586c5de2c225ceb7/plugins">upstream + repo.</link> </para> - </listitem> -</itemizedlist> + </listitem> + </itemizedlist> -<para> -A derivation for <literal>oh-my-zsh</literal> may look like this: + <para> + A derivation for <literal>oh-my-zsh</literal> may look like this: <programlisting> { stdenv, fetchFromGitHub }: @@ -120,6 +150,6 @@ stdenv.mkDerivation rec { ''; } </programlisting> -</para> -</section> + </para> + </section> </chapter> diff --git a/nixos/modules/programs/zsh/zsh.nix b/nixos/modules/programs/zsh/zsh.nix index d30b3415411f..164d8db5859a 100644 --- a/nixos/modules/programs/zsh/zsh.nix +++ b/nixos/modules/programs/zsh/zsh.nix @@ -11,7 +11,8 @@ let cfg = config.programs.zsh; zshAliases = concatStringsSep "\n" ( - mapAttrsFlatten (k: v: "alias ${k}='${v}'") cfg.shellAliases + mapAttrsFlatten (k: v: "alias ${k}=${escapeShellArg v}") + (filterAttrs (k: v: !isNull v) cfg.shellAliases) ); in @@ -34,13 +35,12 @@ in }; shellAliases = mkOption { - default = config.environment.shellAliases; + default = {}; description = '' - Set of aliases for zsh shell. Overrides the default value taken from - <option>environment.shellAliases</option>. + Set of aliases for zsh shell, which overrides <option>environment.shellAliases</option>. See <option>environment.shellAliases</option> for an option format description. ''; - type = types.attrs; # types.attrsOf types.stringOrPath; + type = with types; attrsOf (nullOr (either str path)); }; shellInit = mkOption { @@ -70,7 +70,7 @@ in promptInit = mkOption { default = '' if [ "$TERM" != dumb ]; then - autoload -U promptinit && promptinit && prompt walters + autoload -U promptinit && promptinit && prompt walters fi ''; description = '' @@ -106,6 +106,8 @@ in config = mkIf cfg.enable { + programs.zsh.shellAliases = mapAttrs (name: mkDefault) cfge.shellAliases; + environment.etc."zshenv".text = '' # /etc/zshenv: DO NOT EDIT -- this file has been generated automatically. @@ -116,7 +118,9 @@ in if [ -n "$__ETC_ZSHENV_SOURCED" ]; then return; fi export __ETC_ZSHENV_SOURCED=1 - ${config.system.build.setEnvironment.text} + if [ -z "$__NIXOS_SET_ENVIRONMENT_DONE" ]; then + . ${config.system.build.setEnvironment} + fi ${cfge.shellInit} @@ -124,7 +128,7 @@ in # Read system-wide modifications. if test -f /etc/zshenv.local; then - . /etc/zshenv.local + . /etc/zshenv.local fi ''; @@ -143,7 +147,7 @@ in # Read system-wide modifications. if test -f /etc/zprofile.local; then - . /etc/zprofile.local + . /etc/zprofile.local fi ''; @@ -169,7 +173,7 @@ in # Tell zsh how to find installed completions for p in ''${(z)NIX_PROFILES}; do - fpath+=($p/share/zsh/site-functions $p/share/zsh/$ZSH_VERSION/functions $p/share/zsh/vendor-completions) + fpath+=($p/share/zsh/site-functions $p/share/zsh/$ZSH_VERSION/functions $p/share/zsh/vendor-completions) done ${optionalString cfg.enableGlobalCompInit "autoload -U compinit && compinit"} @@ -184,7 +188,7 @@ in # Read system-wide modifications. if test -f /etc/zshrc.local; then - . /etc/zshrc.local + . /etc/zshrc.local fi ''; diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 4a6bdfe83dd2..aa2b5c0b2dfb 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -28,7 +28,10 @@ with lib; (config: let enabled = getAttrFromPath [ "services" "printing" "gutenprint" ] config; in if enabled then [ pkgs.gutenprint ] else [ ])) - (mkRenamedOptionModule [ "services" "ddclient" "domain" ] [ "services" "ddclient" "domains" ]) + (mkChangedOptionModule [ "services" "ddclient" "domain" ] [ "services" "ddclient" "domains" ] + (config: + let value = getAttrFromPath [ "services" "ddclient" "domain" ] config; + in if value != "" then [ value ] else [])) (mkRemovedOptionModule [ "services" "ddclient" "homeDir" ] "") (mkRenamedOptionModule [ "services" "elasticsearch" "host" ] [ "services" "elasticsearch" "listenAddress" ]) (mkRenamedOptionModule [ "services" "graphite" "api" "host" ] [ "services" "graphite" "api" "listenAddress" ]) @@ -39,6 +42,7 @@ with lib; (mkRenamedOptionModule [ "services" "kubernetes" "apiserver" "address" ] ["services" "kubernetes" "apiserver" "bindAddress"]) (mkRemovedOptionModule [ "services" "kubernetes" "apiserver" "publicAddress" ] "") (mkRenamedOptionModule [ "services" "kubernetes" "addons" "dashboard" "enableRBAC" ] [ "services" "kubernetes" "addons" "dashboard" "rbac" "enable" ]) + (mkRemovedOptionModule [ "services" "kubernetes" "kubelet" "cadvisorPort" ] "") (mkRenamedOptionModule [ "services" "logstash" "address" ] [ "services" "logstash" "listenAddress" ]) (mkRenamedOptionModule [ "services" "mpd" "network" "host" ] [ "services" "mpd" "network" "listenAddress" ]) (mkRenamedOptionModule [ "services" "neo4j" "host" ] [ "services" "neo4j" "defaultListenAddress" ]) @@ -276,6 +280,7 @@ with lib; (mkRenamedOptionModule [ "programs" "info" "enable" ] [ "documentation" "info" "enable" ]) (mkRenamedOptionModule [ "programs" "man" "enable" ] [ "documentation" "man" "enable" ]) + (mkRenamedOptionModule [ "services" "nixosManual" "enable" ] [ "documentation" "nixos" "enable" ]) ] ++ (flip map [ "blackboxExporter" "collectdExporter" "fritzboxExporter" "jsonExporter" "minioExporter" "nginxExporter" "nodeExporter" diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix index 946da92d80e7..092704c6fc3f 100644 --- a/nixos/modules/security/acme.nix +++ b/nixos/modules/security/acme.nix @@ -302,15 +302,15 @@ in workdir="$(mktemp -d)" # Create CA - openssl genrsa -des3 -passout pass:x -out $workdir/ca.pass.key 2048 - openssl rsa -passin pass:x -in $workdir/ca.pass.key -out $workdir/ca.key + openssl genrsa -des3 -passout pass:xxxx -out $workdir/ca.pass.key 2048 + openssl rsa -passin pass:xxxx -in $workdir/ca.pass.key -out $workdir/ca.key openssl req -new -key $workdir/ca.key -out $workdir/ca.csr \ -subj "/C=UK/ST=Warwickshire/L=Leamington/O=OrgName/OU=Security Department/CN=example.com" openssl x509 -req -days 1 -in $workdir/ca.csr -signkey $workdir/ca.key -out $workdir/ca.crt # Create key - openssl genrsa -des3 -passout pass:x -out $workdir/server.pass.key 2048 - openssl rsa -passin pass:x -in $workdir/server.pass.key -out $workdir/server.key + openssl genrsa -des3 -passout pass:xxxx -out $workdir/server.pass.key 2048 + openssl rsa -passin pass:xxxx -in $workdir/server.pass.key -out $workdir/server.key openssl req -new -key $workdir/server.key -out $workdir/server.csr \ -subj "/C=UK/ST=Warwickshire/L=Leamington/O=OrgName/OU=IT Department/CN=example.com" openssl x509 -req -days 1 -in $workdir/server.csr -CA $workdir/ca.crt \ diff --git a/nixos/modules/security/acme.xml b/nixos/modules/security/acme.xml index b4cd83f6632c..ef71fe53d0c7 100644 --- a/nixos/modules/security/acme.xml +++ b/nixos/modules/security/acme.xml @@ -3,23 +3,25 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="module-security-acme"> - -<title>SSL/TLS Certificates with ACME</title> - -<para>NixOS supports automatic domain validation & certificate -retrieval and renewal using the ACME protocol. This is currently only -implemented by and for Let's Encrypt. The alternative ACME client -<literal>simp_le</literal> is used under the hood.</para> - -<section xml:id="module-security-acme-prerequisites"><title>Prerequisites</title> - -<para>You need to have a running HTTP server for verification. The server must -have a webroot defined that can serve -<filename>.well-known/acme-challenge</filename>. This directory must be -writeable by the user that will run the ACME client.</para> - -<para>For instance, this generic snippet could be used for Nginx: - + <title>SSL/TLS Certificates with ACME</title> + <para> + NixOS supports automatic domain validation & certificate retrieval and + renewal using the ACME protocol. This is currently only implemented by and + for Let's Encrypt. The alternative ACME client <literal>simp_le</literal> is + used under the hood. + </para> + <section xml:id="module-security-acme-prerequisites"> + <title>Prerequisites</title> + + <para> + You need to have a running HTTP server for verification. The server must + have a webroot defined that can serve + <filename>.well-known/acme-challenge</filename>. This directory must be + writeable by the user that will run the ACME client. + </para> + + <para> + For instance, this generic snippet could be used for Nginx: <programlisting> http { server { @@ -37,43 +39,47 @@ http { } } </programlisting> -</para> - -</section> - -<section xml:id="module-security-acme-configuring"><title>Configuring</title> - -<para>To enable ACME certificate retrieval & renewal for a certificate for -<literal>foo.example.com</literal>, add the following in your -<filename>configuration.nix</filename>: - + </para> + </section> + <section xml:id="module-security-acme-configuring"> + <title>Configuring</title> + + <para> + To enable ACME certificate retrieval & renewal for a certificate for + <literal>foo.example.com</literal>, add the following in your + <filename>configuration.nix</filename>: <programlisting> <xref linkend="opt-security.acme.certs"/>."foo.example.com" = { <link linkend="opt-security.acme.certs._name_.webroot">webroot</link> = "/var/www/challenges"; <link linkend="opt-security.acme.certs._name_.email">email</link> = "foo@example.com"; }; </programlisting> -</para> - -<para>The private key <filename>key.pem</filename> and certificate -<filename>fullchain.pem</filename> will be put into -<filename>/var/lib/acme/foo.example.com</filename>. The target directory can -be configured with the option <xref linkend="opt-security.acme.directory"/>. -</para> - -<para>Refer to <xref linkend="ch-options" /> for all available configuration -options for the <link linkend="opt-security.acme.certs">security.acme</link> module.</para> - -</section> - -<section xml:id="module-security-acme-nginx"><title>Using ACME certificates in Nginx</title> -<para>NixOS supports fetching ACME certificates for you by setting - <literal><link linkend="opt-services.nginx.virtualHosts._name_.enableACME">enableACME</link> = true;</literal> in a virtualHost config. We -first create self-signed placeholder certificates in place of the -real ACME certs. The placeholder certs are overwritten when the ACME -certs arrive. For <literal>foo.example.com</literal> the config would -look like. -</para> + </para> + + <para> + The private key <filename>key.pem</filename> and certificate + <filename>fullchain.pem</filename> will be put into + <filename>/var/lib/acme/foo.example.com</filename>. The target directory can + be configured with the option <xref linkend="opt-security.acme.directory"/>. + </para> + + <para> + Refer to <xref linkend="ch-options" /> for all available configuration + options for the <link linkend="opt-security.acme.certs">security.acme</link> + module. + </para> + </section> + <section xml:id="module-security-acme-nginx"> + <title>Using ACME certificates in Nginx</title> + + <para> + NixOS supports fetching ACME certificates for you by setting + <literal><link linkend="opt-services.nginx.virtualHosts._name_.enableACME">enableACME</link> + = true;</literal> in a virtualHost config. We first create self-signed + placeholder certificates in place of the real ACME certs. The placeholder + certs are overwritten when the ACME certs arrive. For + <literal>foo.example.com</literal> the config would look like. + </para> <programlisting> services.nginx = { @@ -89,5 +95,5 @@ services.nginx = { }; } </programlisting> -</section> + </section> </chapter> diff --git a/nixos/modules/security/apparmor-suid.nix b/nixos/modules/security/apparmor-suid.nix index dfbf5d859ba9..498c2f25d1c0 100644 --- a/nixos/modules/security/apparmor-suid.nix +++ b/nixos/modules/security/apparmor-suid.nix @@ -28,7 +28,7 @@ with lib; capability setuid, network inet raw, - ${pkgs.glibc.out}/lib/*.so mr, + ${pkgs.stdenv.cc.libc.out}/lib/*.so mr, ${pkgs.libcap.lib}/lib/libcap.so* mr, ${pkgs.attr.out}/lib/libattr.so* mr, diff --git a/nixos/modules/security/dhparams.nix b/nixos/modules/security/dhparams.nix index e2b84c3e3b38..62a499ea624d 100644 --- a/nixos/modules/security/dhparams.nix +++ b/nixos/modules/security/dhparams.nix @@ -170,4 +170,6 @@ in { ''; }) cfg.params; }; + + meta.maintainers = with lib.maintainers; [ ekleog ]; } diff --git a/nixos/modules/security/hidepid.xml b/nixos/modules/security/hidepid.xml index d69341eb3cde..5a17cb1da412 100644 --- a/nixos/modules/security/hidepid.xml +++ b/nixos/modules/security/hidepid.xml @@ -3,31 +3,26 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="sec-hidepid"> - - <title>Hiding process information</title> - - <para> - Setting + <title>Hiding process information</title> + <para> + Setting <programlisting> <xref linkend="opt-security.hideProcessInformation"/> = true; </programlisting> - ensures that access to process information is restricted to the - owning user. This implies, among other things, that command-line - arguments remain private. Unless your deployment relies on unprivileged - users being able to inspect the process information of other users, this - option should be safe to enable. - </para> - - <para> - Members of the <literal>proc</literal> group are exempt from process - information hiding. - </para> - - <para> - To allow a service <replaceable>foo</replaceable> to run without process information hiding, set + ensures that access to process information is restricted to the owning user. + This implies, among other things, that command-line arguments remain private. + Unless your deployment relies on unprivileged users being able to inspect the + process information of other users, this option should be safe to enable. + </para> + <para> + Members of the <literal>proc</literal> group are exempt from process + information hiding. + </para> + <para> + To allow a service <replaceable>foo</replaceable> to run without process + information hiding, set <programlisting> <link linkend="opt-systemd.services._name_.serviceConfig">systemd.services.<replaceable>foo</replaceable>.serviceConfig</link>.SupplementaryGroups = [ "proc" ]; </programlisting> - </para> - + </para> </chapter> diff --git a/nixos/modules/security/lock-kernel-modules.nix b/nixos/modules/security/lock-kernel-modules.nix index c81521ed9b08..fc9e7939d814 100644 --- a/nixos/modules/security/lock-kernel-modules.nix +++ b/nixos/modules/security/lock-kernel-modules.nix @@ -3,6 +3,10 @@ with lib; { + meta = { + maintainers = [ maintainers.joachifm ]; + }; + options = { security.lockKernelModules = mkOption { type = types.bool; diff --git a/nixos/modules/security/misc.nix b/nixos/modules/security/misc.nix new file mode 100644 index 000000000000..42f872b7b088 --- /dev/null +++ b/nixos/modules/security/misc.nix @@ -0,0 +1,39 @@ +{ config, lib, ... }: + +with lib; + +{ + meta = { + maintainers = [ maintainers.joachifm ]; + }; + + options = { + security.allowUserNamespaces = mkOption { + type = types.bool; + default = true; + description = '' + Whether to allow creation of user namespaces. A recurring problem + with user namespaces is the presence of code paths where the kernel's + permission checking logic fails to account for namespacing, instead + permitting a namespaced process to act outside the namespace with the + same privileges as it would have inside it. This is particularly + damaging in the common case of running as root within the namespace. + When user namespace creation is disallowed, attempting to create + a user namespace fails with "no space left on device" (ENOSPC). + ''; + }; + }; + + config = mkIf (!config.security.allowUserNamespaces) { + # Setting the number of allowed user namespaces to 0 effectively disables + # the feature at runtime. Note that root may raise the limit again + # at any time. + boot.kernel.sysctl."user.max_user_namespaces" = 0; + + assertions = [ + { assertion = config.nix.useSandbox -> config.security.allowUserNamespaces; + message = "`nix.useSandbox = true` conflicts with `!security.allowUserNamespaces`."; + } + ]; + }; +} diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index bef10b4fe614..926c6d77d3bb 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -548,6 +548,13 @@ in environment.etc = mapAttrsToList (n: v: makePAMService v) config.security.pam.services; + systemd.tmpfiles.rules = optionals + (any (s: s.updateWtmp) (attrValues config.security.pam.services)) + [ + "f /var/log/wtmp" + "f /var/log/lastlog" + ]; + security.pam.services = { other.text = '' diff --git a/nixos/modules/security/polkit.nix b/nixos/modules/security/polkit.nix index 04685f2c9ea1..7f1de81d5b70 100644 --- a/nixos/modules/security/polkit.nix +++ b/nixos/modules/security/polkit.nix @@ -88,11 +88,11 @@ in "polkit-agent-helper-1".source = "${pkgs.polkit.out}/lib/polkit-1/polkit-agent-helper-1"; }; - system.activationScripts.polkit = - '' - # Probably no more needed, clean up - rm -rf /var/lib/{polkit-1,PolicyKit} - ''; + systemd.tmpfiles.rules = [ + # Probably no more needed, clean up + "R /var/lib/polkit-1" + "R /var/lib/PolicyKit" + ]; users.users.polkituser = { description = "PolKit daemon"; diff --git a/nixos/modules/security/rngd.nix b/nixos/modules/security/rngd.nix index 3a1ffc55e5fe..63e00b548120 100644 --- a/nixos/modules/security/rngd.nix +++ b/nixos/modules/security/rngd.nix @@ -20,7 +20,6 @@ with lib; KERNEL=="random", TAG+="systemd" SUBSYSTEM=="cpu", ENV{MODALIAS}=="cpu:type:x86,*feature:*009E*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service" KERNEL=="hw_random", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service" - ${if config.services.tcsd.enable then "" else ''KERNEL=="tpm0", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service"''} ''; systemd.services.rngd = { @@ -30,8 +29,7 @@ with lib; description = "Hardware RNG Entropy Gatherer Daemon"; - serviceConfig.ExecStart = "${pkgs.rng_tools}/sbin/rngd -f -v" + - (if config.services.tcsd.enable then " --no-tpm=1" else ""); + serviceConfig.ExecStart = "${pkgs.rng-tools}/sbin/rngd -f -v"; }; }; } diff --git a/nixos/modules/security/wrappers/default.nix b/nixos/modules/security/wrappers/default.nix index 77e4b2a616d8..dcb9c8d4ed5f 100644 --- a/nixos/modules/security/wrappers/default.nix +++ b/nixos/modules/security/wrappers/default.nix @@ -180,35 +180,6 @@ in # programs to be wrapped. WRAPPER_PATH=${config.system.path}/bin:${config.system.path}/sbin - # Remove the old /var/setuid-wrappers path from the system... - # - # TODO: this is only necessary for upgrades 16.09 => 17.x; - # this conditional removal block needs to be removed after - # the release. - if [ -d /var/setuid-wrappers ]; then - rm -rf /var/setuid-wrappers - ln -s /run/wrappers/bin /var/setuid-wrappers - fi - - # Remove the old /run/setuid-wrappers-dir path from the - # system as well... - # - # TODO: this is only necessary for upgrades 16.09 => 17.x; - # this conditional removal block needs to be removed after - # the release. - if [ -d /run/setuid-wrapper-dirs ]; then - rm -rf /run/setuid-wrapper-dirs - ln -s /run/wrappers/bin /run/setuid-wrapper-dirs - fi - - # TODO: this is only necessary for upgrades 16.09 => 17.x; - # this conditional removal block needs to be removed after - # the release. - if readlink -f /run/booted-system | grep nixos-17 > /dev/null; then - rm -rf /run/setuid-wrapper-dirs - rm -rf /var/setuid-wrappers - fi - # We want to place the tmpdirs for the wrappers to the parent dir. wrapperDir=$(mktemp --directory --tmpdir="${parentWrapperDir}" wrappers.XXXXXXXXXX) chmod a+rx $wrapperDir diff --git a/nixos/modules/services/admin/salt/master.nix b/nixos/modules/services/admin/salt/master.nix index 165580b97837..c6b1b0cc0bd8 100644 --- a/nixos/modules/services/admin/salt/master.nix +++ b/nixos/modules/services/admin/salt/master.nix @@ -53,6 +53,9 @@ in Type = "notify"; NotifyAccess = "all"; }; + restartTriggers = [ + config.environment.etc."salt/master".source + ]; }; }; diff --git a/nixos/modules/services/admin/salt/minion.nix b/nixos/modules/services/admin/salt/minion.nix index 9ecefb32cfa8..c8fa9461a209 100644 --- a/nixos/modules/services/admin/salt/minion.nix +++ b/nixos/modules/services/admin/salt/minion.nix @@ -15,7 +15,6 @@ let # Default is in /etc/salt/pki/minion pki_dir = "/var/lib/salt/pki/minion"; } cfg.configuration; - configDir = pkgs.writeTextDir "minion" (builtins.toJSON fullConfig); in @@ -28,15 +27,24 @@ in default = {}; description = '' Salt minion configuration as Nix attribute set. - See <link xlink:href="https://docs.saltstack.com/en/latest/ref/configuration/minion.html"/> - for details. + See <link xlink:href="https://docs.saltstack.com/en/latest/ref/configuration/minion.html"/> + for details. ''; }; }; }; config = mkIf cfg.enable { - environment.systemPackages = with pkgs; [ salt ]; + environment = { + # Set this up in /etc/salt/minion so `salt-call`, etc. work. + # The alternatives are + # - passing --config-dir to all salt commands, not just the minion unit, + # - setting aglobal environment variable. + etc."salt/minion".source = pkgs.writeText "minion" ( + builtins.toJSON fullConfig + ); + systemPackages = with pkgs; [ salt ]; + }; systemd.services.salt-minion = { description = "Salt Minion"; wantedBy = [ "multi-user.target" ]; @@ -45,11 +53,14 @@ in utillinux ]; serviceConfig = { - ExecStart = "${pkgs.salt}/bin/salt-minion --config-dir=${configDir}"; + ExecStart = "${pkgs.salt}/bin/salt-minion"; LimitNOFILE = 8192; Type = "notify"; NotifyAccess = "all"; }; + restartTriggers = [ + config.environment.etc."salt/minion".source + ]; }; }; } diff --git a/nixos/modules/services/amqp/rabbitmq.nix b/nixos/modules/services/amqp/rabbitmq.nix index bb6fc0a104df..c6878dd67dbf 100644 --- a/nixos/modules/services/amqp/rabbitmq.nix +++ b/nixos/modules/services/amqp/rabbitmq.nix @@ -4,14 +4,18 @@ with lib; let cfg = config.services.rabbitmq; - config_file = pkgs.writeText "rabbitmq.config" cfg.config; - config_file_wo_suffix = builtins.substring 0 ((builtins.stringLength config_file) - 7) config_file; + + inherit (builtins) concatStringsSep; + + config_file_content = lib.generators.toKeyValue {} cfg.configItems; + config_file = pkgs.writeText "rabbitmq.conf" config_file_content; + + advanced_config_file = pkgs.writeText "advanced.config" cfg.config; in { ###### interface options = { services.rabbitmq = { - enable = mkOption { default = false; description = '' @@ -20,6 +24,15 @@ in { ''; }; + package = mkOption { + default = pkgs.rabbitmq-server; + type = types.package; + defaultText = "pkgs.rabbitmq-server"; + description = '' + Which rabbitmq package to use. + ''; + }; + listenAddress = mkOption { default = "127.0.0.1"; example = ""; @@ -30,6 +43,10 @@ in { <literal>guest</literal> with password <literal>guest</literal> by default, so you should delete this user if you intend to allow external access. + + Together with 'port' setting it's mostly an alias for + configItems."listeners.tcp.1" and it's left for backwards + compatibility with previous version of this module. ''; type = types.str; }; @@ -60,11 +77,29 @@ in { ''; }; + configItems = mkOption { + default = {}; + type = types.attrsOf types.str; + example = '' + { + "auth_backends.1.authn" = "rabbit_auth_backend_ldap"; + "auth_backends.1.authz" = "rabbit_auth_backend_internal"; + } + ''; + description = '' + New style config options. + + See http://www.rabbitmq.com/configure.html + ''; + }; + config = mkOption { default = ""; type = types.str; description = '' - Verbatim configuration file contents. + Verbatim advanced configuration file contents. + Prefered way is to use configItems. + See http://www.rabbitmq.com/configure.html ''; }; @@ -74,6 +109,12 @@ in { type = types.listOf types.str; description = "The names of plugins to enable"; }; + + pluginDirs = mkOption { + default = []; + type = types.listOf types.path; + description = "The list of directories containing external plugins"; + }; }; }; @@ -81,7 +122,10 @@ in { ###### implementation config = mkIf cfg.enable { - environment.systemPackages = [ pkgs.rabbitmq_server ]; + # This is needed so we will have 'rabbitmqctl' in our PATH + environment.systemPackages = [ cfg.package ]; + + services.epmd.enable = true; users.users.rabbitmq = { description = "RabbitMQ server user"; @@ -93,44 +137,54 @@ in { users.groups.rabbitmq.gid = config.ids.gids.rabbitmq; + services.rabbitmq.configItems = { + "listeners.tcp.1" = mkDefault "${cfg.listenAddress}:${toString cfg.port}"; + }; + systemd.services.rabbitmq = { description = "RabbitMQ Server"; wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; + after = [ "network.target" "epmd.socket" ]; + wants = [ "network.target" "epmd.socket" ]; - path = [ pkgs.rabbitmq_server pkgs.procps ]; + path = [ cfg.package pkgs.procps ]; environment = { RABBITMQ_MNESIA_BASE = "${cfg.dataDir}/mnesia"; - RABBITMQ_NODE_IP_ADDRESS = cfg.listenAddress; - RABBITMQ_NODE_PORT = toString cfg.port; RABBITMQ_LOGS = "-"; - RABBITMQ_SASL_LOGS = "-"; - RABBITMQ_PID_FILE = "${cfg.dataDir}/pid"; SYS_PREFIX = ""; + RABBITMQ_CONFIG_FILE = config_file; + RABBITMQ_PLUGINS_DIR = concatStringsSep ":" cfg.pluginDirs; RABBITMQ_ENABLED_PLUGINS_FILE = pkgs.writeText "enabled_plugins" '' [ ${concatStringsSep "," cfg.plugins} ]. ''; - } // optionalAttrs (cfg.config != "") { RABBITMQ_CONFIG_FILE = config_file_wo_suffix; }; + } // optionalAttrs (cfg.config != "") { RABBITMQ_ADVANCED_CONFIG_FILE = advanced_config_file; }; serviceConfig = { - ExecStart = "${pkgs.rabbitmq_server}/sbin/rabbitmq-server"; - ExecStop = "${pkgs.rabbitmq_server}/sbin/rabbitmqctl stop"; + PermissionsStartOnly = true; # preStart must be run as root + ExecStart = "${cfg.package}/sbin/rabbitmq-server"; + ExecStop = "${cfg.package}/sbin/rabbitmqctl shutdown"; User = "rabbitmq"; Group = "rabbitmq"; WorkingDirectory = cfg.dataDir; + Type = "notify"; + NotifyAccess = "all"; + UMask = "0027"; + LimitNOFILE = "100000"; + Restart = "on-failure"; + RestartSec = "10"; + TimeoutStartSec = "3600"; }; - postStart = '' - rabbitmqctl wait ${cfg.dataDir}/pid - ''; - preStart = '' ${optionalString (cfg.cookie != "") '' echo -n ${cfg.cookie} > ${cfg.dataDir}/.erlang.cookie + chown rabbitmq:rabbitmq ${cfg.dataDir}/.erlang.cookie chmod 600 ${cfg.dataDir}/.erlang.cookie ''} + mkdir -p /var/log/rabbitmq + chown rabbitmq:rabbitmq /var/log/rabbitmq ''; }; diff --git a/nixos/modules/services/cluster/kubernetes/default.nix b/nixos/modules/services/cluster/kubernetes/default.nix index aeaa6bd66c99..e63d91eb9aca 100644 --- a/nixos/modules/services/cluster/kubernetes/default.nix +++ b/nixos/modules/services/cluster/kubernetes/default.nix @@ -622,13 +622,6 @@ in { type = types.bool; }; - # TODO: remove this deprecated flag - cadvisorPort = mkOption { - description = "Kubernetes kubelet local cadvisor port."; - default = 4194; - type = types.int; - }; - clusterDns = mkOption { description = "Use alternative DNS."; default = "10.1.0.1"; @@ -862,7 +855,6 @@ in { --hostname-override=${cfg.kubelet.hostname} \ --allow-privileged=${boolToString cfg.kubelet.allowPrivileged} \ --root-dir=${cfg.dataDir} \ - --cadvisor_port=${toString cfg.kubelet.cadvisorPort} \ ${optionalString (cfg.kubelet.clusterDns != "") "--cluster-dns=${cfg.kubelet.clusterDns}"} \ ${optionalString (cfg.kubelet.clusterDomain != "") diff --git a/nixos/modules/services/computing/slurm/slurm.nix b/nixos/modules/services/computing/slurm/slurm.nix index 1e1c5bc9f035..cd481212db2d 100644 --- a/nixos/modules/services/computing/slurm/slurm.nix +++ b/nixos/modules/services/computing/slurm/slurm.nix @@ -6,12 +6,18 @@ let cfg = config.services.slurm; # configuration file can be generated by http://slurm.schedmd.com/configurator.html + + defaultUser = "slurm"; + configFile = pkgs.writeTextDir "slurm.conf" '' + ClusterName=${cfg.clusterName} + StateSaveLocation=${cfg.stateSaveLocation} + SlurmUser=${cfg.user} ${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}''} + ${toString (map (x: "NodeName=${x}\n") cfg.nodeName)} + ${toString (map (x: "PartitionName=${x}\n") cfg.partitionName)} PlugStackConfig=${plugStackConfig} ProctrackType=${cfg.procTrackType} ${cfg.extraConfig} @@ -23,12 +29,19 @@ let ${cfg.extraPlugstackConfig} ''; - cgroupConfig = pkgs.writeTextDir "cgroup.conf" '' ${cfg.extraCgroupConfig} ''; + slurmdbdConf = pkgs.writeTextDir "slurmdbd.conf" + '' + DbdHost=${cfg.dbdserver.dbdHost} + SlurmUser=${cfg.user} + StorageType=accounting_storage/mysql + ${cfg.dbdserver.extraConfig} + ''; + # slurm expects some additional config files to be # in the same directory as slurm.conf etcSlurm = pkgs.symlinkJoin { @@ -42,6 +55,8 @@ in ###### interface + meta.maintainers = [ maintainers.markuskowa ]; + options = { services.slurm = { @@ -59,6 +74,27 @@ in }; }; + dbdserver = { + enable = mkEnableOption "SlurmDBD service"; + + dbdHost = mkOption { + type = types.str; + default = config.networking.hostName; + description = '' + Hostname of the machine where <literal>slurmdbd</literal> + is running (i.e. name returned by <literal>hostname -s</literal>). + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra configuration for <literal>slurmdbd.conf</literal> + ''; + }; + }; + client = { enable = mkEnableOption "slurm client daemon"; }; @@ -105,10 +141,19 @@ in ''; }; + clusterName = mkOption { + type = types.str; + default = "default"; + example = "myCluster"; + description = '' + Necessary to distinguish accounting records in a multi-cluster environment. + ''; + }; + nodeName = mkOption { - type = types.nullOr types.str; - default = null; - example = "linux[1-32] CPUs=1 State=UNKNOWN"; + type = types.listOf types.str; + default = []; + example = literalExample ''[ "linux[1-32] CPUs=1 State=UNKNOWN" ];''; description = '' Name that SLURM uses to refer to a node (or base partition for BlueGene systems). Typically this would be the string that "/bin/hostname -s" @@ -117,9 +162,9 @@ in }; partitionName = mkOption { - type = types.nullOr types.str; - default = null; - example = "debug Nodes=linux[1-32] Default=YES MaxTime=INFINITE State=UP"; + type = types.listOf types.str; + default = []; + example = literalExample ''[ "debug Nodes=linux[1-32] Default=YES MaxTime=INFINITE State=UP" ];''; description = '' Name by which the partition may be referenced. Note that now you have to write the partition's parameters after the name. @@ -140,7 +185,7 @@ in }; procTrackType = mkOption { - type = types.string; + type = types.str; default = "proctrack/linuxproc"; description = '' Plugin to be used for process tracking on a job step basis. @@ -149,6 +194,25 @@ in ''; }; + stateSaveLocation = mkOption { + type = types.str; + default = "/var/spool/slurmctld"; + description = '' + Directory into which the Slurm controller, slurmctld, saves its state. + ''; + }; + + user = mkOption { + type = types.str; + default = defaultUser; + description = '' + Set this option when you want to run the slurmctld daemon + as something else than the default slurm user "slurm". + Note that the UID of this user needs to be the same + on all nodes. + ''; + }; + extraConfig = mkOption { default = ""; type = types.lines; @@ -174,6 +238,8 @@ in used when <literal>procTrackType=proctrack/cgroup</literal>. ''; }; + + }; }; @@ -210,12 +276,24 @@ in ''; }; - in mkIf (cfg.enableStools || cfg.client.enable || cfg.server.enable) { + in mkIf ( cfg.enableStools || + cfg.client.enable || + cfg.server.enable || + cfg.dbdserver.enable ) { environment.systemPackages = [ wrappedSlurm ]; services.munge.enable = mkDefault true; + # use a static uid as default to ensure it is the same on all nodes + users.users.slurm = mkIf (cfg.user == defaultUser) { + name = defaultUser; + group = "slurm"; + uid = config.ids.uids.slurm; + }; + + users.groups.slurm.gid = config.ids.uids.slurm; + systemd.services.slurmd = mkIf (cfg.client.enable) { path = with pkgs; [ wrappedSlurm coreutils ] ++ lib.optional cfg.enableSrunX11 slurm-spank-x11; @@ -251,6 +329,29 @@ in PIDFile = "/run/slurmctld.pid"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; }; + + preStart = '' + mkdir -p ${cfg.stateSaveLocation} + chown -R ${cfg.user}:slurm ${cfg.stateSaveLocation} + ''; + }; + + systemd.services.slurmdbd = mkIf (cfg.dbdserver.enable) { + path = with pkgs; [ wrappedSlurm munge coreutils ]; + + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "munged.service" "mysql.service" ]; + requires = [ "munged.service" "mysql.service" ]; + + # slurm strips the last component off the path + environment.SLURM_CONF = "${slurmdbdConf}/slurm.conf"; + + serviceConfig = { + Type = "forking"; + ExecStart = "${cfg.package}/bin/slurmdbd"; + PIDFile = "/run/slurmdbd.pid"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + }; }; }; diff --git a/nixos/modules/services/continuous-integration/buildbot/master.nix b/nixos/modules/services/continuous-integration/buildbot/master.nix index 8d767de37f00..0f07e6133bb5 100644 --- a/nixos/modules/services/continuous-integration/buildbot/master.nix +++ b/nixos/modules/services/continuous-integration/buildbot/master.nix @@ -6,8 +6,12 @@ with lib; let cfg = config.services.buildbot-master; + + python = cfg.package.pythonModule; + escapeStr = s: escape ["'"] s; - masterCfg = if cfg.masterCfg == null then pkgs.writeText "master.cfg" '' + + defaultMasterCfg = pkgs.writeText "master.cfg" '' from buildbot.plugins import * factory = util.BuildFactory() c = BuildmasterConfig = dict( @@ -27,8 +31,28 @@ let factory.addStep(step) ${cfg.extraConfig} - '' - else cfg.masterCfg; + ''; + + tacFile = pkgs.writeText "buildbot-master.tac" '' + import os + + from twisted.application import service + from buildbot.master import BuildMaster + + basedir = '${cfg.buildbotDir}' + + configfile = '${cfg.masterCfg}' + + # Default umask for server + umask = None + + # note: this line is matched against to check that this is a buildmaster + # directory; do not edit it. + application = service.Application('buildmaster') + + m = BuildMaster(basedir, configfile, umask) + m.setServiceParent(application) + ''; in { options = { @@ -66,9 +90,9 @@ in { }; masterCfg = mkOption { - type = types.nullOr types.path; + type = types.path; description = "Optionally pass master.cfg path. Other options in this configuration will be ignored."; - default = null; + default = defaultMasterCfg; example = "/etc/nixos/buildbot/master.cfg"; }; @@ -175,18 +199,25 @@ in { package = mkOption { type = types.package; - default = pkgs.buildbot-full; - defaultText = "pkgs.buildbot-full"; + default = pkgs.pythonPackages.buildbot-full; + defaultText = "pkgs.pythonPackages.buildbot-full"; description = "Package to use for buildbot."; - example = literalExample "pkgs.buildbot-full"; + example = literalExample "pkgs.python3Packages.buildbot-full"; }; packages = mkOption { - default = with pkgs; [ python27Packages.twisted git ]; + default = [ pkgs.git ]; example = literalExample "[ pkgs.git ]"; type = types.listOf types.package; description = "Packages to add to PATH for the buildbot process."; }; + + pythonPackages = mkOption { + default = pythonPackages: with pythonPackages; [ ]; + defaultText = "pythonPackages: with pythonPackages; [ ]"; + description = "Packages to add the to the PYTHONPATH of the buildbot process."; + example = literalExample "pythonPackages: with pythonPackages; [ requests ]"; + }; }; }; @@ -210,14 +241,15 @@ in { description = "Buildbot Continuous Integration Server."; after = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; - path = cfg.packages; + path = cfg.packages ++ cfg.pythonPackages python.pkgs; + environment.PYTHONPATH = "${python.withPackages (self: cfg.pythonPackages self ++ [ cfg.package ])}/${python.sitePackages}"; preStart = '' - env > envvars - mkdir -vp ${cfg.buildbotDir} - ln -sfv ${masterCfg} ${cfg.buildbotDir}/master.cfg - rm -fv $cfg.buildbotDir}/buildbot.tac - ${cfg.package}/bin/buildbot create-master ${cfg.buildbotDir} + mkdir -vp "${cfg.buildbotDir}" + # Link the tac file so buildbot command line tools recognize the directory + ln -sf "${tacFile}" "${cfg.buildbotDir}/buildbot.tac" + ${cfg.package}/bin/buildbot create-master --db "${cfg.dbUrl}" "${cfg.buildbotDir}" + rm -f buildbot.tac.new master.cfg.sample ''; serviceConfig = { @@ -225,12 +257,11 @@ in { User = cfg.user; Group = cfg.group; WorkingDirectory = cfg.home; - ExecStart = "${cfg.package}/bin/buildbot start --nodaemon ${cfg.buildbotDir}"; + # NOTE: call twistd directly with stdout logging for systemd + ExecStart = "${python.pkgs.twisted}/bin/twistd -o --nodaemon --pidfile= --logfile - --python ${tacFile}"; }; - }; }; meta.maintainers = with lib.maintainers; [ nand0p mic92 ]; - } diff --git a/nixos/modules/services/continuous-integration/buildbot/worker.nix b/nixos/modules/services/continuous-integration/buildbot/worker.nix index 67c541570b97..4130ec918a70 100644 --- a/nixos/modules/services/continuous-integration/buildbot/worker.nix +++ b/nixos/modules/services/continuous-integration/buildbot/worker.nix @@ -7,6 +7,40 @@ with lib; let cfg = config.services.buildbot-worker; + python = cfg.package.pythonModule; + + tacFile = pkgs.writeText "aur-buildbot-worker.tac" '' + import os + from io import open + + from buildbot_worker.bot import Worker + from twisted.application import service + + basedir = '${cfg.buildbotDir}' + + # note: this line is matched against to check that this is a worker + # directory; do not edit it. + application = service.Application('buildbot-worker') + + master_url_split = '${cfg.masterUrl}'.split(':') + buildmaster_host = master_url_split[0] + port = int(master_url_split[1]) + workername = '${cfg.workerUser}' + + with open('${cfg.workerPassFile}', 'r', encoding='utf-8') as passwd_file: + passwd = passwd_file.read().strip('\r\n') + keepalive = 600 + umask = None + maxdelay = 300 + numcpus = None + allow_shutdown = None + + s = Worker(buildmaster_host, port, workername, passwd, basedir, + keepalive, umask=umask, maxdelay=maxdelay, + numcpus=numcpus, allow_shutdown=allow_shutdown) + s.setServiceParent(application) + ''; + in { options = { services.buildbot-worker = { @@ -59,6 +93,23 @@ in { description = "Specifies the Buildbot Worker password."; }; + workerPassFile = mkOption { + type = types.path; + description = "File used to store the Buildbot Worker password"; + }; + + hostMessage = mkOption { + default = null; + type = types.nullOr types.str; + description = "Description of this worker"; + }; + + adminMessage = mkOption { + default = null; + type = types.nullOr types.str; + description = "Name of the administrator of this worker"; + }; + masterUrl = mkOption { default = "localhost:9989"; type = types.str; @@ -67,23 +118,24 @@ in { package = mkOption { type = types.package; - default = pkgs.buildbot-worker; - defaultText = "pkgs.buildbot-worker"; + default = pkgs.pythonPackages.buildbot-worker; + defaultText = "pkgs.pythonPackages.buildbot-worker"; description = "Package to use for buildbot worker."; - example = literalExample "pkgs.buildbot-worker"; + example = literalExample "pkgs.python3Packages.buildbot-worker"; }; packages = mkOption { - default = with pkgs; [ python27Packages.twisted git ]; + default = with pkgs; [ git ]; example = literalExample "[ pkgs.git ]"; type = types.listOf types.package; description = "Packages to add to PATH for the buildbot process."; }; - }; }; config = mkIf cfg.enable { + services.buildbot-worker.workerPassFile = mkDefault (pkgs.writeText "buildbot-worker-password" cfg.workerPass); + users.groups = optional (cfg.group == "bbworker") { name = "bbworker"; }; @@ -104,11 +156,16 @@ in { after = [ "network.target" "buildbot-master.service" ]; wantedBy = [ "multi-user.target" ]; path = cfg.packages; + environment.PYTHONPATH = "${python.withPackages (p: [ cfg.package ])}/${python.sitePackages}"; preStart = '' - mkdir -vp ${cfg.buildbotDir} - rm -fv $cfg.buildbotDir}/buildbot.tac - ${cfg.package}/bin/buildbot-worker create-worker ${cfg.buildbotDir} ${cfg.masterUrl} ${cfg.workerUser} ${cfg.workerPass} + mkdir -vp "${cfg.buildbotDir}/info" + ${optionalString (cfg.hostMessage != null) '' + ln -sf "${pkgs.writeText "buildbot-worker-host" cfg.hostMessage}" "${cfg.buildbotDir}/info/host" + ''} + ${optionalString (cfg.adminMessage != null) '' + ln -sf "${pkgs.writeText "buildbot-worker-admin" cfg.adminMessage}" "${cfg.buildbotDir}/info/admin" + ''} ''; serviceConfig = { @@ -116,11 +173,9 @@ in { User = cfg.user; Group = cfg.group; WorkingDirectory = cfg.home; - Environment = "PYTHONPATH=${cfg.package}/lib/python2.7/site-packages:${pkgs.python27Packages.future}/lib/python2.7/site-packages"; # NOTE: call twistd directly with stdout logging for systemd - #ExecStart = "${cfg.package}/bin/buildbot-worker start --nodaemon ${cfg.buildbotDir}"; - ExecStart = "${pkgs.python27Packages.twisted}/bin/twistd -n -l - -y ${cfg.buildbotDir}/buildbot.tac"; + ExecStart = "${python.pkgs.twisted}/bin/twistd --nodaemon --pidfile= --logfile - --python ${tacFile}"; }; }; diff --git a/nixos/modules/services/databases/foundationdb.xml b/nixos/modules/services/databases/foundationdb.xml index 7883680d46cc..bf4b644c9b86 100644 --- a/nixos/modules/services/databases/foundationdb.xml +++ b/nixos/modules/services/databases/foundationdb.xml @@ -3,42 +3,50 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="module-services-foundationdb"> - -<title>FoundationDB</title> - -<para><emphasis>Source:</emphasis> <filename>modules/services/databases/foundationdb.nix</filename></para> - -<para><emphasis>Upstream documentation:</emphasis> <link xlink:href="https://apple.github.io/foundationdb/"/></para> - -<para><emphasis>Maintainer:</emphasis> Austin Seipp</para> - -<para><emphasis>Available version(s):</emphasis> 5.1.x, 5.2.x, 6.0.x</para> - -<para>FoundationDB (or "FDB") is an open source, distributed, transactional -key-value store.</para> - -<section xml:id="module-services-foundationdb-configuring"><title>Configuring and basic setup</title> - -<para>To enable FoundationDB, add the following to your -<filename>configuration.nix</filename>: - + <title>FoundationDB</title> + <para> + <emphasis>Source:</emphasis> + <filename>modules/services/databases/foundationdb.nix</filename> + </para> + <para> + <emphasis>Upstream documentation:</emphasis> + <link xlink:href="https://apple.github.io/foundationdb/"/> + </para> + <para> + <emphasis>Maintainer:</emphasis> Austin Seipp + </para> + <para> + <emphasis>Available version(s):</emphasis> 5.1.x, 5.2.x, 6.0.x + </para> + <para> + FoundationDB (or "FDB") is an open source, distributed, transactional + key-value store. + </para> + <section xml:id="module-services-foundationdb-configuring"> + <title>Configuring and basic setup</title> + + <para> + To enable FoundationDB, add the following to your + <filename>configuration.nix</filename>: <programlisting> services.foundationdb.enable = true; services.foundationdb.package = pkgs.foundationdb52; # FoundationDB 5.2.x </programlisting> -</para> - -<para>The <option>services.foundationdb.package</option> option is required, -and must always be specified. Due to the fact FoundationDB network protocols and -on-disk storage formats may change between (major) versions, and upgrades must -be explicitly handled by the user, you must always manually specify this -yourself so that the NixOS module will use the proper version. Note that minor, -bugfix releases are always compatible.</para> - -<para>After running <command>nixos-rebuild</command>, you can verify whether -FoundationDB is running by executing <command>fdbcli</command> (which is added -to <option>environment.systemPackages</option>): - + </para> + + <para> + The <option>services.foundationdb.package</option> option is required, and + must always be specified. Due to the fact FoundationDB network protocols and + on-disk storage formats may change between (major) versions, and upgrades + must be explicitly handled by the user, you must always manually specify + this yourself so that the NixOS module will use the proper version. Note + that minor, bugfix releases are always compatible. + </para> + + <para> + After running <command>nixos-rebuild</command>, you can verify whether + FoundationDB is running by executing <command>fdbcli</command> (which is + added to <option>environment.systemPackages</option>): <programlisting> $ sudo -u foundationdb fdbcli Using cluster file `/etc/foundationdb/fdb.cluster'. @@ -66,14 +74,14 @@ Cluster: fdb> </programlisting> -</para> - -<para>You can also write programs using the available client libraries. -For example, the following Python program can be run in order to grab the -cluster status, as a quick example. (This example uses -<command>nix-shell</command> shebang support to automatically supply the -necessary Python modules). - + </para> + + <para> + You can also write programs using the available client libraries. For + example, the following Python program can be run in order to grab the + cluster status, as a quick example. (This example uses + <command>nix-shell</command> shebang support to automatically supply the + necessary Python modules). <programlisting> a@link> cat fdb-status.py #! /usr/bin/env nix-shell @@ -100,255 +108,336 @@ a@link> ./fdb-status.py FoundationDB available: True a@link> </programlisting> -</para> - -<para>FoundationDB is run under the <command>foundationdb</command> user and -group by default, but this may be changed in the NixOS configuration. The -systemd unit <command>foundationdb.service</command> controls the -<command>fdbmonitor</command> process.</para> - -<para>By default, the NixOS module for FoundationDB creates a single -SSD-storage based database for development and basic usage. This storage engine -is designed for SSDs and will perform poorly on HDDs; however it can handle far -more data than the alternative "memory" engine and is a better default choice -for most deployments. (Note that you can change the storage backend on-the-fly -for a given FoundationDB cluster using <command>fdbcli</command>.)</para> - -<para>Furthermore, only 1 server process and 1 backup agent are started in the -default configuration. See below for more on scaling to increase this.</para> - -<para>FoundationDB stores all data for all server processes under -<filename>/var/lib/foundationdb</filename>. You can override this using -<option>services.foundationdb.dataDir</option>, e.g. - + </para> + + <para> + FoundationDB is run under the <command>foundationdb</command> user and group + by default, but this may be changed in the NixOS configuration. The systemd + unit <command>foundationdb.service</command> controls the + <command>fdbmonitor</command> process. + </para> + + <para> + By default, the NixOS module for FoundationDB creates a single SSD-storage + based database for development and basic usage. This storage engine is + designed for SSDs and will perform poorly on HDDs; however it can handle far + more data than the alternative "memory" engine and is a better default + choice for most deployments. (Note that you can change the storage backend + on-the-fly for a given FoundationDB cluster using + <command>fdbcli</command>.) + </para> + + <para> + Furthermore, only 1 server process and 1 backup agent are started in the + default configuration. See below for more on scaling to increase this. + </para> + + <para> + FoundationDB stores all data for all server processes under + <filename>/var/lib/foundationdb</filename>. You can override this using + <option>services.foundationdb.dataDir</option>, e.g. <programlisting> services.foundationdb.dataDir = "/data/fdb"; </programlisting> - -</para> - -<para>Similarly, logs are stored under -<filename>/var/log/foundationdb</filename> by default, and there is a -corresponding <option>services.foundationdb.logDir</option> as well.</para> - -</section> - -<section xml:id="module-services-foundationdb-scaling"><title>Scaling processes and backup agents</title> - -<para>Scaling the number of server processes is quite easy; simply specify -<option>services.foundationdb.serverProcesses</option> to be the number of -FoundationDB worker processes that should be started on the machine.</para> - -<para>FoundationDB worker processes typically require 4GB of RAM per-process at -minimum for good performance, so this option is set to 1 by default since the -maximum amount of RAM is unknown. You're advised to abide by this restriction, -so pick a number of processes so that each has 4GB or more.</para> - -<para>A similar option exists in order to scale backup agent processes, -<option>services.foundationdb.backupProcesses</option>. Backup agents are not -as performance/RAM sensitive, so feel free to experiment with the number of -available backup processes.</para> - -</section> - -<section xml:id="module-services-foundationdb-clustering"><title>Clustering</title> - -<para>FoundationDB on NixOS works similarly to other Linux systems, so this -section will be brief. Please refer to the full FoundationDB documentation for -more on clustering.</para> - -<para>FoundationDB organizes clusters using a set of -<emphasis>coordinators</emphasis>, which are just specially-designated worker -processes. By default, every installation of FoundationDB on NixOS will start -as its own individual cluster, with a single coordinator: the first worker -process on <command>localhost</command>.</para> - -<para>Coordinators are specified globally using the -<command>/etc/foundationdb/fdb.cluster</command> file, which all servers and -client applications will use to find and join coordinators. Note that this file -<emphasis>can not</emphasis> be managed by NixOS so easily: FoundationDB is -designed so that it will rewrite the file at runtime for all clients and nodes -when cluster coordinators change, with clients transparently handling this -without intervention. It is fundamentally a mutable file, and you should not -try to manage it in any way in NixOS.</para> - -<para>When dealing with a cluster, there are two main things you want to -do:</para> - -<itemizedlist> - <listitem><para>Add a node to the cluster for storage/compute.</para></listitem> - <listitem><para>Promote an ordinary worker to a coordinator.</para></listitem> -</itemizedlist> - -<para>A node must already be a member of the cluster in order to properly be -promoted to a coordinator, so you must always add it first if you wish to -promote it.</para> - -<para>To add a machine to a FoundationDB cluster:</para> - -<itemizedlist> - <listitem><para>Choose one of the servers to start as the initial coordinator. - </para></listitem> - <listitem><para>Copy the <command>/etc/foundationdb/fdb.cluster</command> file - from this server to all the other servers. Restart FoundationDB on all of - these other servers, so they join the cluster.</para></listitem> - <listitem><para>All of these servers are now connected and working together - in the cluster, under the chosen coordinator.</para></listitem> -</itemizedlist> - -<para>At this point, you can add as many nodes as you want by just repeating -the above steps. By default there will still be a single coordinator: you can -use <command>fdbcli</command> to change this and add new coordinators.</para> - -<para>As a convenience, FoundationDB can automatically assign coordinators -based on the redundancy mode you wish to achieve for the cluster. Once all the -nodes have been joined, simply set the replication policy, and then issue the -<command>coordinators auto</command> command</para> - -<para>For example, assuming we have 3 nodes available, we can enable double -redundancy mode, then auto-select coordinators. For double redundancy, 3 -coordinators is ideal: therefore FoundationDB will make -<emphasis>every</emphasis> node a coordinator automatically:</para> + </para> + + <para> + Similarly, logs are stored under <filename>/var/log/foundationdb</filename> + by default, and there is a corresponding + <option>services.foundationdb.logDir</option> as well. + </para> + </section> + <section xml:id="module-services-foundationdb-scaling"> + <title>Scaling processes and backup agents</title> + + <para> + Scaling the number of server processes is quite easy; simply specify + <option>services.foundationdb.serverProcesses</option> to be the number of + FoundationDB worker processes that should be started on the machine. + </para> + + <para> + FoundationDB worker processes typically require 4GB of RAM per-process at + minimum for good performance, so this option is set to 1 by default since + the maximum amount of RAM is unknown. You're advised to abide by this + restriction, so pick a number of processes so that each has 4GB or more. + </para> + + <para> + A similar option exists in order to scale backup agent processes, + <option>services.foundationdb.backupProcesses</option>. Backup agents are + not as performance/RAM sensitive, so feel free to experiment with the number + of available backup processes. + </para> + </section> + <section xml:id="module-services-foundationdb-clustering"> + <title>Clustering</title> + + <para> + FoundationDB on NixOS works similarly to other Linux systems, so this + section will be brief. Please refer to the full FoundationDB documentation + for more on clustering. + </para> + + <para> + FoundationDB organizes clusters using a set of + <emphasis>coordinators</emphasis>, which are just specially-designated + worker processes. By default, every installation of FoundationDB on NixOS + will start as its own individual cluster, with a single coordinator: the + first worker process on <command>localhost</command>. + </para> + + <para> + Coordinators are specified globally using the + <command>/etc/foundationdb/fdb.cluster</command> file, which all servers and + client applications will use to find and join coordinators. Note that this + file <emphasis>can not</emphasis> be managed by NixOS so easily: + FoundationDB is designed so that it will rewrite the file at runtime for all + clients and nodes when cluster coordinators change, with clients + transparently handling this without intervention. It is fundamentally a + mutable file, and you should not try to manage it in any way in NixOS. + </para> + + <para> + When dealing with a cluster, there are two main things you want to do: + </para> + + <itemizedlist> + <listitem> + <para> + Add a node to the cluster for storage/compute. + </para> + </listitem> + <listitem> + <para> + Promote an ordinary worker to a coordinator. + </para> + </listitem> + </itemizedlist> + + <para> + A node must already be a member of the cluster in order to properly be + promoted to a coordinator, so you must always add it first if you wish to + promote it. + </para> + + <para> + To add a machine to a FoundationDB cluster: + </para> + + <itemizedlist> + <listitem> + <para> + Choose one of the servers to start as the initial coordinator. + </para> + </listitem> + <listitem> + <para> + Copy the <command>/etc/foundationdb/fdb.cluster</command> file from this + server to all the other servers. Restart FoundationDB on all of these + other servers, so they join the cluster. + </para> + </listitem> + <listitem> + <para> + All of these servers are now connected and working together in the + cluster, under the chosen coordinator. + </para> + </listitem> + </itemizedlist> + + <para> + At this point, you can add as many nodes as you want by just repeating the + above steps. By default there will still be a single coordinator: you can + use <command>fdbcli</command> to change this and add new coordinators. + </para> + + <para> + As a convenience, FoundationDB can automatically assign coordinators based + on the redundancy mode you wish to achieve for the cluster. Once all the + nodes have been joined, simply set the replication policy, and then issue + the <command>coordinators auto</command> command + </para> + + <para> + For example, assuming we have 3 nodes available, we can enable double + redundancy mode, then auto-select coordinators. For double redundancy, 3 + coordinators is ideal: therefore FoundationDB will make + <emphasis>every</emphasis> node a coordinator automatically: + </para> <programlisting> fdbcli> configure double ssd fdbcli> coordinators auto </programlisting> -<para>This will transparently update all the servers within seconds, and -appropriately rewrite the <command>fdb.cluster</command> file, as well as -informing all client processes to do the same.</para> - -</section> - -<section xml:id="module-services-foundationdb-connectivity"><title>Client connectivity</title> - -<para>By default, all clients must use the current -<command>fdb.cluster</command> file to access a given FoundationDB cluster. -This file is located by default in -<command>/etc/foundationdb/fdb.cluster</command> on all machines with the -FoundationDB service enabled, so you may copy the active one from your cluster -to a new node in order to connect, if it is not part of the cluster.</para> - -</section> - -<section xml:id="module-services-foundationdb-authorization"><title>Client authorization and TLS</title> - -<para>By default, any user who can connect to a FoundationDB process with the -correct cluster configuration can access anything. FoundationDB uses a -pluggable design to transport security, and out of the box it supports a -LibreSSL-based plugin for TLS support. This plugin not only does in-flight -encryption, but also performs client authorization based on the given -endpoint's certificate chain. For example, a FoundationDB server may be -configured to only accept client connections over TLS, where the client TLS -certificate is from organization <emphasis>Acme Co</emphasis> in the -<emphasis>Research and Development</emphasis> unit.</para> - -<para>Configuring TLS with FoundationDB is done using the -<option>services.foundationdb.tls</option> options in order to control the peer -verification string, as well as the certificate and its private key.</para> - -<para>Note that the certificate and its private key must be accessible to the -FoundationDB user account that the server runs under. These files are also NOT -managed by NixOS, as putting them into the store may reveal private -information.</para> - -<para>After you have a key and certificate file in place, it is not enough to -simply set the NixOS module options -- you must also configure the -<command>fdb.cluster</command> file to specify that a given set of coordinators -use TLS. This is as simple as adding the suffix <command>:tls</command> to your -cluster coordinator configuration, after the port number. For example, assuming -you have a coordinator on localhost with the default configuration, simply -specifying:</para> + <para> + This will transparently update all the servers within seconds, and + appropriately rewrite the <command>fdb.cluster</command> file, as well as + informing all client processes to do the same. + </para> + </section> + <section xml:id="module-services-foundationdb-connectivity"> + <title>Client connectivity</title> + + <para> + By default, all clients must use the current <command>fdb.cluster</command> + file to access a given FoundationDB cluster. This file is located by default + in <command>/etc/foundationdb/fdb.cluster</command> on all machines with the + FoundationDB service enabled, so you may copy the active one from your + cluster to a new node in order to connect, if it is not part of the cluster. + </para> + </section> + <section xml:id="module-services-foundationdb-authorization"> + <title>Client authorization and TLS</title> + + <para> + By default, any user who can connect to a FoundationDB process with the + correct cluster configuration can access anything. FoundationDB uses a + pluggable design to transport security, and out of the box it supports a + LibreSSL-based plugin for TLS support. This plugin not only does in-flight + encryption, but also performs client authorization based on the given + endpoint's certificate chain. For example, a FoundationDB server may be + configured to only accept client connections over TLS, where the client TLS + certificate is from organization <emphasis>Acme Co</emphasis> in the + <emphasis>Research and Development</emphasis> unit. + </para> + + <para> + Configuring TLS with FoundationDB is done using the + <option>services.foundationdb.tls</option> options in order to control the + peer verification string, as well as the certificate and its private key. + </para> + + <para> + Note that the certificate and its private key must be accessible to the + FoundationDB user account that the server runs under. These files are also + NOT managed by NixOS, as putting them into the store may reveal private + information. + </para> + + <para> + After you have a key and certificate file in place, it is not enough to + simply set the NixOS module options -- you must also configure the + <command>fdb.cluster</command> file to specify that a given set of + coordinators use TLS. This is as simple as adding the suffix + <command>:tls</command> to your cluster coordinator configuration, after the + port number. For example, assuming you have a coordinator on localhost with + the default configuration, simply specifying: + </para> <programlisting> XXXXXX:XXXXXX@127.0.0.1:4500:tls </programlisting> -<para>will configure all clients and server processes to use TLS from now -on.</para> - -</section> - -<section xml:id="module-services-foundationdb-disaster-recovery"><title>Backups and Disaster Recovery</title> - -<para>The usual rules for doing FoundationDB backups apply on NixOS as written -in the FoundationDB manual. However, one important difference is the security -profile for NixOS: by default, the <command>foundationdb</command> systemd unit -uses <emphasis>Linux namespaces</emphasis> to restrict write access to the -system, except for the log directory, data directory, and the -<command>/etc/foundationdb/</command> directory. This is enforced by default -and cannot be disabled.</para> - -<para>However, a side effect of this is that the <command>fdbbackup</command> -command doesn't work properly for local filesystem backups: FoundationDB uses a -server process alongside the database processes to perform backups and copy the -backups to the filesystem. As a result, this process is put under the -restricted namespaces above: the backup process can only write to a limited -number of paths.</para> - -<para>In order to allow flexible backup locations on local disks, the -FoundationDB NixOS module supports a -<option>services.foundationdb.extraReadWritePaths</option> option. This option -takes a list of paths, and adds them to the systemd unit, allowing the -processes inside the service to write (and read) the specified -directories.</para> - -<para>For example, to create backups in <command>/opt/fdb-backups</command>, -first set up the paths in the module options:</para> + <para> + will configure all clients and server processes to use TLS from now on. + </para> + </section> + <section xml:id="module-services-foundationdb-disaster-recovery"> + <title>Backups and Disaster Recovery</title> + + <para> + The usual rules for doing FoundationDB backups apply on NixOS as written in + the FoundationDB manual. However, one important difference is the security + profile for NixOS: by default, the <command>foundationdb</command> systemd + unit uses <emphasis>Linux namespaces</emphasis> to restrict write access to + the system, except for the log directory, data directory, and the + <command>/etc/foundationdb/</command> directory. This is enforced by default + and cannot be disabled. + </para> + + <para> + However, a side effect of this is that the <command>fdbbackup</command> + command doesn't work properly for local filesystem backups: FoundationDB + uses a server process alongside the database processes to perform backups + and copy the backups to the filesystem. As a result, this process is put + under the restricted namespaces above: the backup process can only write to + a limited number of paths. + </para> + + <para> + In order to allow flexible backup locations on local disks, the FoundationDB + NixOS module supports a + <option>services.foundationdb.extraReadWritePaths</option> option. This + option takes a list of paths, and adds them to the systemd unit, allowing + the processes inside the service to write (and read) the specified + directories. + </para> + + <para> + For example, to create backups in <command>/opt/fdb-backups</command>, first + set up the paths in the module options: + </para> <programlisting> services.foundationdb.extraReadWritePaths = [ "/opt/fdb-backups" ]; </programlisting> -<para>Restart the FoundationDB service, and it will now be able to write to -this directory (even if it does not yet exist.) Note: this path -<emphasis>must</emphasis> exist before restarting the unit. Otherwise, systemd -will not include it in the private FoundationDB namespace (and it will not add -it dynamically at runtime).</para> + <para> + Restart the FoundationDB service, and it will now be able to write to this + directory (even if it does not yet exist.) Note: this path + <emphasis>must</emphasis> exist before restarting the unit. Otherwise, + systemd will not include it in the private FoundationDB namespace (and it + will not add it dynamically at runtime). + </para> -<para>You can now perform a backup:</para> + <para> + You can now perform a backup: + </para> <programlisting> $ sudo -u foundationdb fdbbackup start -t default -d file:///opt/fdb-backups $ sudo -u foundationdb fdbbackup status -t default </programlisting> - -</section> - -<section xml:id="module-services-foundationdb-limitations"><title>Known limitations</title> - -<para>The FoundationDB setup for NixOS should currently be considered beta. -FoundationDB is not new software, but the NixOS compilation and integration has -only undergone fairly basic testing of all the available functionality.</para> - -<itemizedlist> - <listitem><para>There is no way to specify individual parameters for - individual <command>fdbserver</command> processes. Currently, all server - processes inherit all the global <command>fdbmonitor</command> settings. - </para></listitem> - <listitem><para>Ruby bindings are not currently installed.</para></listitem> - <listitem><para>Go bindings are not currently installed.</para></listitem> -</itemizedlist> - -</section> - -<section xml:id="module-services-foundationdb-options"><title>Options</title> - -<para>NixOS's FoundationDB module allows you to configure all of the most -relevant configuration options for <command>fdbmonitor</command>, matching it -quite closely. A complete list of options for the FoundationDB module may be -found <link linkend="opt-services.foundationdb.enable">here</link>. You should -also read the FoundationDB documentation as well.</para> - -</section> - -<section xml:id="module-services-foundationdb-full-docs"><title>Full documentation</title> - -<para>FoundationDB is a complex piece of software, and requires careful -administration to properly use. Full documentation for administration can be -found here: <link xlink:href="https://apple.github.io/foundationdb/"/>.</para> - -</section> - + </section> + <section xml:id="module-services-foundationdb-limitations"> + <title>Known limitations</title> + + <para> + The FoundationDB setup for NixOS should currently be considered beta. + FoundationDB is not new software, but the NixOS compilation and integration + has only undergone fairly basic testing of all the available functionality. + </para> + + <itemizedlist> + <listitem> + <para> + There is no way to specify individual parameters for individual + <command>fdbserver</command> processes. Currently, all server processes + inherit all the global <command>fdbmonitor</command> settings. + </para> + </listitem> + <listitem> + <para> + Ruby bindings are not currently installed. + </para> + </listitem> + <listitem> + <para> + Go bindings are not currently installed. + </para> + </listitem> + </itemizedlist> + </section> + <section xml:id="module-services-foundationdb-options"> + <title>Options</title> + + <para> + NixOS's FoundationDB module allows you to configure all of the most relevant + configuration options for <command>fdbmonitor</command>, matching it quite + closely. A complete list of options for the FoundationDB module may be found + <link linkend="opt-services.foundationdb.enable">here</link>. You should + also read the FoundationDB documentation as well. + </para> + </section> + <section xml:id="module-services-foundationdb-full-docs"> + <title>Full documentation</title> + + <para> + FoundationDB is a complex piece of software, and requires careful + administration to properly use. Full documentation for administration can be + found here: <link xlink:href="https://apple.github.io/foundationdb/"/>. + </para> + </section> </chapter> diff --git a/nixos/modules/services/databases/postgresql.nix b/nixos/modules/services/databases/postgresql.nix index f59fb1c81772..6edb1503c233 100644 --- a/nixos/modules/services/databases/postgresql.nix +++ b/nixos/modules/services/databases/postgresql.nix @@ -55,7 +55,7 @@ in package = mkOption { type = types.package; - example = literalExample "pkgs.postgresql96"; + example = literalExample "pkgs.postgresql_9_6"; description = '' PostgreSQL package to use. ''; @@ -118,7 +118,7 @@ in extraPlugins = mkOption { type = types.listOf types.path; default = []; - example = literalExample "[ (pkgs.postgis.override { postgresql = pkgs.postgresql94; }) ]"; + example = literalExample "[ (pkgs.postgis.override { postgresql = pkgs.postgresql_9_4; }) ]"; description = '' When this list contains elements a new store path is created. PostgreSQL and the elements are symlinked into it. Then pg_config, @@ -167,9 +167,9 @@ in # Note: when changing the default, make it conditional on # ‘system.stateVersion’ to maintain compatibility with existing # systems! - mkDefault (if versionAtLeast config.system.stateVersion "17.09" then pkgs.postgresql96 - else if versionAtLeast config.system.stateVersion "16.03" then pkgs.postgresql95 - else pkgs.postgresql94); + mkDefault (if versionAtLeast config.system.stateVersion "17.09" then pkgs.postgresql_9_6 + else if versionAtLeast config.system.stateVersion "16.03" then pkgs.postgresql_9_5 + else pkgs.postgresql_9_4); services.postgresql.dataDir = mkDefault (if versionAtLeast config.system.stateVersion "17.09" then "/var/lib/postgresql/${config.services.postgresql.package.psqlSchema}" @@ -188,6 +188,8 @@ in uid = config.ids.uids.postgres; group = "postgres"; description = "PostgreSQL server user"; + home = "${cfg.dataDir}"; + useDefaultShell = true; }; users.groups.postgres.gid = config.ids.gids.postgres; diff --git a/nixos/modules/services/databases/postgresql.xml b/nixos/modules/services/databases/postgresql.xml index 1aaf33963245..14f4d4909bc0 100644 --- a/nixos/modules/services/databases/postgresql.xml +++ b/nixos/modules/services/databases/postgresql.xml @@ -3,36 +3,39 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="module-postgresql"> - -<title>PostgreSQL</title> - + <title>PostgreSQL</title> <!-- FIXME: render nicely --> - <!-- FIXME: source can be added automatically --> -<para><emphasis>Source:</emphasis> <filename>modules/services/databases/postgresql.nix</filename></para> - -<para><emphasis>Upstream documentation:</emphasis> <link xlink:href="http://www.postgresql.org/docs/"/></para> - + <para> + <emphasis>Source:</emphasis> + <filename>modules/services/databases/postgresql.nix</filename> + </para> + <para> + <emphasis>Upstream documentation:</emphasis> + <link xlink:href="http://www.postgresql.org/docs/"/> + </para> <!-- FIXME: more stuff, like maintainer? --> - -<para>PostgreSQL is an advanced, free relational database.<!-- MORE --></para> - -<section xml:id="module-services-postgres-configuring"><title>Configuring</title> - -<para>To enable PostgreSQL, add the following to your -<filename>configuration.nix</filename>: - + <para> + PostgreSQL is an advanced, free relational database. +<!-- MORE --> + </para> + <section xml:id="module-services-postgres-configuring"> + <title>Configuring</title> + + <para> + To enable PostgreSQL, add the following to your + <filename>configuration.nix</filename>: <programlisting> <xref linkend="opt-services.postgresql.enable"/> = true; -<xref linkend="opt-services.postgresql.package"/> = pkgs.postgresql94; +<xref linkend="opt-services.postgresql.package"/> = pkgs.postgresql_9_4; </programlisting> - -Note that you are required to specify the desired version of -PostgreSQL (e.g. <literal>pkgs.postgresql94</literal>). Since -upgrading your PostgreSQL version requires a database dump and reload -(see below), NixOS cannot provide a default value for -<xref linkend="opt-services.postgresql.package"/> such as the most recent -release of PostgreSQL.</para> + Note that you are required to specify the desired version of PostgreSQL + (e.g. <literal>pkgs.postgresql_9_4</literal>). Since upgrading your + PostgreSQL version requires a database dump and reload (see below), NixOS + cannot provide a default value for + <xref linkend="opt-services.postgresql.package"/> such as the most recent + release of PostgreSQL. + </para> <!-- <para>After running <command>nixos-rebuild</command>, you can verify @@ -47,31 +50,28 @@ alice=> </screen> --> -<para>By default, PostgreSQL stores its databases in -<filename>/var/db/postgresql</filename>. You can override this using -<xref linkend="opt-services.postgresql.dataDir"/>, e.g. - + <para> + By default, PostgreSQL stores its databases in + <filename>/var/db/postgresql</filename>. You can override this using + <xref linkend="opt-services.postgresql.dataDir"/>, e.g. <programlisting> <xref linkend="opt-services.postgresql.dataDir"/> = "/data/postgresql"; </programlisting> - -</para> - -</section> - - -<section xml:id="module-services-postgres-upgrading"><title>Upgrading</title> - -<para>FIXME: document dump/upgrade/load cycle.</para> - -</section> - - -<section xml:id="module-services-postgres-options"><title>Options</title> - - <para>A complete list of options for the PostgreSQL module may be found <link linkend="opt-services.postgresql.enable">here</link>.</para> - -</section> - - + </para> + </section> + <section xml:id="module-services-postgres-upgrading"> + <title>Upgrading</title> + + <para> + FIXME: document dump/upgrade/load cycle. + </para> + </section> + <section xml:id="module-services-postgres-options"> + <title>Options</title> + + <para> + A complete list of options for the PostgreSQL module may be found + <link linkend="opt-services.postgresql.enable">here</link>. + </para> + </section> </chapter> diff --git a/nixos/modules/services/desktops/flatpak.xml b/nixos/modules/services/desktops/flatpak.xml index d9c8b711c450..8045d5fa14f8 100644 --- a/nixos/modules/services/desktops/flatpak.xml +++ b/nixos/modules/services/desktops/flatpak.xml @@ -3,51 +3,54 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="module-services-flatpak"> - -<title>Flatpak</title> - -<para><emphasis>Source:</emphasis> <filename>modules/services/desktop/flatpak.nix</filename></para> - -<para><emphasis>Upstream documentation:</emphasis> <link xlink:href="https://github.com/flatpak/flatpak/wiki"/></para> - -<para>Flatpak is a system for building, distributing, and running sandboxed desktop applications on Linux.</para> - -<para> - To enable Flatpak, add the following to your <filename>configuration.nix</filename>: - - <programlisting> + <title>Flatpak</title> + <para> + <emphasis>Source:</emphasis> + <filename>modules/services/desktop/flatpak.nix</filename> + </para> + <para> + <emphasis>Upstream documentation:</emphasis> + <link xlink:href="https://github.com/flatpak/flatpak/wiki"/> + </para> + <para> + Flatpak is a system for building, distributing, and running sandboxed desktop + applications on Linux. + </para> + <para> + To enable Flatpak, add the following to your + <filename>configuration.nix</filename>: +<programlisting> <xref linkend="opt-services.flatpak.enable"/> = true; </programlisting> -</para> - -<para> - For the sandboxed apps to work correctly, desktop integration portals need to be installed. If you run GNOME, this will be handled automatically for you; in other cases, you will need to add something like the following to your <filename>configuration.nix</filename>: - - <programlisting> + </para> + <para> + For the sandboxed apps to work correctly, desktop integration portals need to + be installed. If you run GNOME, this will be handled automatically for you; + in other cases, you will need to add something like the following to your + <filename>configuration.nix</filename>: +<programlisting> <xref linkend="opt-services.flatpak.extraPortals"/> = [ pkgs.xdg-desktop-portal-gtk ]; </programlisting> -</para> - -<para> - Then, you will need to add a repository, for example, <link xlink:href="https://github.com/flatpak/flatpak/wiki">Flathub</link>, either using the following commands: - - <programlisting> + </para> + <para> + Then, you will need to add a repository, for example, + <link xlink:href="https://github.com/flatpak/flatpak/wiki">Flathub</link>, + either using the following commands: +<programlisting> flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo flatpak update </programlisting> - - or by opening the <link xlink:href="https://flathub.org/repo/flathub.flatpakrepo">repository file</link> in GNOME Software. -</para> - -<para> + or by opening the + <link xlink:href="https://flathub.org/repo/flathub.flatpakrepo">repository + file</link> in GNOME Software. + </para> + <para> Finally, you can search and install programs: - - <programlisting> +<programlisting> flatpak search bustle flatpak install flathub org.freedesktop.Bustle flatpak run org.freedesktop.Bustle </programlisting> - Again, GNOME Software offers graphical interface for these tasks. -</para> + </para> </chapter> diff --git a/nixos/modules/services/desktops/gnome3/rygel.nix b/nixos/modules/services/desktops/gnome3/rygel.nix new file mode 100644 index 000000000000..55d5e703aa19 --- /dev/null +++ b/nixos/modules/services/desktops/gnome3/rygel.nix @@ -0,0 +1,30 @@ +# rygel service. +{ config, lib, pkgs, ... }: + +with lib; + +{ + ###### interface + options = { + services.gnome3.rygel = { + enable = mkOption { + default = false; + description = '' + Whether to enable Rygel UPnP Mediaserver. + + You will need to also allow UPnP connections in firewall, see the following <link xlink:href="https://github.com/NixOS/nixpkgs/pull/45045#issuecomment-416030795">comment</link>. + ''; + type = types.bool; + }; + }; + }; + + ###### implementation + config = mkIf config.services.gnome3.rygel.enable { + environment.systemPackages = [ pkgs.gnome3.rygel ]; + + services.dbus.packages = [ pkgs.gnome3.rygel ]; + + systemd.packages = [ pkgs.gnome3.rygel ]; + }; +} diff --git a/nixos/modules/services/desktops/gsignond.nix b/nixos/modules/services/desktops/gsignond.nix new file mode 100644 index 000000000000..cf26e05d5c18 --- /dev/null +++ b/nixos/modules/services/desktops/gsignond.nix @@ -0,0 +1,43 @@ +# Accounts-SSO gSignOn daemon + +{ config, lib, pkgs, ... }: + +with lib; + +let + package = pkgs.gsignond.override { plugins = config.services.gsignond.plugins; }; +in +{ + + ###### interface + + options = { + + services.gsignond = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable gSignOn daemon, a DBus service + which performs user authentication on behalf of its clients. + ''; + }; + + plugins = mkOption { + type = types.listOf types.package; + default = []; + description = '' + What plugins to use with the gSignOn daemon. + ''; + }; + }; + }; + + ###### implementation + config = mkIf config.services.gsignond.enable { + environment.etc."gsignond.conf".source = "${package}/etc/gsignond.conf"; + services.dbus.packages = [ package ]; + }; + +} diff --git a/nixos/modules/services/desktops/profile-sync-daemon.nix b/nixos/modules/services/desktops/profile-sync-daemon.nix index e3f74df3e573..e4e47cfbd438 100644 --- a/nixos/modules/services/desktops/profile-sync-daemon.nix +++ b/nixos/modules/services/desktops/profile-sync-daemon.nix @@ -4,22 +4,7 @@ with lib; let cfg = config.services.psd; - - configFile = '' - ${optionalString (cfg.users != [ ]) '' - USERS="${concatStringsSep " " cfg.users}" - ''} - - ${optionalString (cfg.browsers != [ ]) '' - BROWSERS="${concatStringsSep " " cfg.browsers}" - ''} - - ${optionalString (cfg.volatile != "") "VOLATILE=${cfg.volatile}"} - ${optionalString (cfg.daemonFile != "") "DAEMON_FILE=${cfg.daemonFile}"} - ''; - in { - options.services.psd = with types; { enable = mkOption { type = bool; @@ -28,32 +13,6 @@ in { Whether to enable the Profile Sync daemon. ''; }; - - users = mkOption { - type = listOf str; - default = [ ]; - example = [ "demo" ]; - description = '' - A list of users whose browser profiles should be sync'd to tmpfs. - ''; - }; - - browsers = mkOption { - type = listOf str; - default = [ ]; - example = [ "chromium" "firefox" ]; - description = '' - A list of browsers to sync. Available choices are: - - chromium chromium-dev conkeror.mozdev.org epiphany firefox - firefox-trunk google-chrome google-chrome-beta google-chrome-unstable - heftig-aurora icecat luakit midori opera opera-developer opera-beta - qupzilla palemoon rekonq seamonkey - - An empty list will enable all browsers. - ''; - }; - resyncTimer = mkOption { type = str; default = "1h"; @@ -66,80 +25,53 @@ in { omitted. ''; }; - - volatile = mkOption { - type = str; - default = "/run/psd-profiles"; - description = '' - The directory where browser profiles should reside(this should be - mounted as a tmpfs). Do not include a trailing backslash. - ''; - }; - - daemonFile = mkOption { - type = str; - default = "/run/psd"; - description = '' - Where the pid and backup configuration files will be stored. - ''; - }; }; config = mkIf cfg.enable { - assertions = [ - { assertion = cfg.users != []; - message = "services.psd.users must contain at least one user"; - } - ]; - systemd = { - services = { - psd = { - description = "Profile Sync daemon"; - wants = [ "psd-resync.service" "local-fs.target" ]; - wantedBy = [ "multi-user.target" ]; - preStart = "mkdir -p ${cfg.volatile}"; - - path = with pkgs; [ glibc rsync gawk ]; - - unitConfig = { - RequiresMountsFor = [ "/home/" ]; + user = { + services = { + psd = { + enable = true; + description = "Profile Sync daemon"; + wants = [ "psd-resync.service" "local-fs.target" ]; + wantedBy = [ "default.target" ]; + path = with pkgs; [ rsync kmod gawk nettools utillinux profile-sync-daemon ]; + unitConfig = { + RequiresMountsFor = [ "/home/" ]; + }; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = "yes"; + ExecStart = "${pkgs.profile-sync-daemon}/bin/profile-sync-daemon sync"; + ExecStop = "${pkgs.profile-sync-daemon}/bin/profile-sync-daemon unsync"; + }; }; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = "yes"; - ExecStart = "${pkgs.profile-sync-daemon}/bin/profile-sync-daemon sync"; - ExecStop = "${pkgs.profile-sync-daemon}/bin/profile-sync-daemon unsync"; + psd-resync = { + enable = true; + description = "Timed profile resync"; + after = [ "psd.service" ]; + wants = [ "psd-resync.timer" ]; + partOf = [ "psd.service" ]; + wantedBy = [ "default.target" ]; + path = with pkgs; [ rsync kmod gawk nettools utillinux profile-sync-daemon ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.profile-sync-daemon}/bin/profile-sync-daemon resync"; + }; }; }; - psd-resync = { - description = "Timed profile resync"; - after = [ "psd.service" ]; - wants = [ "psd-resync.timer" ]; - partOf = [ "psd.service" ]; - - path = with pkgs; [ glibc rsync gawk ]; + timers.psd-resync = { + description = "Timer for profile sync daemon - ${cfg.resyncTimer}"; + partOf = [ "psd-resync.service" "psd.service" ]; - serviceConfig = { - Type = "oneshot"; - ExecStart = "${pkgs.profile-sync-daemon}/bin/profile-sync-daemon resync"; + timerConfig = { + OnUnitActiveSec = "${cfg.resyncTimer}"; }; }; }; - - timers.psd-resync = { - description = "Timer for profile sync daemon - ${cfg.resyncTimer}"; - partOf = [ "psd-resync.service" "psd.service" ]; - - timerConfig = { - OnUnitActiveSec = "${cfg.resyncTimer}"; - }; - }; }; - - environment.etc."psd.conf".text = configFile; - }; } diff --git a/nixos/modules/services/editors/emacs.xml b/nixos/modules/services/editors/emacs.xml index 94eb2e6a77bf..6cf20cf4aa7e 100644 --- a/nixos/modules/services/editors/emacs.xml +++ b/nixos/modules/services/editors/emacs.xml @@ -3,150 +3,148 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="module-services-emacs"> - - <title>Emacs</title> - - <!-- + <title>Emacs</title> +<!-- Documentation contributors: Damien Cassou @DamienCassou Thomas Tuegel @ttuegel Rodney Lorrimar @rvl --> + <para> + <link xlink:href="http://www.gnu.org/software/emacs/">Emacs</link> is an + extensible, customizable, self-documenting real-time display editor — and + more. At its core is an interpreter for Emacs Lisp, a dialect of the Lisp + programming language with extensions to support text editing. + </para> + <para> + Emacs runs within a graphical desktop environment using the X Window System, + but works equally well on a text terminal. Under + <productname>macOS</productname>, a "Mac port" edition is available, which + uses Apple's native GUI frameworks. + </para> + <para> + <productname>Nixpkgs</productname> provides a superior environment for + running <application>Emacs</application>. It's simple to create custom builds + by overriding the default packages. Chaotic collections of Emacs Lisp code + and extensions can be brought under control using declarative package + management. <productname>NixOS</productname> even provides a + <command>systemd</command> user service for automatically starting the Emacs + daemon. + </para> + <section xml:id="module-services-emacs-installing"> + <title>Installing <application>Emacs</application></title> <para> - <link xlink:href="http://www.gnu.org/software/emacs/">Emacs</link> - is an extensible, customizable, self-documenting real-time display - editor — and more. At its core is an interpreter for Emacs Lisp, a - dialect of the Lisp programming language with extensions to - support text editing. + Emacs can be installed in the normal way for Nix (see + <xref linkend="sec-package-management" />). In addition, a NixOS + <emphasis>service</emphasis> can be enabled. </para> - <para> - Emacs runs within a graphical desktop environment using the X - Window System, but works equally well on a text terminal. Under - <productname>macOS</productname>, a "Mac port" edition is - available, which uses Apple's native GUI frameworks. - </para> + <section xml:id="module-services-emacs-releases"> + <title>The Different Releases of Emacs</title> + + <para> + <productname>Nixpkgs</productname> defines several basic Emacs packages. + The following are attributes belonging to the <varname>pkgs</varname> set: + <variablelist> + <varlistentry> + <term> + <varname>emacs</varname> + </term> + <term> + <varname>emacs25</varname> + </term> + <listitem> + <para> + The latest stable version of Emacs 25 using the + <link + xlink:href="http://www.gtk.org">GTK+ 2</link> + widget toolkit. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <varname>emacs25-nox</varname> + </term> + <listitem> + <para> + Emacs 25 built without any dependency on X11 libraries. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <varname>emacsMacport</varname> + </term> + <term> + <varname>emacs25Macport</varname> + </term> + <listitem> + <para> + Emacs 25 with the "Mac port" patches, providing a more native look and + feel under macOS. + </para> + </listitem> + </varlistentry> + </variablelist> + </para> + + <para> + If those aren't suitable, then the following imitation Emacs editors are + also available in Nixpkgs: + <link xlink:href="https://www.gnu.org/software/zile/">Zile</link>, + <link xlink:href="http://homepage.boetes.org/software/mg/">mg</link>, + <link xlink:href="http://yi-editor.github.io/">Yi</link>. + </para> + </section> - <para> - <productname>Nixpkgs</productname> provides a superior environment - for running <application>Emacs</application>. It's simple to - create custom builds by overriding the default packages. Chaotic - collections of Emacs Lisp code and extensions can be brought under - control using declarative package - management. <productname>NixOS</productname> even provides a - <command>systemd</command> user service for automatically - starting the Emacs daemon. - </para> + <section xml:id="module-services-emacs-adding-packages"> + <title>Adding Packages to Emacs</title> - <section xml:id="module-services-emacs-installing"> - <title>Installing <application>Emacs</application></title> + <para> + Emacs includes an entire ecosystem of functionality beyond text editing, + including a project planner, mail and news reader, debugger interface, + calendar, and more. + </para> + <para> + Most extensions are gotten with the Emacs packaging system + (<filename>package.el</filename>) from + <link + xlink:href="https://elpa.gnu.org/">Emacs Lisp Package Archive + (<acronym>ELPA</acronym>)</link>, + <link xlink:href="https://melpa.org/"><acronym>MELPA</acronym></link>, + <link xlink:href="https://stable.melpa.org/">MELPA Stable</link>, and + <link xlink:href="http://orgmode.org/elpa.html">Org ELPA</link>. Nixpkgs is + regularly updated to mirror all these archives. + </para> + + <para> + Under NixOS, you can continue to use + <function>package-list-packages</function> and + <function>package-install</function> to install packages. You can also + declare the set of Emacs packages you need using the derivations from + Nixpkgs. The rest of this section discusses declarative installation of + Emacs packages through nixpkgs. + </para> + + <note> <para> - Emacs can be installed in the normal way for Nix (see - <xref linkend="sec-package-management" />). - In addition, a NixOS <emphasis>service</emphasis> - can be enabled. + This documentation describes the new Emacs packages framework in NixOS + 16.03 (<varname>emacsPackagesNg</varname>) which should not be confused + with the previous and deprecated framework + (<varname>emacs24Packages</varname>). </para> - - <section xml:id="module-services-emacs-releases"> - <title>The Different Releases of Emacs</title> - - <para> - <productname>Nixpkgs</productname> defines several basic Emacs - packages. The following are attributes belonging to the - <varname>pkgs</varname> set: - - <variablelist> - <varlistentry> - <term><varname>emacs</varname></term> - <term><varname>emacs25</varname></term> - <listitem> - <para> - The latest stable version of Emacs 25 using the <link - xlink:href="http://www.gtk.org">GTK+ 2</link> widget - toolkit. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><varname>emacs25-nox</varname></term> - <listitem> - <para> - Emacs 25 built without any dependency on X11 - libraries. - </para> - </listitem> - </varlistentry> - <varlistentry> - <term><varname>emacsMacport</varname></term> - <term><varname>emacs25Macport</varname></term> - <listitem> - <para> - Emacs 25 with the "Mac port" patches, providing a more - native look and feel under macOS. - </para> - </listitem> - </varlistentry> - </variablelist> - </para> - - <para> - If those aren't suitable, then the following imitation Emacs - editors are also available in Nixpkgs: - <link xlink:href="https://www.gnu.org/software/zile/">Zile</link>, - <link xlink:href="http://homepage.boetes.org/software/mg/">mg</link>, - <link xlink:href="http://yi-editor.github.io/">Yi</link>. - </para> - - </section> - <section xml:id="module-services-emacs-adding-packages"> - <title>Adding Packages to Emacs</title> - <para> - Emacs includes an entire ecosystem of functionality beyond - text editing, including a project planner, mail and news - reader, debugger interface, calendar, and more. - </para> - - <para> - Most extensions are gotten with the Emacs packaging system - (<filename>package.el</filename>) from <link - xlink:href="https://elpa.gnu.org/">Emacs Lisp Package Archive - (<acronym>ELPA</acronym>)</link>, - <link xlink:href="https://melpa.org/"><acronym>MELPA</acronym></link>, - <link xlink:href="https://stable.melpa.org/">MELPA Stable</link>, - and <link xlink:href="http://orgmode.org/elpa.html">Org ELPA</link>. - Nixpkgs is regularly updated to mirror all these archives. - </para> - - <para> - Under NixOS, you can continue to use - <function>package-list-packages</function> and - <function>package-install</function> to install packages. You - can also declare the set of Emacs packages you need using the - derivations from Nixpkgs. The rest of this section discusses - declarative installation of Emacs packages through nixpkgs. - </para> - - <note> - <para> - This documentation describes the new Emacs packages - framework in NixOS 16.03 - (<varname>emacsPackagesNg</varname>) which should not be - confused with the previous and deprecated framework - (<varname>emacs24Packages</varname>). - </para> - </note> - - <para> - The first step to declare the list of packages you want in - your Emacs installation is to create a dedicated - derivation. This can be done in a dedicated - <filename>emacs.nix</filename> file such as: - - <example xml:id="ex-emacsNix"> - <title>Nix expression to build Emacs with packages (<filename>emacs.nix</filename>)</title> - <programlisting language="nix"> + </note> + + <para> + The first step to declare the list of packages you want in your Emacs + installation is to create a dedicated derivation. This can be done in a + dedicated <filename>emacs.nix</filename> file such as: + <example xml:id="ex-emacsNix"> + <title>Nix expression to build Emacs with packages (<filename>emacs.nix</filename>)</title> +<programlisting language="nix"> /* This is a nix expression to build Emacs and some Emacs packages I like from source on any distribution where Nix is installed. This will install @@ -181,119 +179,104 @@ in pkgs.notmuch # From main packages set <co xml:id="ex-emacsNix-7" /> ]) </programlisting> - </example> - - <calloutlist> - <callout arearefs="ex-emacsNix-1"> - <para> - The first non-comment line in this file - (<literal>{ pkgs ? ... }</literal>) - indicates that the whole file represents a function. - </para> - </callout> - - <callout arearefs="ex-emacsNix-2"> - <para> - The <varname>let</varname> expression below defines a - <varname>myEmacs</varname> binding pointing to the current - stable version of Emacs. This binding is here to separate the - choice of the Emacs binary from the specification of the - required packages. - </para> - </callout> - - <callout arearefs="ex-emacsNix-3"> - <para> - This generates an <varname>emacsWithPackages</varname> - function. It takes a single argument: a function from a - package set to a list of packages (the packages that will - be available in Emacs). - </para> - </callout> - - <callout arearefs="ex-emacsNix-4"> - <para> - The rest of the file specifies the list of packages to - install. In the example, two packages - (<varname>magit</varname> and - <varname>zerodark-theme</varname>) are taken from MELPA - stable. - </para> - </callout> - - <callout arearefs="ex-emacsNix-5"> - <para> - Two packages (<varname>undo-tree</varname> and - <varname>zoom-frm</varname>) are taken from MELPA. - </para> - </callout> - - <callout arearefs="ex-emacsNix-6"> - <para>Three packages are taken from GNU ELPA.</para> - </callout> - - <callout arearefs="ex-emacsNix-7"> - <para> - <varname>notmuch</varname> is taken from a nixpkgs derivation - which contains an Emacs mode. - </para> - </callout> - - </calloutlist> + </example> + <calloutlist> + <callout arearefs="ex-emacsNix-1"> + <para> + The first non-comment line in this file (<literal>{ pkgs ? ... + }</literal>) indicates that the whole file represents a function. </para> - + </callout> + <callout arearefs="ex-emacsNix-2"> <para> - The result of this configuration will be an - <command>emacs</command> command which launches Emacs with all - of your chosen packages in the <varname>load-path</varname>. + The <varname>let</varname> expression below defines a + <varname>myEmacs</varname> binding pointing to the current stable + version of Emacs. This binding is here to separate the choice of the + Emacs binary from the specification of the required packages. </para> - + </callout> + <callout arearefs="ex-emacsNix-3"> <para> - You can check that it works by executing this in a terminal: - + This generates an <varname>emacsWithPackages</varname> function. It + takes a single argument: a function from a package set to a list of + packages (the packages that will be available in Emacs). + </para> + </callout> + <callout arearefs="ex-emacsNix-4"> + <para> + The rest of the file specifies the list of packages to install. In the + example, two packages (<varname>magit</varname> and + <varname>zerodark-theme</varname>) are taken from MELPA stable. + </para> + </callout> + <callout arearefs="ex-emacsNix-5"> + <para> + Two packages (<varname>undo-tree</varname> and + <varname>zoom-frm</varname>) are taken from MELPA. + </para> + </callout> + <callout arearefs="ex-emacsNix-6"> + <para> + Three packages are taken from GNU ELPA. + </para> + </callout> + <callout arearefs="ex-emacsNix-7"> + <para> + <varname>notmuch</varname> is taken from a nixpkgs derivation which + contains an Emacs mode. + </para> + </callout> + </calloutlist> + </para> + + <para> + The result of this configuration will be an <command>emacs</command> + command which launches Emacs with all of your chosen packages in the + <varname>load-path</varname>. + </para> + + <para> + You can check that it works by executing this in a terminal: <screen> $ nix-build emacs.nix $ ./result/bin/emacs -q </screen> + and then typing <literal>M-x package-initialize</literal>. Check that you + can use all the packages you want in this Emacs instance. For example, try + switching to the zerodark theme through <literal>M-x load-theme <RET> + zerodark <RET> y</literal>. + </para> - and then typing <literal>M-x package-initialize</literal>. - Check that you can use all the packages you want in this - Emacs instance. For example, try switching to the zerodark - theme through - <literal>M-x load-theme <RET> zerodark <RET> y</literal>. - </para> - - <tip> - <para> - A few popular extensions worth checking out are: auctex, - company, edit-server, flycheck, helm, iedit, magit, - multiple-cursors, projectile, and yasnippet. - </para> - </tip> - - <para> - The list of available packages in the various ELPA - repositories can be seen with the following commands: - <example xml:id="module-services-emacs-querying-packages"> - <title>Querying Emacs packages</title> - <programlisting><![CDATA[ + <tip> + <para> + A few popular extensions worth checking out are: auctex, company, + edit-server, flycheck, helm, iedit, magit, multiple-cursors, projectile, + and yasnippet. + </para> + </tip> + + <para> + The list of available packages in the various ELPA repositories can be seen + with the following commands: + <example xml:id="module-services-emacs-querying-packages"> + <title>Querying Emacs packages</title> +<programlisting><![CDATA[ nix-env -f "<nixpkgs>" -qaP -A emacsPackagesNg.elpaPackages nix-env -f "<nixpkgs>" -qaP -A emacsPackagesNg.melpaPackages nix-env -f "<nixpkgs>" -qaP -A emacsPackagesNg.melpaStablePackages nix-env -f "<nixpkgs>" -qaP -A emacsPackagesNg.orgPackages ]]></programlisting> - </example> - </para> - - <para> - If you are on NixOS, you can install this particular Emacs for - all users by adding it to the list of system packages - (see <xref linkend="sec-declarative-package-mgmt" />). Simply - modify your file <filename>configuration.nix</filename> to - make it contain: - <example xml:id="module-services-emacs-configuration-nix"> - <title>Custom Emacs in <filename>configuration.nix</filename></title> - <programlisting><![CDATA[ + </example> + </para> + + <para> + If you are on NixOS, you can install this particular Emacs for all users by + adding it to the list of system packages (see + <xref linkend="sec-declarative-package-mgmt" />). Simply modify your file + <filename>configuration.nix</filename> to make it contain: + <example xml:id="module-services-emacs-configuration-nix"> + <title>Custom Emacs in <filename>configuration.nix</filename></title> +<programlisting><![CDATA[ { environment.systemPackages = [ # [...] @@ -301,60 +284,59 @@ nix-env -f "<nixpkgs>" -qaP -A emacsPackagesNg.orgPackages ]; } ]]></programlisting> - </example> - </para> + </example> + </para> - <para> - In this case, the next <command>nixos-rebuild switch</command> - will take care of adding your <command>emacs</command> to the - <varname>PATH</varname> environment variable - (see <xref linkend="sec-changing-config" />). - </para> + <para> + In this case, the next <command>nixos-rebuild switch</command> will take + care of adding your <command>emacs</command> to the <varname>PATH</varname> + environment variable (see <xref linkend="sec-changing-config" />). + </para> <!-- fixme: i think the following is better done with config.nix https://nixos.org/nixpkgs/manual/#sec-modify-via-packageOverrides --> - <para> - If you are not on NixOS or want to install this particular - Emacs only for yourself, you can do so by adding it to your - <filename>~/.config/nixpkgs/config.nix</filename> - (see <link xlink:href="http://nixos.org/nixpkgs/manual/#sec-modify-via-packageOverrides">Nixpkgs manual</link>): - <example xml:id="module-services-emacs-config-nix"> - <title>Custom Emacs in <filename>~/.config/nixpkgs/config.nix</filename></title> - <programlisting><![CDATA[ + + <para> + If you are not on NixOS or want to install this particular Emacs only for + yourself, you can do so by adding it to your + <filename>~/.config/nixpkgs/config.nix</filename> (see + <link xlink:href="http://nixos.org/nixpkgs/manual/#sec-modify-via-packageOverrides">Nixpkgs + manual</link>): + <example xml:id="module-services-emacs-config-nix"> + <title>Custom Emacs in <filename>~/.config/nixpkgs/config.nix</filename></title> +<programlisting><![CDATA[ { packageOverrides = super: let self = super.pkgs; in { myemacs = import /path/to/emacs.nix { pkgs = self; }; }; } ]]></programlisting> - </example> - </para> - - <para> - In this case, the next - <literal>nix-env -f '<nixpkgs>' -iA myemacs</literal> - will take care of adding your emacs to the - <varname>PATH</varname> environment variable. - </para> - </section> - - <section xml:id="module-services-emacs-advanced"> - <title>Advanced Emacs Configuration</title> + </example> + </para> - <para> - If you want, you can tweak the Emacs package itself from your - <filename>emacs.nix</filename>. For example, if you want to - have a GTK+3-based Emacs instead of the default GTK+2-based - binary and remove the automatically generated - <filename>emacs.desktop</filename> (useful is you only use - <command>emacsclient</command>), you can change your file - <filename>emacs.nix</filename> in this way: - </para> + <para> + In this case, the next <literal>nix-env -f '<nixpkgs>' -iA + myemacs</literal> will take care of adding your emacs to the + <varname>PATH</varname> environment variable. + </para> + </section> - <example xml:id="ex-emacsGtk3Nix"> - <title>Custom Emacs build</title> - <programlisting><![CDATA[ + <section xml:id="module-services-emacs-advanced"> + <title>Advanced Emacs Configuration</title> + + <para> + If you want, you can tweak the Emacs package itself from your + <filename>emacs.nix</filename>. For example, if you want to have a + GTK+3-based Emacs instead of the default GTK+2-based binary and remove the + automatically generated <filename>emacs.desktop</filename> (useful is you + only use <command>emacsclient</command>), you can change your file + <filename>emacs.nix</filename> in this way: + </para> + + <example xml:id="ex-emacsGtk3Nix"> + <title>Custom Emacs build</title> +<programlisting><![CDATA[ { pkgs ? import <nixpkgs> {} }: let myEmacs = (pkgs.emacs.override { @@ -370,161 +352,143 @@ let }); in [...] ]]></programlisting> - </example> + </example> - <para> - After building this file as shown in <xref linkend="ex-emacsNix" />, - you will get an GTK3-based Emacs binary pre-loaded with your - favorite packages. - </para> - </section> + <para> + After building this file as shown in <xref linkend="ex-emacsNix" />, you + will get an GTK3-based Emacs binary pre-loaded with your favorite packages. + </para> </section> - -<section xml:id="module-services-emacs-running"> + </section> + <section xml:id="module-services-emacs-running"> <title>Running Emacs as a Service</title> + <para> - <productname>NixOS</productname> provides an optional - <command>systemd</command> service which launches - <link xlink:href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html"> - Emacs daemon - </link> - with the user's login session. + <productname>NixOS</productname> provides an optional + <command>systemd</command> service which launches + <link xlink:href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html"> + Emacs daemon </link> with the user's login session. </para> <para> - <emphasis>Source:</emphasis> - <filename>modules/services/editors/emacs.nix</filename> + <emphasis>Source:</emphasis> + <filename>modules/services/editors/emacs.nix</filename> </para> <section xml:id="module-services-emacs-enabling"> - <title>Enabling the Service</title> - - <para> - To install and enable the <command>systemd</command> - user service for Emacs daemon, add the following to your - <filename>configuration.nix</filename>: + <title>Enabling the Service</title> + <para> + To install and enable the <command>systemd</command> user service for Emacs + daemon, add the following to your <filename>configuration.nix</filename>: <programlisting> <xref linkend="opt-services.emacs.enable"/> = true; <xref linkend="opt-services.emacs.package"/> = import /home/cassou/.emacs.d { pkgs = pkgs; }; </programlisting> - </para> - - <para> - The <varname>services.emacs.package</varname> option allows a - custom derivation to be used, for example, one created by - <function>emacsWithPackages</function>. - </para> - - <para> - Ensure that the Emacs server is enabled for your user's Emacs - configuration, either by customizing the - <varname>server-mode</varname> variable, or by adding - <literal>(server-start)</literal> to - <filename>~/.emacs.d/init.el</filename>. - </para> - - <para> - To start the daemon, execute the following: - + </para> + + <para> + The <varname>services.emacs.package</varname> option allows a custom + derivation to be used, for example, one created by + <function>emacsWithPackages</function>. + </para> + + <para> + Ensure that the Emacs server is enabled for your user's Emacs + configuration, either by customizing the <varname>server-mode</varname> + variable, or by adding <literal>(server-start)</literal> to + <filename>~/.emacs.d/init.el</filename>. + </para> + + <para> + To start the daemon, execute the following: <screen> $ nixos-rebuild switch # to activate the new configuration.nix $ systemctl --user daemon-reload # to force systemd reload $ systemctl --user start emacs.service # to start the Emacs daemon </screen> - - The server should now be ready to serve Emacs clients. - </para> - + The server should now be ready to serve Emacs clients. + </para> </section> <section xml:id="module-services-emacs-starting-client"> - <title>Starting the client</title> - <para> - Ensure that the emacs server is enabled, either by customizing - the <varname>server-mode</varname> variable, or by adding - <literal>(server-start)</literal> to - <filename>~/.emacs</filename>. - </para> + <title>Starting the client</title> - <para> - To connect to the emacs daemon, run one of the following: - <programlisting><![CDATA[ + <para> + Ensure that the emacs server is enabled, either by customizing the + <varname>server-mode</varname> variable, or by adding + <literal>(server-start)</literal> to <filename>~/.emacs</filename>. + </para> + + <para> + To connect to the emacs daemon, run one of the following: +<programlisting><![CDATA[ emacsclient FILENAME emacsclient --create-frame # opens a new frame (window) emacsclient --create-frame --tty # opens a new frame on the current terminal ]]></programlisting> - </para> + </para> </section> <section xml:id="module-services-emacs-editor-variable"> - <title>Configuring the <varname>EDITOR</varname> variable</title> - <!--<title><command>emacsclient</command> as the Default Editor</title>--> - - <para> - If <xref linkend="opt-services.emacs.defaultEditor"/> is - <literal>true</literal>, the <varname>EDITOR</varname> variable - will be set to a wrapper script which launches - <command>emacsclient</command>. - </para> - - <para> - Any setting of <varname>EDITOR</varname> in the shell config - files will override - <varname>services.emacs.defaultEditor</varname>. - To make sure <varname>EDITOR</varname> refers to the Emacs - wrapper script, remove any existing <varname>EDITOR</varname> - assignment from <filename>.profile</filename>, - <filename>.bashrc</filename>, <filename>.zshenv</filename> or - any other shell config file. - </para> - - <para> - If you have formed certain bad habits when editing files, - these can be corrected with a shell alias to the wrapper - script: - <programlisting>alias vi=$EDITOR</programlisting> - </para> + <title>Configuring the <varname>EDITOR</varname> variable</title> + +<!--<title><command>emacsclient</command> as the Default Editor</title>--> + + <para> + If <xref linkend="opt-services.emacs.defaultEditor"/> is + <literal>true</literal>, the <varname>EDITOR</varname> variable will be set + to a wrapper script which launches <command>emacsclient</command>. + </para> + + <para> + Any setting of <varname>EDITOR</varname> in the shell config files will + override <varname>services.emacs.defaultEditor</varname>. To make sure + <varname>EDITOR</varname> refers to the Emacs wrapper script, remove any + existing <varname>EDITOR</varname> assignment from + <filename>.profile</filename>, <filename>.bashrc</filename>, + <filename>.zshenv</filename> or any other shell config file. + </para> + + <para> + If you have formed certain bad habits when editing files, these can be + corrected with a shell alias to the wrapper script: +<programlisting>alias vi=$EDITOR</programlisting> + </para> </section> <section xml:id="module-services-emacs-per-user"> - <title>Per-User Enabling of the Service</title> - - <para> - In general, <command>systemd</command> user services - are globally enabled by symlinks in - <filename>/etc/systemd/user</filename>. In the case where - Emacs daemon is not wanted for all users, it is possible to - install the service but not globally enable it: + <title>Per-User Enabling of the Service</title> + <para> + In general, <command>systemd</command> user services are globally enabled + by symlinks in <filename>/etc/systemd/user</filename>. In the case where + Emacs daemon is not wanted for all users, it is possible to install the + service but not globally enable it: <programlisting> <xref linkend="opt-services.emacs.enable"/> = false; <xref linkend="opt-services.emacs.install"/> = true; </programlisting> - </para> - - <para> - To enable the <command>systemd</command> user service for just - the currently logged in user, run: - - <programlisting>systemctl --user enable emacs</programlisting> - - This will add the symlink - <filename>~/.config/systemd/user/emacs.service</filename>. - </para> + </para> + + <para> + To enable the <command>systemd</command> user service for just the + currently logged in user, run: +<programlisting>systemctl --user enable emacs</programlisting> + This will add the symlink + <filename>~/.config/systemd/user/emacs.service</filename>. + </para> </section> -</section> - -<section xml:id="module-services-emacs-configuring"> + </section> + <section xml:id="module-services-emacs-configuring"> <title>Configuring Emacs</title> <para> - The Emacs init file should be changed to load the extension - packages at startup: - - <example xml:id="module-services-emacs-package-initialisation"> - <title>Package initialization in <filename>.emacs</filename></title> - <programlisting><![CDATA[ + The Emacs init file should be changed to load the extension packages at + startup: + <example xml:id="module-services-emacs-package-initialisation"> + <title>Package initialization in <filename>.emacs</filename></title> +<programlisting><![CDATA[ (require 'package) ;; optional. makes unpure packages archives unavailable @@ -533,66 +497,71 @@ emacsclient --create-frame --tty # opens a new frame on the current terminal (setq package-enable-at-startup nil) (package-initialize) ]]></programlisting> - </example> + </example> </para> <para> - After the declarative emacs package configuration has been - tested, previously downloaded packages can be cleaned up by - removing <filename>~/.emacs.d/elpa</filename> (do make a backup - first, in case you forgot a package). + After the declarative emacs package configuration has been tested, + previously downloaded packages can be cleaned up by removing + <filename>~/.emacs.d/elpa</filename> (do make a backup first, in case you + forgot a package). </para> - <!-- +<!-- todo: is it worth documenting customizations for server-switch-hook, server-done-hook? --> <section xml:id="module-services-emacs-major-mode"> - <title>A Major Mode for Nix Expressions</title> + <title>A Major Mode for Nix Expressions</title> - <para> - Of interest may be <varname>melpaPackages.nix-mode</varname>, - which provides syntax highlighting for the Nix language. This is - particularly convenient if you regularly edit Nix files. - </para> + <para> + Of interest may be <varname>melpaPackages.nix-mode</varname>, which + provides syntax highlighting for the Nix language. This is particularly + convenient if you regularly edit Nix files. + </para> </section> <section xml:id="module-services-emacs-man-pages"> - <title>Accessing man pages</title> - <para> - You can use <function>woman</function> to get completion of all - available man pages. For example, type <literal>M-x woman - <RET> nixos-rebuild <RET>.</literal> - </para> + <title>Accessing man pages</title> + + <para> + You can use <function>woman</function> to get completion of all available + man pages. For example, type <literal>M-x woman <RET> nixos-rebuild + <RET>.</literal> + </para> </section> <section xml:id="sec-emacs-docbook-xml"> - <title>Editing DocBook 5 XML Documents</title> - <para> - Emacs includes <link - xlink:href="https://www.gnu.org/software/emacs/manual/html_node/nxml-mode/Introduction.html">nXML</link>, - a major-mode for validating and editing XML documents. - When editing DocBook 5.0 documents, such as - <link linkend="book-nixos-manual">this one</link>, - nXML needs to be configured with the relevant schema, which is - not included. - </para> + <title>Editing DocBook 5 XML Documents</title> - <para> - To install the DocBook 5.0 schemas, either add - <varname>pkgs.docbook5</varname> to - <xref linkend="opt-environment.systemPackages"/> (<link + <para> + Emacs includes + <link + xlink:href="https://www.gnu.org/software/emacs/manual/html_node/nxml-mode/Introduction.html">nXML</link>, + a major-mode for validating and editing XML documents. When editing DocBook + 5.0 documents, such as <link linkend="book-nixos-manual">this one</link>, + nXML needs to be configured with the relevant schema, which is not + included. + </para> + + <para> + To install the DocBook 5.0 schemas, either add + <varname>pkgs.docbook5</varname> to + <xref linkend="opt-environment.systemPackages"/> + (<link linkend="sec-declarative-package-mgmt">NixOS</link>), or run - <literal>nix-env -i pkgs.docbook5</literal> - (<link linkend="sec-ad-hoc-packages">Nix</link>). - </para> - - <para> - Then customize the variable <varname>rng-schema-locating-files</varname> to include <filename>~/.emacs.d/schemas.xml</filename> and put the following text into that file: - <example xml:id="ex-emacs-docbook-xml"> - <title>nXML Schema Configuration (<filename>~/.emacs.d/schemas.xml</filename>)</title> - <programlisting language="xml"><![CDATA[ + <literal>nix-env -i pkgs.docbook5</literal> + (<link linkend="sec-ad-hoc-packages">Nix</link>). + </para> + + <para> + Then customize the variable <varname>rng-schema-locating-files</varname> to + include <filename>~/.emacs.d/schemas.xml</filename> and put the following + text into that file: + <example xml:id="ex-emacs-docbook-xml"> + <title>nXML Schema Configuration (<filename>~/.emacs.d/schemas.xml</filename>)</title> +<programlisting language="xml"><![CDATA[ <?xml version="1.0"?> <!-- To let emacs find this file, evaluate: @@ -612,9 +581,7 @@ emacsclient --create-frame --tty # opens a new frame on the current terminal </locatingRules> ]]></programlisting> </example> - </para> - + </para> </section> -</section> - + </section> </chapter> diff --git a/nixos/modules/services/hardware/lirc.nix b/nixos/modules/services/hardware/lirc.nix new file mode 100644 index 000000000000..5635d6f09715 --- /dev/null +++ b/nixos/modules/services/hardware/lirc.nix @@ -0,0 +1,89 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.lirc; +in { + + ###### interface + + options = { + services.lirc = { + + enable = mkEnableOption "LIRC daemon"; + + options = mkOption { + type = types.lines; + example = '' + [lircd] + nodaemon = False + ''; + description = "LIRC default options descriped in man:lircd(8) (<filename>lirc_options.conf</filename>)"; + }; + + configs = mkOption { + type = types.listOf types.lines; + description = "Configurations for lircd to load, see man:lircd.conf(5) for details (<filename>lircd.conf</filename>)"; + }; + + extraArguments = mkOption { + type = types.listOf types.str; + default = []; + description = "Extra arguments to lircd."; + }; + + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + + # Note: LIRC executables raises a warning, if lirc_options.conf do not exists + environment.etc."lirc/lirc_options.conf".text = cfg.options; + + environment.systemPackages = [ pkgs.lirc ]; + + systemd.sockets.lircd = { + description = "LIRC daemon socket"; + wantedBy = [ "sockets.target" ]; + socketConfig = { + ListenStream = "/run/lirc/lircd"; + SocketUser = "lirc"; + SocketMode = "0660"; + }; + }; + + systemd.services.lircd = let + configFile = pkgs.writeText "lircd.conf" (builtins.concatStringsSep "\n" cfg.configs); + in { + description = "LIRC daemon service"; + after = [ "network.target" ]; + + unitConfig.Documentation = [ "man:lircd(8)" ]; + + serviceConfig = { + RuntimeDirectory = "lirc"; + + # socket lives in runtime directory; we have to keep is available + RuntimeDirectoryPreserve = true; + + ExecStart = '' + ${pkgs.lirc}/bin/lircd --nodaemon \ + ${escapeShellArgs cfg.extraArguments} \ + ${configFile} + ''; + User = "lirc"; + }; + }; + + users.users.lirc = { + uid = config.ids.uids.lirc; + group = "lirc"; + description = "LIRC user for lircd"; + }; + + users.groups.lirc.gid = config.ids.gids.lirc; + }; +} diff --git a/nixos/modules/services/hardware/ratbagd.nix b/nixos/modules/services/hardware/ratbagd.nix new file mode 100644 index 000000000000..103e1d2315ae --- /dev/null +++ b/nixos/modules/services/hardware/ratbagd.nix @@ -0,0 +1,32 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.ratbagd; +in +{ + ###### interface + + options = { + services.ratbagd = { + enable = mkOption { + default = false; + description = '' + Whether to enable ratbagd for configuring gaming mice. + ''; + }; + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + # Give users access to the "ratbagctl" tool + environment.systemPackages = [ pkgs.libratbag ]; + + services.dbus.packages = [ pkgs.libratbag ]; + + systemd.packages = [ pkgs.libratbag ]; + }; +} diff --git a/nixos/modules/services/hardware/trezord.nix b/nixos/modules/services/hardware/trezord.nix index f2ec00a7d3e1..c06a0665d02f 100644 --- a/nixos/modules/services/hardware/trezord.nix +++ b/nixos/modules/services/hardware/trezord.nix @@ -26,15 +26,14 @@ in { name = "trezord-udev-rules"; destination = "/etc/udev/rules.d/51-trezor.rules"; text = '' - # Trezor 1 - SUBSYSTEM=="usb", ATTR{idVendor}=="534c", ATTR{idProduct}=="0001", MODE="0666", GROUP="dialout", SYMLINK+="trezor%n" - KERNEL=="hidraw*", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", MODE="0666", GROUP="dialout" - - # Trezor 2 (Model-T) - SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="53c0", MODE="0661", GROUP="dialout", TAG+="uaccess", TAG+="udev-acl", SYMLINK+="trezor%n" - SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="53c1", MODE="0660", GROUP="dialout", TAG+="uaccess", TAG+="udev-acl", SYMLINK+="trezor%n" - KERNEL=="hidraw*", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="53c1", MODE="0660", GROUP="dialout", TAG+="uaccess", TAG+="udev-acl" - ]; + # TREZOR v1 (One) + SUBSYSTEM=="usb", ATTR{idVendor}=="534c", ATTR{idProduct}=="0001", MODE="0660", GROUP="trezord", TAG+="uaccess", SYMLINK+="trezor%n" + KERNEL=="hidraw*", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", MODE="0660", GROUP="trezord", TAG+="uaccess" + + # TREZOR v2 (T) + SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="53c0", MODE="0660", GROUP="trezord", TAG+="uaccess", SYMLINK+="trezor%n" + SUBSYSTEM=="usb", ATTR{idVendor}=="1209", ATTR{idProduct}=="53c1", MODE="0660", GROUP="trezord", TAG+="uaccess", SYMLINK+="trezor%n" + KERNEL=="hidraw*", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="53c1", MODE="0660", GROUP="trezord", TAG+="uaccess" ''; }); diff --git a/nixos/modules/services/hardware/triggerhappy.nix b/nixos/modules/services/hardware/triggerhappy.nix new file mode 100644 index 000000000000..81d4a1ae65bf --- /dev/null +++ b/nixos/modules/services/hardware/triggerhappy.nix @@ -0,0 +1,114 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.triggerhappy; + + socket = "/run/thd.socket"; + + configFile = pkgs.writeText "triggerhappy.conf" '' + ${concatMapStringsSep "\n" + ({ keys, event, cmd, ... }: + ''${concatMapStringsSep "+" (x: "KEY_" + x) keys} ${toString { press = 1; hold = 2; release = 0; }.${event}} ${cmd}'' + ) + cfg.bindings} + ${cfg.extraConfig} + ''; + + bindingCfg = { config, ... }: { + options = { + + keys = mkOption { + type = types.listOf types.str; + description = "List of keys to match. Key names as defined in linux/input-event-codes.h"; + }; + + event = mkOption { + type = types.enum ["press" "hold" "release"]; + default = "press"; + description = "Event to match."; + }; + + cmd = mkOption { + type = types.str; + description = "What to run."; + }; + + }; + }; + +in + +{ + + ###### interface + + options = { + + services.triggerhappy = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable the <command>triggerhappy</command> hotkey daemon. + ''; + }; + + bindings = mkOption { + type = types.listOf (types.submodule bindingCfg); + default = []; + example = lib.literalExample '' + [ { keys = ["PLAYPAUSE"]; cmd = "''${pkgs.mpc_cli}/bin/mpc -q toggle"; } ] + ''; + description = '' + Key bindings for <command>triggerhappy</command>. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Literal contents to append to the end of <command>triggerhappy</command> configuration file. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + systemd.sockets.triggerhappy = { + description = "Triggerhappy Socket"; + wantedBy = [ "sockets.target" ]; + socketConfig.ListenDatagram = socket; + }; + + systemd.services.triggerhappy = { + wantedBy = [ "multi-user.target" ]; + after = [ "local-fs.target" ]; + description = "Global hotkey daemon"; + serviceConfig = { + ExecStart = "${pkgs.triggerhappy}/bin/thd --user nobody --socket ${socket} --triggers ${configFile} --deviceglob /dev/input/event*"; + }; + }; + + services.udev.packages = lib.singleton (pkgs.writeTextFile { + name = "triggerhappy-udev-rules"; + destination = "/etc/udev/rules.d/61-triggerhappy.rules"; + text = '' + ACTION=="add", SUBSYSTEM=="input", KERNEL=="event[0-9]*", ATTRS{name}!="triggerhappy", \ + RUN+="${pkgs.triggerhappy}/bin/th-cmd --socket ${socket} --passfd --udev" + ''; + }); + + }; + +} diff --git a/nixos/modules/services/hardware/upower.nix b/nixos/modules/services/hardware/upower.nix index 2198842a4511..1da47349c077 100644 --- a/nixos/modules/services/hardware/upower.nix +++ b/nixos/modules/services/hardware/upower.nix @@ -56,6 +56,32 @@ in { Type = "dbus"; BusName = "org.freedesktop.UPower"; ExecStart = "@${cfg.package}/libexec/upowerd upowerd"; + Restart = "on-failure"; + # Upstream lockdown: + # Filesystem lockdown + ProtectSystem = "strict"; + # Needed by keyboard backlight support + ProtectKernelTunables = false; + ProtectControlGroups = true; + ReadWritePaths = "/var/lib/upower"; + ProtectHome = true; + PrivateTmp = true; + + # Network + # PrivateNetwork=true would block udev's netlink socket + RestrictAddressFamilies = "AF_UNIX AF_NETLINK"; + + # Execute Mappings + MemoryDenyWriteExecute = true; + + # Modules + ProtectKernelModules = true; + + # Real-time + RestrictRealtime = true; + + # Privilege escalation + NoNewPrivileges = true; }; }; diff --git a/nixos/modules/services/logging/journaldriver.nix b/nixos/modules/services/logging/journaldriver.nix index 74ac3d4c2365..9bd581e9ec0e 100644 --- a/nixos/modules/services/logging/journaldriver.nix +++ b/nixos/modules/services/logging/journaldriver.nix @@ -7,7 +7,7 @@ # to be set. # # For further information please consult the documentation in the -# upstream repository at: https://github.com/aprilabank/journaldriver/ +# upstream repository at: https://github.com/tazjin/journaldriver/ { config, lib, pkgs, ...}: diff --git a/nixos/modules/services/mail/clamsmtp.nix b/nixos/modules/services/mail/clamsmtp.nix index 8f4f39aa7288..fc1267c5d280 100644 --- a/nixos/modules/services/mail/clamsmtp.nix +++ b/nixos/modules/services/mail/clamsmtp.nix @@ -176,4 +176,6 @@ in } ) cfg.instances); }; + + meta.maintainers = with lib.maintainers; [ ekleog ]; } diff --git a/nixos/modules/services/mail/dkimproxy-out.nix b/nixos/modules/services/mail/dkimproxy-out.nix index 894b88e25c1b..f4ac9e47007a 100644 --- a/nixos/modules/services/mail/dkimproxy-out.nix +++ b/nixos/modules/services/mail/dkimproxy-out.nix @@ -115,4 +115,6 @@ in }; }; }; + + meta.maintainers = with lib.maintainers; [ ekleog ]; } diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix index e6091182b2ab..30ad7d82fb80 100644 --- a/nixos/modules/services/mail/dovecot.nix +++ b/nixos/modules/services/mail/dovecot.nix @@ -311,7 +311,7 @@ in { name = "dovenull"; uid = config.ids.uids.dovenull2; description = "Dovecot user for untrusted logins"; - group = cfg.group; + group = "dovenull"; } ] ++ optional (cfg.user == "dovecot2") { name = "dovecot2"; @@ -332,6 +332,10 @@ in } ++ optional (cfg.createMailUser && cfg.mailGroup != null) { name = cfg.mailGroup; + } + ++ singleton + { name = "dovenull"; + gid = config.ids.gids.dovenull2; }; environment.etc."dovecot/modules".source = modulesDir; diff --git a/nixos/modules/services/mail/exim.nix b/nixos/modules/services/mail/exim.nix index 06c4b2811b3f..c05811291359 100644 --- a/nixos/modules/services/mail/exim.nix +++ b/nixos/modules/services/mail/exim.nix @@ -2,7 +2,7 @@ let inherit (lib) mkIf mkOption singleton types; - inherit (pkgs) coreutils exim; + inherit (pkgs) coreutils; cfg = config.services.exim; in @@ -57,6 +57,16 @@ in ''; }; + package = mkOption { + type = types.package; + default = pkgs.exim; + defaultText = "pkgs.exim"; + description = '' + The Exim derivation to use. + This can be used to enable features such as LDAP or PAM support. + ''; + }; + }; }; @@ -74,7 +84,7 @@ in spool_directory = ${cfg.spoolDir} ${cfg.config} ''; - systemPackages = [ exim ]; + systemPackages = [ cfg.package ]; }; users.users = singleton { @@ -89,14 +99,14 @@ in gid = config.ids.gids.exim; }; - security.wrappers.exim.source = "${exim}/bin/exim"; + security.wrappers.exim.source = "${cfg.package}/bin/exim"; systemd.services.exim = { description = "Exim Mail Daemon"; wantedBy = [ "multi-user.target" ]; restartTriggers = [ config.environment.etc."exim.conf".source ]; serviceConfig = { - ExecStart = "${exim}/bin/exim -bdf -q30m"; + ExecStart = "${cfg.package}/bin/exim -bdf -q30m"; ExecReload = "${coreutils}/bin/kill -HUP $MAINPID"; }; preStart = '' diff --git a/nixos/modules/services/mail/postfix.nix b/nixos/modules/services/mail/postfix.nix index 33249aa3e554..d43733484ffa 100644 --- a/nixos/modules/services/mail/postfix.nix +++ b/nixos/modules/services/mail/postfix.nix @@ -602,7 +602,7 @@ in target = "postfix"; }; - # This makes comfortable for root to run 'postqueue' for example. + # This makes it comfortable to run 'postqueue/postdrop' for example. systemPackages = [ pkgs.postfix ]; }; @@ -616,6 +616,22 @@ in setgid = true; }; + security.wrappers.postqueue = { + program = "postqueue"; + source = "${pkgs.postfix}/bin/postqueue"; + group = setgidGroup; + setuid = false; + setgid = true; + }; + + security.wrappers.postdrop = { + program = "postdrop"; + source = "${pkgs.postfix}/bin/postdrop"; + group = setgidGroup; + setuid = false; + setgid = true; + }; + users.users = optional (user == "postfix") { name = "postfix"; description = "Postfix mail server user"; diff --git a/nixos/modules/services/mail/rmilter.nix b/nixos/modules/services/mail/rmilter.nix index 7f38d7570132..492c64583219 100644 --- a/nixos/modules/services/mail/rmilter.nix +++ b/nixos/modules/services/mail/rmilter.nix @@ -52,7 +52,7 @@ in enable = mkOption { type = types.bool; - default = cfg.rspamd.enable; + default = false; description = "Whether to run the rmilter daemon."; }; @@ -89,7 +89,7 @@ in bindSocket.path = mkOption { type = types.str; - default = "/run/rmilter/rmilter.sock"; + default = "/run/rmilter.sock"; description = '' Path to Unix domain socket to listen on. ''; @@ -193,6 +193,9 @@ in config = mkMerge [ (mkIf cfg.enable { + warnings = [ + ''`config.services.rmilter' is deprecated, `rmilter' deprecated and unsupported by upstream, and will be removed from next releases. Use built-in rspamd milter instead.'' + ]; users.users = singleton { name = cfg.user; diff --git a/nixos/modules/services/mail/rspamd.nix b/nixos/modules/services/mail/rspamd.nix index b3dae60c2c7e..ff01a5dee53d 100644 --- a/nixos/modules/services/mail/rspamd.nix +++ b/nixos/modules/services/mail/rspamd.nix @@ -115,36 +115,10 @@ let }; }; - 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)); + + mkBindSockets = enabled: socks: concatStringsSep "\n " + (flatten (map (each: "bind_socket = \"${each.rawEntry}\";") socks)); rspamdConfFile = pkgs.writeText "rspamd.conf" '' @@ -175,18 +149,6 @@ let ${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 { @@ -197,7 +159,7 @@ in services.rspamd = { - enable = mkEnableOption "Whether to run the rspamd daemon."; + enable = mkEnableOption "rspamd, the Rapid spam filtering system"; debug = mkOption { type = types.bool; @@ -205,13 +167,6 @@ in description = "Whether to run the rspamd daemon in debug mode."; }; - socketActivation = mkOption { - type = types.bool; - description = '' - Enable systemd socket activation for rspamd. - ''; - }; - workers = mkOption { type = with types; attrsOf (submodule workerOpts); description = '' @@ -272,13 +227,6 @@ 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 ]; @@ -299,17 +247,14 @@ in systemd.services.rspamd = { description = "Rspamd Service"; - wantedBy = mkIf (!cfg.socketActivation) [ "multi-user.target" ]; - after = [ "network.target" ] ++ - (if cfg.socketActivation then allSocketNames else []); - requires = mkIf cfg.socketActivation allSocketNames; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; 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 = '' @@ -317,24 +262,10 @@ 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 = [ + (mkRemovedOptionModule [ "services" "rspamd" "socketActivation" ] + "Socket activation never worked correctly and could at this time not be fixed and so was removed") (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/airsonic.nix b/nixos/modules/services/misc/airsonic.nix index 083587b8ebb1..01d7b3cf6b9d 100644 --- a/nixos/modules/services/misc/airsonic.nix +++ b/nixos/modules/services/misc/airsonic.nix @@ -73,6 +73,24 @@ in { ${cfg.home}/transcoders. ''; }; + + jvmOptions = mkOption { + description = '' + Extra command line options for the JVM running AirSonic. + Useful for sending jukebox output to non-default alsa + devices. + ''; + default = [ + ]; + type = types.listOf types.str; + example = [ + "-Djavax.sound.sampled.Clip='#CODEC [plughw:1,0]'" + "-Djavax.sound.sampled.Port='#Port CODEC [hw:1]'" + "-Djavax.sound.sampled.SourceDataLine='#CODEC [plughw:1,0]'" + "-Djavax.sound.sampled.TargetDataLine='#CODEC [plughw:1,0]'" + ]; + }; + }; }; @@ -98,6 +116,7 @@ in { -Dserver.port=${toString cfg.port} \ -Dairsonic.contextPath=${cfg.contextPath} \ -Djava.awt.headless=true \ + ${toString cfg.jvmOptions} \ -verbose:gc \ -jar ${pkgs.airsonic}/webapps/airsonic.war ''; diff --git a/nixos/modules/services/misc/emby.nix b/nixos/modules/services/misc/emby.nix index 64cc9c610ac3..0ad4a3f7376f 100644 --- a/nixos/modules/services/misc/emby.nix +++ b/nixos/modules/services/misc/emby.nix @@ -36,11 +36,18 @@ in after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; preStart = '' - test -d ${cfg.dataDir} || { - echo "Creating initial Emby data directory in ${cfg.dataDir}" - mkdir -p ${cfg.dataDir} - chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir} - } + if [ -d ${cfg.dataDir} ] + then + for plugin in ${cfg.dataDir}/plugins/* + do + echo "Correcting permissions of plugin: $plugin" + chmod u+w $plugin + done + else + echo "Creating initial Emby data directory in ${cfg.dataDir}" + mkdir -p ${cfg.dataDir} + chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir} + fi ''; serviceConfig = { @@ -48,7 +55,7 @@ in User = cfg.user; Group = cfg.group; PermissionsStartOnly = "true"; - ExecStart = "${pkgs.emby}/bin/MediaBrowser.Server.Mono"; + ExecStart = "${pkgs.emby}/bin/emby -programdata ${cfg.dataDir}"; Restart = "on-failure"; }; }; diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index 5bf66354f487..8ea831afb7c1 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -53,6 +53,7 @@ let repos_path: "${cfg.statePath}/repositories" secret_file: "${cfg.statePath}/config/gitlab_shell_secret" log_file: "${cfg.statePath}/log/gitlab-shell.log" + custom_hooks_dir: "${cfg.statePath}/custom_hooks" redis: bin: ${pkgs.redis}/bin/redis-cli host: 127.0.0.1 @@ -162,7 +163,7 @@ let makeWrapper ${cfg.packages.gitlab.rubyEnv}/bin/rake $out/bin/gitlab-rake \ ${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") gitlabEnv)} \ --set GITLAB_CONFIG_PATH '${cfg.statePath}/config' \ - --set PATH '${lib.makeBinPath [ pkgs.nodejs pkgs.gzip pkgs.git pkgs.gnutar config.services.postgresql.package ]}:$PATH' \ + --set PATH '${lib.makeBinPath [ pkgs.nodejs pkgs.gzip pkgs.git pkgs.gnutar config.services.postgresql.package pkgs.coreutils pkgs.procps ]}:$PATH' \ --set RAKEOPT '-f ${cfg.packages.gitlab}/share/gitlab/Rakefile' \ --run 'cd ${cfg.packages.gitlab}/share/gitlab' ''; @@ -203,6 +204,7 @@ in { default = pkgs.gitlab; defaultText = "pkgs.gitlab"; description = "Reference to the gitlab package"; + example = "pkgs.gitlab-ee"; }; packages.gitlab-shell = mkOption { @@ -501,7 +503,7 @@ in { }; systemd.services.gitlab-workhorse = { - after = [ "network.target" "gitlab.service" ]; + after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; environment.HOME = gitlabEnv.HOME; environment.GITLAB_SHELL_CONFIG_PATH = gitlabEnv.GITLAB_SHELL_CONFIG_PATH; @@ -561,6 +563,9 @@ in { mkdir -p ${cfg.statePath}/shell mkdir -p ${cfg.statePath}/db mkdir -p ${cfg.statePath}/uploads + mkdir -p ${cfg.statePath}/custom_hooks/pre-receive.d + mkdir -p ${cfg.statePath}/custom_hooks/post-receive.d + mkdir -p ${cfg.statePath}/custom_hooks/update.d rm -rf ${cfg.statePath}/config ${cfg.statePath}/shell/hooks mkdir -p ${cfg.statePath}/config @@ -569,9 +574,9 @@ in { mkdir -p /run/gitlab mkdir -p ${cfg.statePath}/log - ln -sf ${cfg.statePath}/log /run/gitlab/log - ln -sf ${cfg.statePath}/tmp /run/gitlab/tmp - ln -sf ${cfg.statePath}/uploads /run/gitlab/uploads + [ -d /run/gitlab/log ] || ln -sf ${cfg.statePath}/log /run/gitlab/log + [ -d /run/gitlab/tmp ] || ln -sf ${cfg.statePath}/tmp /run/gitlab/tmp + [ -d /run/gitlab/uploads ] || ln -sf ${cfg.statePath}/uploads /run/gitlab/uploads ln -sf $GITLAB_SHELL_CONFIG_PATH /run/gitlab/shell-config.yml chown -R ${cfg.user}:${cfg.group} /run/gitlab @@ -629,6 +634,10 @@ in { touch "${cfg.statePath}/db-seeded" fi + # The gitlab:shell:setup regenerates the authorized_keys file so that + # the store path to the gitlab-shell in it gets updated + ${pkgs.sudo}/bin/sudo -u ${cfg.user} force=yes ${gitlab-rake}/bin/gitlab-rake gitlab:shell:setup RAILS_ENV=production + # The gitlab:shell:create_hooks task seems broken for fixing links # so we instead delete all the hooks and create them anew rm -f ${cfg.statePath}/repositories/**/*.git/hooks diff --git a/nixos/modules/services/misc/gitlab.xml b/nixos/modules/services/misc/gitlab.xml index 67b9f1d3e474..ab99d7bd3a60 100644 --- a/nixos/modules/services/misc/gitlab.xml +++ b/nixos/modules/services/misc/gitlab.xml @@ -3,20 +3,22 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="module-services-gitlab"> - -<title>Gitlab</title> - -<para>Gitlab is a feature-rich git hosting service.</para> - -<section xml:id="module-services-gitlab-prerequisites"><title>Prerequisites</title> - -<para>The gitlab service exposes only an Unix socket at -<literal>/run/gitlab/gitlab-workhorse.socket</literal>. You need to configure a -webserver to proxy HTTP requests to the socket.</para> - -<para>For instance, the following configuration could be used to use nginx as - frontend proxy: - + <title>Gitlab</title> + <para> + Gitlab is a feature-rich git hosting service. + </para> + <section xml:id="module-services-gitlab-prerequisites"> + <title>Prerequisites</title> + + <para> + The gitlab service exposes only an Unix socket at + <literal>/run/gitlab/gitlab-workhorse.socket</literal>. You need to + configure a webserver to proxy HTTP requests to the socket. + </para> + + <para> + For instance, the following configuration could be used to use nginx as + frontend proxy: <programlisting> <link linkend="opt-services.nginx.enable">services.nginx</link> = { <link linkend="opt-services.nginx.enable">enable</link> = true; @@ -31,21 +33,24 @@ webserver to proxy HTTP requests to the socket.</para> }; }; </programlisting> -</para> - -</section> - -<section xml:id="module-services-gitlab-configuring"><title>Configuring</title> - -<para>Gitlab depends on both PostgreSQL and Redis and will automatically enable -both services. In the case of PostgreSQL, a database and a role will be created. -</para> - -<para>The default state dir is <literal>/var/gitlab/state</literal>. This is where -all data like the repositories and uploads will be stored.</para> - -<para>A basic configuration with some custom settings could look like this: - + </para> + </section> + <section xml:id="module-services-gitlab-configuring"> + <title>Configuring</title> + + <para> + Gitlab depends on both PostgreSQL and Redis and will automatically enable + both services. In the case of PostgreSQL, a database and a role will be + created. + </para> + + <para> + The default state dir is <literal>/var/gitlab/state</literal>. This is where + all data like the repositories and uploads will be stored. + </para> + + <para> + A basic configuration with some custom settings could look like this: <programlisting> services.gitlab = { <link linkend="opt-services.gitlab.enable">enable</link> = true; @@ -105,40 +110,41 @@ services.gitlab = { }; }; </programlisting> -</para> - -<para>If you're setting up a new Gitlab instance, generate new secrets. You -for instance use <literal>tr -dc A-Za-z0-9 < /dev/urandom | head -c 128</literal> -to generate a new secret. Gitlab encrypts sensitive data stored in the database. -If you're restoring an existing Gitlab instance, you must specify the secrets -secret from <literal>config/secrets.yml</literal> located in your Gitlab state -folder.</para> - -<para>Refer to <xref linkend="ch-options" /> for all available configuration -options for the <link linkend="opt-services.gitlab.enable">services.gitlab</link> module.</para> - -</section> - -<section xml:id="module-services-gitlab-maintenance"><title>Maintenance</title> - -<para>You can run Gitlab's rake tasks with <literal>gitlab-rake</literal> -which will be available on the system when gitlab is enabled. You will -have to run the command as the user that you configured to run gitlab -with.</para> - -<para>For example, to backup a Gitlab instance: - + </para> + + <para> + If you're setting up a new Gitlab instance, generate new secrets. You for + instance use <literal>tr -dc A-Za-z0-9 < /dev/urandom | head -c + 128</literal> to generate a new secret. Gitlab encrypts sensitive data + stored in the database. If you're restoring an existing Gitlab instance, you + must specify the secrets secret from <literal>config/secrets.yml</literal> + located in your Gitlab state folder. + </para> + + <para> + Refer to <xref linkend="ch-options" /> for all available configuration + options for the + <link linkend="opt-services.gitlab.enable">services.gitlab</link> module. + </para> + </section> + <section xml:id="module-services-gitlab-maintenance"> + <title>Maintenance</title> + + <para> + You can run Gitlab's rake tasks with <literal>gitlab-rake</literal> which + will be available on the system when gitlab is enabled. You will have to run + the command as the user that you configured to run gitlab with. + </para> + + <para> + For example, to backup a Gitlab instance: <programlisting> $ sudo -u git -H gitlab-rake gitlab:backup:create </programlisting> - -A list of all availabe rake tasks can be obtained by running: - + A list of all availabe rake tasks can be obtained by running: <programlisting> $ sudo -u git -H gitlab-rake -T </programlisting> -</para> - -</section> - + </para> + </section> </chapter> diff --git a/nixos/modules/services/misc/home-assistant.nix b/nixos/modules/services/misc/home-assistant.nix index 0756e81612ac..2e9aa33aeeee 100644 --- a/nixos/modules/services/misc/home-assistant.nix +++ b/nixos/modules/services/misc/home-assistant.nix @@ -157,6 +157,7 @@ in { Restart = "on-failure"; ProtectSystem = "strict"; ReadWritePaths = "${cfg.configDir}"; + KillSignal = "SIGINT"; PrivateTmp = true; RemoveIPC = true; }; diff --git a/nixos/modules/services/misc/lidarr.nix b/nixos/modules/services/misc/lidarr.nix new file mode 100644 index 000000000000..627f22334fe8 --- /dev/null +++ b/nixos/modules/services/misc/lidarr.nix @@ -0,0 +1,46 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.lidarr; +in +{ + options = { + services.lidarr = { + enable = mkEnableOption "Lidarr"; + }; + }; + + config = mkIf cfg.enable { + systemd.services.lidarr = { + description = "Lidarr"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + preStart = '' + [ ! -d /var/lib/lidarr ] && mkdir -p /var/lib/lidarr + chown -R lidarr:lidarr /var/lib/lidarr + ''; + + serviceConfig = { + Type = "simple"; + User = "lidarr"; + Group = "lidarr"; + PermissionsStartOnly = "true"; + ExecStart = "${pkgs.lidarr}/bin/Lidarr"; + Restart = "on-failure"; + + StateDirectory = "/var/lib/lidarr/"; + StateDirectoryMode = "0770"; + }; + }; + + users.users.lidarr = { + uid = config.ids.uids.lidarr; + home = "/var/lib/lidarr"; + group = "lidarr"; + }; + + users.groups.lidarr.gid = config.ids.gids.lidarr; + }; +} diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix index c0eb882c58f3..5e171c08d893 100644 --- a/nixos/modules/services/misc/nix-daemon.nix +++ b/nixos/modules/services/misc/nix-daemon.nix @@ -345,7 +345,6 @@ in type = types.listOf types.str; default = [ - "$HOME/.nix-defexpr/channels" "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos" "nixos-config=/etc/nixos/configuration.nix" "/nix/var/nix/profiles/per-user/root/channels" @@ -400,8 +399,8 @@ in systemd.sockets.nix-daemon.wantedBy = [ "sockets.target" ]; systemd.services.nix-daemon = - { path = [ nix pkgs.utillinux ] - ++ optionals cfg.distributedBuilds [ config.programs.ssh.package pkgs.gzip ] + { path = [ nix pkgs.utillinux config.programs.ssh.package ] + ++ optionals cfg.distributedBuilds [ pkgs.gzip ] ++ optionals (!isNix20) [ pkgs.openssl.bin ]; environment = cfg.envVars @@ -436,7 +435,7 @@ in # Set up the environment variables for running Nix. environment.sessionVariables = cfg.envVars // - { NIX_PATH = concatStringsSep ":" cfg.nixPath; + { NIX_PATH = cfg.nixPath; }; environment.extraInit = optionalString (!isNix20) @@ -446,6 +445,10 @@ in if [ "$USER" != root -o ! -w /nix/var/nix/db ]; then export NIX_REMOTE=daemon fi + '' + '' + if [ -e "$HOME/.nix-defexpr/channels" ]; then + export NIX_PATH="$HOME/.nix-defexpr/channels''${NIX_PATH:+:$NIX_PATH}" + fi ''; nix.nrBuildUsers = mkDefault (lib.max 32 cfg.maxJobs); diff --git a/nixos/modules/services/misc/nix-optimise.nix b/nixos/modules/services/misc/nix-optimise.nix index 6f75e4dd03ea..416529f690e0 100644 --- a/nixos/modules/services/misc/nix-optimise.nix +++ b/nixos/modules/services/misc/nix-optimise.nix @@ -40,6 +40,8 @@ in systemd.services.nix-optimise = { description = "Nix Store Optimiser"; + # No point running it inside a nixos-container. It should be on the host instead. + unitConfig.ConditionVirtualization = "!container"; serviceConfig.ExecStart = "${config.nix.package}/bin/nix-store --optimise"; startAt = optionals cfg.automatic cfg.dates; }; diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix index 993b59590bb0..df3e71c80dea 100644 --- a/nixos/modules/services/misc/nixos-manual.nix +++ b/nixos/modules/services/misc/nixos-manual.nix @@ -1,91 +1,21 @@ -# This module includes the NixOS man-pages in the system environment, -# and optionally starts a browser that shows the NixOS manual on one -# of the virtual consoles. The latter is useful for the installation +# This module optionally starts a browser that shows the NixOS manual +# on one of the virtual consoles which is useful for the installation # CD. -{ config, lib, pkgs, baseModules, ... }: +{ config, lib, pkgs, ... }: with lib; let - cfg = config.services.nixosManual; - - /* For the purpose of generating docs, evaluate options with each derivation - in `pkgs` (recursively) replaced by a fake with path "\${pkgs.attribute.path}". - It isn't perfect, but it seems to cover a vast majority of use cases. - Caveat: even if the package is reached by a different means, - the path above will be shown and not e.g. `${config.services.foo.package}`. */ - manual = import ../../../doc/manual rec { - inherit pkgs config; - version = config.system.nixos.release; - revision = "release-${version}"; - options = - let - scrubbedEval = evalModules { - modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ baseModules; - args = (config._module.args) // { modules = [ ]; }; - specialArgs = { pkgs = scrubDerivations "pkgs" pkgs; }; - }; - scrubDerivations = namePrefix: pkgSet: mapAttrs - (name: value: - let wholeName = "${namePrefix}.${name}"; in - if isAttrs value then - scrubDerivations wholeName value - // (optionalAttrs (isDerivation value) { outPath = "\${${wholeName}}"; }) - else value - ) - pkgSet; - in scrubbedEval.options; - }; - - entry = "${manual.manual}/share/doc/nixos/index.html"; - - helpScript = pkgs.writeScriptBin "nixos-help" - '' - #! ${pkgs.runtimeShell} -e - # Finds first executable browser in a colon-separated list. - # (see how xdg-open defines BROWSER) - browser="$( - IFS=: ; for b in $BROWSER; do - [ -n "$(type -P "$b" || true)" ] && echo "$b" && break - done - )" - if [ -z "$browser" ]; then - browser="$(type -P xdg-open || true)" - if [ -z "$browser" ]; then - browser="$(type -P w3m || true)" - if [ -z "$browser" ]; then - echo "$0: unable to start a web browser; please set \$BROWSER" - exit 1 - fi - fi - fi - exec "$browser" ${entry} - ''; - - desktopItem = pkgs.makeDesktopItem { - name = "nixos-manual"; - desktopName = "NixOS Manual"; - genericName = "View NixOS documentation in a web browser"; - icon = "nix-snowflake"; - exec = "${helpScript}/bin/nixos-help"; - categories = "System"; - }; + cfgd = config.documentation; in { options = { - services.nixosManual.enable = mkOption { - type = types.bool; - default = true; - description = '' - Whether to build the NixOS manual pages. - ''; - }; - + # TODO(@oxij): rename this to `.enable` eventually. services.nixosManual.showManual = mkOption { type = types.bool; default = false; @@ -114,37 +44,30 @@ in }; - config = mkIf cfg.enable { - - system.build.manual = manual; - - environment.systemPackages = [] - ++ optionals config.services.xserver.enable [ desktopItem pkgs.nixos-icons ] - ++ optional config.documentation.man.enable manual.manpages - ++ optionals config.documentation.doc.enable [ manual.manual helpScript ]; - - boot.extraTTYs = mkIf cfg.showManual ["tty${toString cfg.ttyNumber}"]; - - systemd.services = optionalAttrs cfg.showManual - { "nixos-manual" = - { description = "NixOS Manual"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = - { ExecStart = "${cfg.browser} ${entry}"; - StandardInput = "tty"; - StandardOutput = "tty"; - TTYPath = "/dev/tty${toString cfg.ttyNumber}"; - TTYReset = true; - TTYVTDisallocate = true; - Restart = "always"; - }; + config = mkMerge [ + (mkIf cfg.showManual { + assertions = singleton { + assertion = cfgd.enable && cfgd.nixos.enable; + message = "Can't enable `services.nixosManual.showManual` without `documentation.nixos.enable`"; + }; + }) + (mkIf (cfg.showManual && cfgd.enable && cfgd.nixos.enable) { + boot.extraTTYs = [ "tty${toString cfg.ttyNumber}" ]; + + systemd.services."nixos-manual" = { + description = "NixOS Manual"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${cfg.browser} ${config.system.build.manual.manualHTMLIndex}"; + StandardInput = "tty"; + StandardOutput = "tty"; + TTYPath = "/dev/tty${toString cfg.ttyNumber}"; + TTYReset = true; + TTYVTDisallocate = true; + Restart = "always"; }; }; - - services.mingetty.helpLine = "\nRun `nixos-help` " - + lib.optionalString cfg.showManual "or press <Alt-F${toString cfg.ttyNumber}> " - + "for the NixOS manual."; - - }; + }) + ]; } diff --git a/nixos/modules/services/misc/redmine.nix b/nixos/modules/services/misc/redmine.nix index f763ba21d0b2..8d25ac5cb76f 100644 --- a/nixos/modules/services/misc/redmine.nix +++ b/nixos/modules/services/misc/redmine.nix @@ -5,7 +5,7 @@ with lib; let cfg = config.services.redmine; - bundle = "${pkgs.redmine}/share/redmine/bin/bundle"; + bundle = "${cfg.package}/share/redmine/bin/bundle"; databaseYml = pkgs.writeText "database.yml" '' production: @@ -15,6 +15,7 @@ let port: ${toString cfg.database.port} username: ${cfg.database.user} password: #dbpass# + ${optionalString (cfg.database.socket != null) "socket: ${cfg.database.socket}"} ''; configurationYml = pkgs.writeText "configuration.yml" '' @@ -29,6 +30,19 @@ let ${cfg.extraConfig} ''; + unpackTheme = unpack "theme"; + unpackPlugin = unpack "plugin"; + unpack = id: (name: source: + pkgs.stdenv.mkDerivation { + name = "redmine-${id}-${name}"; + buildInputs = [ pkgs.unzip ]; + buildCommand = '' + mkdir -p $out + cd $out + unpackFile ${source} + ''; + }); + in { @@ -40,6 +54,14 @@ in description = "Enable the Redmine service."; }; + package = mkOption { + type = types.package; + default = pkgs.redmine; + defaultText = "pkgs.redmine"; + description = "Which Redmine package to use."; + example = "pkgs.redmine.override { ruby = pkgs.ruby_2_3; }"; + }; + user = mkOption { type = types.str; default = "redmine"; @@ -52,6 +74,12 @@ in description = "Group under which Redmine is ran."; }; + port = mkOption { + type = types.int; + default = 3000; + description = "Port on which Redmine is ran."; + }; + stateDir = mkOption { type = types.str; default = "/var/lib/redmine"; @@ -66,6 +94,41 @@ in See https://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-configuration ''; + example = literalExample '' + email_delivery: + delivery_method: smtp + smtp_settings: + address: mail.example.com + port: 25 + ''; + }; + + themes = mkOption { + type = types.attrsOf types.path; + default = {}; + description = "Set of themes."; + example = literalExample '' + { + dkuk-redmine_alex_skin = builtins.fetchurl { + url = https://bitbucket.org/dkuk/redmine_alex_skin/get/1842ef675ef3.zip; + sha256 = "0hrin9lzyi50k4w2bd2b30vrf1i4fi1c0gyas5801wn8i7kpm9yl"; + }; + } + ''; + }; + + plugins = mkOption { + type = types.attrsOf types.path; + default = {}; + description = "Set of plugins."; + example = literalExample '' + { + redmine_env_auth = builtins.fetchurl { + url = https://github.com/Intera/redmine_env_auth/archive/0.6.zip; + sha256 = "0yyr1yjd8gvvh832wdc8m3xfnhhxzk2pk3gm2psg5w9jdvd6skak"; + }; + } + ''; }; database = { @@ -78,7 +141,7 @@ in host = mkOption { type = types.str; - default = "127.0.0.1"; + default = (if cfg.database.socket != null then "localhost" else "127.0.0.1"); description = "Database host address."; }; @@ -119,6 +182,13 @@ in <option>database.user</option>. ''; }; + + socket = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/mysqld/mysqld.sock"; + description = "Path to the unix socket file to use for authentication."; + }; }; }; }; @@ -126,17 +196,20 @@ in config = mkIf cfg.enable { assertions = [ - { assertion = cfg.database.passwordFile != null || cfg.database.password != ""; - message = "either services.redmine.database.passwordFile or services.redmine.database.password must be set"; + { assertion = cfg.database.passwordFile != null || cfg.database.password != "" || cfg.database.socket != null; + message = "one of services.redmine.database.socket, services.redmine.database.passwordFile, or services.redmine.database.password must be set"; + } + { assertion = cfg.database.socket != null -> (cfg.database.type == "mysql2"); + message = "Socket authentication is only available for the mysql2 database type"; } ]; - environment.systemPackages = [ pkgs.redmine ]; + environment.systemPackages = [ cfg.package ]; systemd.services.redmine = { after = [ "network.target" (if cfg.database.type == "mysql2" then "mysql.service" else "postgresql.service") ]; wantedBy = [ "multi-user.target" ]; - environment.HOME = "${pkgs.redmine}/share/redmine"; + environment.HOME = "${cfg.package}/share/redmine"; environment.RAILS_ENV = "production"; environment.RAILS_CACHE = "${cfg.stateDir}/cache"; environment.REDMINE_LANG = "en"; @@ -151,43 +224,80 @@ in subversion ]; preStart = '' - # start with a fresh config directory every time - rm -rf ${cfg.stateDir}/config - cp -r ${pkgs.redmine}/share/redmine/config.dist ${cfg.stateDir}/config + # ensure cache directory exists for db:migrate command + mkdir -p "${cfg.stateDir}/cache" - # create the basic state directory layout pkgs.redmine expects - mkdir -p /run/redmine + # create the basic directory layout the redmine package expects + mkdir -p /run/redmine/public for i in config files log plugins tmp; do - mkdir -p ${cfg.stateDir}/$i - ln -fs ${cfg.stateDir}/$i /run/redmine/$i + mkdir -p "${cfg.stateDir}/$i" + ln -fs "${cfg.stateDir}/$i" /run/redmine/ + done + + for i in plugin_assets themes; do + mkdir -p "${cfg.stateDir}/public/$i" + ln -fs "${cfg.stateDir}/public/$i" /run/redmine/public/ done - # ensure cache directory exists for db:migrate command - mkdir -p ${cfg.stateDir}/cache + + # start with a fresh config directory + # the config directory is copied instead of linked as some mutable data is stored in there + rm -rf "${cfg.stateDir}/config/"* + cp -r ${cfg.package}/share/redmine/config.dist/* "${cfg.stateDir}/config/" # link in the application configuration - ln -fs ${configurationYml} ${cfg.stateDir}/config/configuration.yml + ln -fs ${configurationYml} "${cfg.stateDir}/config/configuration.yml" + + + # link in all user specified themes + rm -rf "${cfg.stateDir}/public/themes/"* + for theme in ${concatStringsSep " " (mapAttrsToList unpackTheme cfg.themes)}; do + ln -fs $theme/* "${cfg.stateDir}/public/themes" + done + + # link in redmine provided themes + ln -sf ${cfg.package}/share/redmine/public/themes.dist/* "${cfg.stateDir}/public/themes/" + - chmod -R ug+rwX,o-rwx+x ${cfg.stateDir}/ + # link in all user specified plugins + rm -rf "${cfg.stateDir}/plugins/"* + for plugin in ${concatStringsSep " " (mapAttrsToList unpackPlugin cfg.plugins)}; do + ln -fs $plugin/* "${cfg.stateDir}/plugins/''${plugin##*-redmine-plugin-}" + done + + + # ensure correct permissions for most files + chmod -R ug+rwX,o-rwx+x "${cfg.stateDir}/" - # handle database.passwordFile + + # handle database.passwordFile & permissions DBPASS=$(head -n1 ${cfg.database.passwordFile}) - cp -f ${databaseYml} ${cfg.stateDir}/config/database.yml - sed -e "s,#dbpass#,$DBPASS,g" -i ${cfg.stateDir}/config/database.yml - chmod 440 ${cfg.stateDir}/config/database.yml + cp -f ${databaseYml} "${cfg.stateDir}/config/database.yml" + sed -e "s,#dbpass#,$DBPASS,g" -i "${cfg.stateDir}/config/database.yml" + chmod 440 "${cfg.stateDir}/config/database.yml" + # generate a secret token if required if ! test -e "${cfg.stateDir}/config/initializers/secret_token.rb"; then ${bundle} exec rake generate_secret_token - chmod 440 ${cfg.stateDir}/config/initializers/secret_token.rb + chmod 440 "${cfg.stateDir}/config/initializers/secret_token.rb" fi + # ensure everything is owned by ${cfg.user} - chown -R ${cfg.user}:${cfg.group} ${cfg.stateDir} + chown -R ${cfg.user}:${cfg.group} "${cfg.stateDir}" + + + # execute redmine required commands prior to starting the application + # NOTE: su required in case using mysql socket authentication + /run/wrappers/bin/su -s ${pkgs.bash}/bin/bash -m -l redmine -c '${bundle} exec rake db:migrate' + /run/wrappers/bin/su -s ${pkgs.bash}/bin/bash -m -l redmine -c '${bundle} exec rake redmine:load_default_data' + - ${bundle} exec rake db:migrate - ${bundle} exec rake redmine:load_default_data + # log files don't exist until after first command has been executed + # correct ownership of files generated by calling exec rake ... + chown -R ${cfg.user}:${cfg.group} "${cfg.stateDir}/log" ''; serviceConfig = { @@ -196,13 +306,13 @@ in User = cfg.user; Group = cfg.group; TimeoutSec = "300"; - WorkingDirectory = "${pkgs.redmine}/share/redmine"; - ExecStart="${bundle} exec rails server webrick -e production -P ${cfg.stateDir}/redmine.pid"; + WorkingDirectory = "${cfg.package}/share/redmine"; + ExecStart="${bundle} exec rails server webrick -e production -p ${toString cfg.port} -P '${cfg.stateDir}/redmine.pid'"; }; }; - users.extraUsers = optionalAttrs (cfg.user == "redmine") (singleton + users.users = optionalAttrs (cfg.user == "redmine") (singleton { name = "redmine"; group = cfg.group; home = cfg.stateDir; @@ -210,7 +320,7 @@ in uid = config.ids.uids.redmine; }); - users.extraGroups = optionalAttrs (cfg.group == "redmine") (singleton + users.groups = optionalAttrs (cfg.group == "redmine") (singleton { name = "redmine"; gid = config.ids.gids.redmine; }); diff --git a/nixos/modules/services/misc/sickbeard.nix b/nixos/modules/services/misc/sickbeard.nix new file mode 100644 index 000000000000..5cfbbe516ae1 --- /dev/null +++ b/nixos/modules/services/misc/sickbeard.nix @@ -0,0 +1,92 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + name = "sickbeard"; + + cfg = config.services.sickbeard; + sickbeard = cfg.package; + +in +{ + + ###### interface + + options = { + services.sickbeard = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the sickbeard server."; + }; + package = mkOption { + type = types.package; + default = pkgs.sickbeard; + example = literalExample "pkgs.sickrage"; + description ='' + Enable <literal>pkgs.sickrage</literal> or <literal>pkgs.sickgear</literal> + as an alternative to SickBeard + ''; + }; + dataDir = mkOption { + type = types.path; + default = "/var/lib/${name}"; + description = "Path where to store data files."; + }; + configFile = mkOption { + type = types.path; + default = "${cfg.dataDir}/config.ini"; + description = "Path to config file."; + }; + port = mkOption { + type = types.ints.u16; + default = 8081; + description = "Port to bind to."; + }; + user = mkOption { + type = types.str; + default = name; + description = "User to run the service as"; + }; + group = mkOption { + type = types.str; + default = name; + description = "Group to run the service as"; + }; + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + + users.users = optionalAttrs (cfg.user == name) (singleton { + name = name; + uid = config.ids.uids.sickbeard; + group = cfg.group; + description = "sickbeard user"; + home = cfg.dataDir; + createHome = true; + }); + + users.groups = optionalAttrs (cfg.group == name) (singleton { + name = name; + gid = config.ids.gids.sickbeard; + }); + + systemd.services.sickbeard = { + description = "Sickbeard Server"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + serviceConfig = { + User = cfg.user; + Group = cfg.group; + ExecStart = "${sickbeard}/SickBeard.py --datadir ${cfg.dataDir} --config ${cfg.configFile} --port ${toString cfg.port}"; + }; + }; + }; +} diff --git a/nixos/modules/services/misc/taskserver/doc.xml b/nixos/modules/services/misc/taskserver/doc.xml index 21d25ecf391f..5eac8d9ef784 100644 --- a/nixos/modules/services/misc/taskserver/doc.xml +++ b/nixos/modules/services/misc/taskserver/doc.xml @@ -2,101 +2,93 @@ xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0" xml:id="module-taskserver"> - - <title>Taskserver</title> + <title>Taskserver</title> + <para> + Taskserver is the server component of + <link xlink:href="https://taskwarrior.org/">Taskwarrior</link>, a free and + open source todo list application. + </para> + <para> + <emphasis>Upstream documentation:</emphasis> + <link xlink:href="https://taskwarrior.org/docs/#taskd"/> + </para> + <section xml:id="module-services-taskserver-configuration"> + <title>Configuration</title> <para> - Taskserver is the server component of - <link xlink:href="https://taskwarrior.org/">Taskwarrior</link>, a free and - open source todo list application. + Taskserver does all of its authentication via TLS using client certificates, + so you either need to roll your own CA or purchase a certificate from a + known CA, which allows creation of client certificates. These certificates + are usually advertised as <quote>server certificates</quote>. </para> <para> - <emphasis>Upstream documentation:</emphasis> - <link xlink:href="https://taskwarrior.org/docs/#taskd"/> + So in order to make it easier to handle your own CA, there is a helper tool + called <command>nixos-taskserver</command> which manages the custom CA along + with Taskserver organisations, users and groups. </para> - <section xml:id="module-services-taskserver-configuration"> - <title>Configuration</title> - - <para> - Taskserver does all of its authentication via TLS using client - certificates, so you either need to roll your own CA or purchase a - certificate from a known CA, which allows creation of client - certificates. - - These certificates are usually advertised as - <quote>server certificates</quote>. - </para> - - <para> - So in order to make it easier to handle your own CA, there is a helper - tool called <command>nixos-taskserver</command> which manages the custom - CA along with Taskserver organisations, users and groups. - </para> - - <para> - While the client certificates in Taskserver only authenticate whether a - user is allowed to connect, every user has its own UUID which identifies - it as an entity. - </para> - - <para> - With <command>nixos-taskserver</command> the client certificate is created - along with the UUID of the user, so it handles all of the credentials - needed in order to setup the Taskwarrior client to work with a Taskserver. - </para> - </section> + <para> + While the client certificates in Taskserver only authenticate whether a user + is allowed to connect, every user has its own UUID which identifies it as an + entity. + </para> - <section xml:id="module-services-taskserver-nixos-taskserver-tool"> - <title>The nixos-taskserver tool</title> + <para> + With <command>nixos-taskserver</command> the client certificate is created + along with the UUID of the user, so it handles all of the credentials needed + in order to setup the Taskwarrior client to work with a Taskserver. + </para> + </section> + <section xml:id="module-services-taskserver-nixos-taskserver-tool"> + <title>The nixos-taskserver tool</title> - <para> - Because Taskserver by default only provides scripts to setup users - imperatively, the <command>nixos-taskserver</command> tool is used for - addition and deletion of organisations along with users and groups defined - by <xref linkend="opt-services.taskserver.organisations"/> and as well for - imperative set up. - </para> + <para> + Because Taskserver by default only provides scripts to setup users + imperatively, the <command>nixos-taskserver</command> tool is used for + addition and deletion of organisations along with users and groups defined + by <xref linkend="opt-services.taskserver.organisations"/> and as well for + imperative set up. + </para> - <para> - The tool is designed to not interfere if the command is used to manually - set up some organisations, users or groups. - </para> + <para> + The tool is designed to not interfere if the command is used to manually set + up some organisations, users or groups. + </para> - <para> - For example if you add a new organisation using - <command>nixos-taskserver org add foo</command>, the organisation is not - modified and deleted no matter what you define in - <option>services.taskserver.organisations</option>, even if you're adding - the same organisation in that option. - </para> + <para> + For example if you add a new organisation using <command>nixos-taskserver + org add foo</command>, the organisation is not modified and deleted no + matter what you define in + <option>services.taskserver.organisations</option>, even if you're adding + the same organisation in that option. + </para> - <para> - The tool is modelled to imitate the official <command>taskd</command> - command, documentation for each subcommand can be shown by using the - <option>--help</option> switch. - </para> - </section> - <section xml:id="module-services-taskserver-declarative-ca-management"> - <title>Declarative/automatic CA management</title> + <para> + The tool is modelled to imitate the official <command>taskd</command> + command, documentation for each subcommand can be shown by using the + <option>--help</option> switch. + </para> + </section> + <section xml:id="module-services-taskserver-declarative-ca-management"> + <title>Declarative/automatic CA management</title> - <para> - Everything is done according to what you specify in the module options, - however in order to set up a Taskwarrior client for synchronisation with a - Taskserver instance, you have to transfer the keys and certificates to the - client machine. - </para> + <para> + Everything is done according to what you specify in the module options, + however in order to set up a Taskwarrior client for synchronisation with a + Taskserver instance, you have to transfer the keys and certificates to the + client machine. + </para> - <para> - This is done using - <command>nixos-taskserver user export $orgname $username</command> which - is printing a shell script fragment to stdout which can either be used - verbatim or adjusted to import the user on the client machine. - </para> + <para> + This is done using <command>nixos-taskserver user export $orgname + $username</command> which is printing a shell script fragment to stdout + which can either be used verbatim or adjusted to import the user on the + client machine. + </para> - <para> - For example, let's say you have the following configuration: + <para> + For example, let's say you have the following configuration: <screen> { <xref linkend="opt-services.taskserver.enable"/> = true; @@ -105,40 +97,39 @@ <link linkend="opt-services.taskserver.organisations._name_.users">services.taskserver.organisations.my-company.users</link> = [ "alice" ]; } </screen> - This creates an organisation called <literal>my-company</literal> with the - user <literal>alice</literal>. - </para> + This creates an organisation called <literal>my-company</literal> with the + user <literal>alice</literal>. + </para> - <para> - Now in order to import the <literal>alice</literal> user to another - machine <literal>alicebox</literal>, all we need to do is something like - this: + <para> + Now in order to import the <literal>alice</literal> user to another machine + <literal>alicebox</literal>, all we need to do is something like this: <screen> $ ssh server nixos-taskserver user export my-company alice | sh </screen> - Of course, if no SSH daemon is available on the server you can also copy - & paste it directly into a shell. - </para> + Of course, if no SSH daemon is available on the server you can also copy + & paste it directly into a shell. + </para> - <para> - After this step the user should be set up and you can start synchronising - your tasks for the first time with <command>task sync init</command> on - <literal>alicebox</literal>. - </para> + <para> + After this step the user should be set up and you can start synchronising + your tasks for the first time with <command>task sync init</command> on + <literal>alicebox</literal>. + </para> - <para> - Subsequent synchronisation requests merely require the command - <command>task sync</command> after that stage. - </para> - </section> - <section xml:id="module-services-taskserver-manual-ca-management"> - <title>Manual CA management</title> + <para> + Subsequent synchronisation requests merely require the command <command>task + sync</command> after that stage. + </para> + </section> + <section xml:id="module-services-taskserver-manual-ca-management"> + <title>Manual CA management</title> - <para> - If you set any options within - <link linkend="opt-services.taskserver.pki.manual.ca.cert">service.taskserver.pki.manual</link>.*, - <command>nixos-taskserver</command> won't issue certificates, but you can - still use it for adding or removing user accounts. - </para> - </section> + <para> + If you set any options within + <link linkend="opt-services.taskserver.pki.manual.ca.cert">service.taskserver.pki.manual</link>.*, + <command>nixos-taskserver</command> won't issue certificates, but you can + still use it for adding or removing user accounts. + </para> + </section> </chapter> diff --git a/nixos/modules/services/misc/weechat.nix b/nixos/modules/services/misc/weechat.nix new file mode 100644 index 000000000000..c6ff540ea12f --- /dev/null +++ b/nixos/modules/services/misc/weechat.nix @@ -0,0 +1,58 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.weechat; +in + +{ + options.services.weechat = { + enable = mkEnableOption "weechat"; + root = mkOption { + description = "Weechat state directory."; + type = types.str; + default = "/var/lib/weechat"; + }; + sessionName = mkOption { + description = "Name of the `screen' session for weechat."; + default = "weechat-screen"; + type = types.str; + }; + binary = mkOption { + description = "Binary to execute (by default \${weechat}/bin/weechat)."; + example = literalExample '' + ''${pkgs.weechat}/bin/weechat-headless + ''; + default = "${pkgs.weechat}/bin/weechat"; + }; + }; + + config = mkIf cfg.enable { + users = { + groups.weechat = {}; + users.weechat = { + createHome = true; + group = "weechat"; + home = cfg.root; + isSystemUser = true; + }; + }; + + systemd.services.weechat = { + environment.WEECHAT_HOME = cfg.root; + serviceConfig = { + User = "weechat"; + Group = "weechat"; + RemainAfterExit = "yes"; + }; + script = "exec ${config.security.wrapperDir}/screen -Dm -S ${cfg.sessionName} ${cfg.binary}"; + wantedBy = [ "multi-user.target" ]; + wants = [ "network.target" ]; + }; + + security.wrappers.screen.source = "${pkgs.screen}/bin/screen"; + }; + + meta.doc = ./weechat.xml; +} diff --git a/nixos/modules/services/misc/weechat.xml b/nixos/modules/services/misc/weechat.xml new file mode 100644 index 000000000000..b7f755bbc5c7 --- /dev/null +++ b/nixos/modules/services/misc/weechat.xml @@ -0,0 +1,66 @@ +<chapter xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xi="http://www.w3.org/2001/XInclude" + version="5.0" + xml:id="module-services-weechat"> + <title>WeeChat</title> + <para> + <link xlink:href="https://weechat.org/">WeeChat</link> is a fast and + extensible IRC client. + </para> + <section> + <title>Basic Usage</title> + + <para> + By default, the module creates a + <literal><link xlink:href="https://www.freedesktop.org/wiki/Software/systemd/">systemd</link></literal> + unit which runs the chat client in a detached + <literal><link xlink:href="https://www.gnu.org/software/screen/">screen</link></literal> + session. + </para> + + <para> + This can be done by enabling the <literal>weechat</literal> service: +<programlisting> +{ ... }: + +{ + <link linkend="opt-services.weechat.enable">services.weechat.enable</link> = true; +} +</programlisting> + </para> + + <para> + The service is managed by a dedicated user named <literal>weechat</literal> + in the state directory <literal>/var/lib/weechat</literal>. + </para> + </section> + <section> + <title>Re-attaching to WeeChat</title> + + <para> + WeeChat runs in a screen session owned by a dedicated user. To explicitly + allow your another user to attach to this session, the + <literal>screenrc</literal> needs to be tweaked by adding + <link xlink:href="https://www.gnu.org/software/screen/manual/html_node/Multiuser.html#Multiuser">multiuser</link> + support: +<programlisting> +{ + <link linkend="opt-programs.screen.screenrc">programs.screen.screenrc</link> = '' + multiuser on + acladd normal_user + ''; +} +</programlisting> + Now, the session can be re-attached like this: +<programlisting> +screen -x weechat/weechat-screen +</programlisting> + </para> + + <para> + <emphasis>The session name can be changed using + <link linkend="opt-services.weechat.sessionName">services.weechat.sessionName.</link></emphasis> + </para> + </section> +</chapter> diff --git a/nixos/modules/services/monitoring/datadog-agent.nix b/nixos/modules/services/monitoring/datadog-agent.nix index e545e06b3495..5434fe99347d 100644 --- a/nixos/modules/services/monitoring/datadog-agent.nix +++ b/nixos/modules/services/monitoring/datadog-agent.nix @@ -7,8 +7,7 @@ let ddConf = { dd_url = "https://app.datadoghq.com"; - skip_ssl_validation = "no"; - api_key = ""; + skip_ssl_validation = false; confd_path = "/etc/datadog-agent/conf.d"; additional_checksd = "/etc/datadog-agent/checks.d"; use_dogstatsd = true; @@ -16,6 +15,8 @@ let // optionalAttrs (cfg.logLevel != null) { log_level = cfg.logLevel; } // optionalAttrs (cfg.hostname != null) { inherit (cfg) hostname; } // optionalAttrs (cfg.tags != null ) { tags = concatStringsSep ", " cfg.tags; } + // optionalAttrs (cfg.enableLiveProcessCollection) { process_config = { enabled = "true"; }; } + // optionalAttrs (cfg.enableTraceAgent) { apm_config = { enabled = true; }; } // cfg.extraConfig; # Generate Datadog configuration files for each configured checks. @@ -125,6 +126,22 @@ in { ''; }; + enableLiveProcessCollection = mkOption { + description = '' + Whether to enable the live process collection agent. + ''; + default = false; + type = types.bool; + }; + + enableTraceAgent = mkOption { + description = '' + Whether to enable the trace agent. + ''; + default = false; + type = types.bool; + }; + checks = mkOption { description = '' Configuration for all Datadog checks. Keys of this attribute @@ -206,7 +223,6 @@ in { Group = "datadog"; Restart = "always"; RestartSec = 2; - PrivateTmp = true; }; restartTriggers = [ datadogPkg ] ++ map (etc: etc.source) etcfiles; } attrs; @@ -229,6 +245,25 @@ in { path = [ datadogPkg pkgs.python pkgs.sysstat pkgs.procps pkgs.jdk ]; serviceConfig.ExecStart = "${datadogPkg}/bin/dd-jmxfetch"; }); + + datadog-process-agent = lib.mkIf cfg.enableLiveProcessCollection (makeService { + description = "Datadog Live Process Agent"; + path = [ ]; + script = '' + export DD_API_KEY=$(head -n 1 ${cfg.apiKeyFile}) + ${pkgs.datadog-process-agent}/bin/agent --config /etc/datadog-agent/datadog.yaml + ''; + }); + + datadog-trace-agent = lib.mkIf cfg.enableTraceAgent (makeService { + description = "Datadog Trace Agent"; + path = [ ]; + script = '' + export DD_API_KEY=$(head -n 1 ${cfg.apiKeyFile}) + ${pkgs.datadog-trace-agent}/bin/trace-agent -config /etc/datadog-agent/datadog.yaml + ''; + }); + }; environment.etc = etcfiles; diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix index 3e801f9b838d..c0c16a429d89 100644 --- a/nixos/modules/services/monitoring/grafana.nix +++ b/nixos/modules/services/monitoring/grafana.nix @@ -4,6 +4,7 @@ with lib; let cfg = config.services.grafana; + opt = options.services.grafana; envOptions = { PATHS_DATA = cfg.dataDir; @@ -41,6 +42,12 @@ let AUTH_ANONYMOUS_ORG_ROLE = cfg.auth.anonymous.org_role; ANALYTICS_REPORTING_ENABLED = boolToString cfg.analytics.reporting.enable; + + SMTP_ENABLE = boolToString cfg.smtp.enable; + SMTP_HOST = cfg.smtp.host; + SMTP_USER = cfg.smtp.user; + SMTP_PASSWORD = cfg.smtp.password; + SMTP_FROM_ADDRESS = cfg.smtp.fromAddress; } // cfg.extraOptions; in { @@ -134,11 +141,23 @@ in { }; password = mkOption { - description = "Database password."; + description = '' + Database password. + This option is mutual exclusive with the passwordFile option. + ''; default = ""; type = types.str; }; + passwordFile = mkOption { + description = '' + File that containts the database password. + This option is mutual exclusive with the password option. + ''; + default = null; + type = types.nullOr types.path; + }; + path = mkOption { description = "Database path."; default = "${cfg.dataDir}/data/grafana.db"; @@ -163,16 +182,69 @@ in { }; adminPassword = mkOption { - description = "Default admin password."; + description = '' + Default admin password. + This option is mutual exclusive with the adminPasswordFile option. + ''; default = "admin"; type = types.str; }; + adminPasswordFile = mkOption { + description = '' + Default admin password. + This option is mutual exclusive with the <literal>adminPassword</literal> option. + ''; + default = null; + type = types.nullOr types.path; + }; + secretKey = mkOption { description = "Secret key used for signing."; default = "SW2YcwTIb9zpOOhoPsMm"; type = types.str; }; + + secretKeyFile = mkOption { + description = "Secret key used for signing."; + default = null; + type = types.nullOr types.path; + }; + }; + + smtp = { + enable = mkEnableOption "smtp"; + host = mkOption { + description = "Host to connect to"; + default = "localhost:25"; + type = types.str; + }; + user = mkOption { + description = "User used for authentication"; + default = ""; + type = types.str; + }; + password = mkOption { + description = '' + Password used for authentication. + This option is mutual exclusive with the passwordFile option. + ''; + default = ""; + type = types.str; + }; + passwordFile = mkOption { + description = '' + Password used for authentication. + This option is mutual exclusive with the password option. + ''; + default = null; + type = types.nullOr types.path; + }; + fromAddress = mkOption { + description = "Email address used for sending"; + default = "admin@grafana.localhost"; + type = types.str; + }; }; users = { @@ -235,18 +307,37 @@ in { but without GF_ prefix ''; default = {}; - type = types.attrsOf types.str; + type = with types; attrsOf (either str path); }; }; config = mkIf cfg.enable { warnings = optional ( - cfg.database.password != options.services.grafana.database.password.default || - cfg.security.adminPassword != options.services.grafana.security.adminPassword.default + cfg.database.password != opt.database.password.default || + cfg.security.adminPassword != opt.security.adminPassword.default ) "Grafana passwords will be stored as plaintext in the Nix store!"; environment.systemPackages = [ cfg.package ]; + assertions = [ + { + assertion = cfg.database.password != opt.database.password.default -> cfg.database.passwordFile == null; + message = "Cannot set both password and passwordFile"; + } + { + assertion = cfg.security.adminPassword != opt.security.adminPassword.default -> cfg.security.adminPasswordFile == null; + message = "Cannot set both adminPassword and adminPasswordFile"; + } + { + assertion = cfg.security.secretKeyFile != opt.security.secretKeyFile.default -> cfg.security.secretKeyFile == null; + message = "Cannot set both secretKey and secretKeyFile"; + } + { + assertion = cfg.smtp.password != opt.smtp.password.default -> cfg.smtp.passwordFile == null; + message = "Cannot set both password and secretKeyFile"; + } + ]; + systemd.services.grafana = { description = "Grafana Service Daemon"; wantedBy = ["multi-user.target"]; @@ -254,8 +345,22 @@ in { environment = { QT_QPA_PLATFORM = "offscreen"; } // mapAttrs' (n: v: nameValuePair "GF_${n}" (toString v)) envOptions; + script = '' + ${optionalString (cfg.database.passwordFile != null) '' + export GF_DATABASE_PASSWORD="$(cat ${escapeShellArg cfg.database.passwordFile})" + ''} + ${optionalString (cfg.security.adminPasswordFile != null) '' + export GF_SECURITY_ADMIN_PASSWORD="$(cat ${escapeShellArg cfg.security.adminPasswordFile})" + ''} + ${optionalString (cfg.security.secretKeyFile != null) '' + export GF_SECURITY_SECRET_KEY="$(cat ${escapeShellArg cfg.security.secretKeyFile})" + ''} + ${optionalString (cfg.smtp.passwordFile != null) '' + export GF_SMTP_PASSWORD="$(cat ${escapeShellArg cfg.smtp.passwordFile})" + ''} + exec ${cfg.package.bin}/bin/grafana-server -homepath ${cfg.dataDir} + ''; serviceConfig = { - ExecStart = "${cfg.package.bin}/bin/grafana-server -homepath ${cfg.dataDir}"; WorkingDirectory = cfg.dataDir; User = "grafana"; }; diff --git a/nixos/modules/services/monitoring/munin.nix b/nixos/modules/services/monitoring/munin.nix index ff9604c7dbcd..2b265d5b5a90 100644 --- a/nixos/modules/services/monitoring/munin.nix +++ b/nixos/modules/services/monitoring/munin.nix @@ -5,8 +5,8 @@ # TODO: support fastcgi # http://munin-monitoring.org/wiki/CgiHowto2 -# spawn-fcgi -s /var/run/munin/fastcgi-graph.sock -U www-data -u munin -g munin /usr/lib/munin/cgi/munin-cgi-graph -# spawn-fcgi -s /var/run/munin/fastcgi-html.sock -U www-data -u munin -g munin /usr/lib/munin/cgi/munin-cgi-html +# spawn-fcgi -s /run/munin/fastcgi-graph.sock -U www-data -u munin -g munin /usr/lib/munin/cgi/munin-cgi-graph +# spawn-fcgi -s /run/munin/fastcgi-html.sock -U www-data -u munin -g munin /usr/lib/munin/cgi/munin-cgi-html # https://paste.sh/vofcctHP#-KbDSXVeWoifYncZmLfZzgum # nginx http://munin.readthedocs.org/en/latest/example/webserver/nginx.html @@ -22,7 +22,7 @@ let dbdir /var/lib/munin htmldir /var/www/munin logdir /var/log/munin - rundir /var/run/munin + rundir /run/munin ${cronCfg.extraGlobalConfig} @@ -170,7 +170,7 @@ in wantedBy = [ "multi-user.target" ]; path = with pkgs; [ munin smartmontools "/run/current-system/sw" "/run/wrappers" ]; environment.MUNIN_LIBDIR = "${pkgs.munin}/lib"; - environment.MUNIN_PLUGSTATE = "/var/run/munin"; + environment.MUNIN_PLUGSTATE = "/run/munin"; environment.MUNIN_LOGDIR = "/var/log/munin"; preStart = '' echo "updating munin plugins..." @@ -188,7 +188,7 @@ in }; # munin_stats plugin breaks as of 2.0.33 when this doesn't exist - systemd.tmpfiles.rules = [ "d /var/run/munin 0755 munin munin -" ]; + systemd.tmpfiles.rules = [ "d /run/munin 0755 munin munin -" ]; }) (mkIf cronCfg.enable { @@ -210,7 +210,7 @@ in }; systemd.tmpfiles.rules = [ - "d /var/run/munin 0755 munin munin -" + "d /run/munin 0755 munin munin -" "d /var/log/munin 0755 munin munin -" "d /var/www/munin 0755 munin munin -" "d /var/lib/munin 0755 munin munin -" diff --git a/nixos/modules/services/monitoring/prometheus/alertmanager.nix b/nixos/modules/services/monitoring/prometheus/alertmanager.nix index 8a47c9f1e7d8..8a44cf7fd8f6 100644 --- a/nixos/modules/services/monitoring/prometheus/alertmanager.nix +++ b/nixos/modules/services/monitoring/prometheus/alertmanager.nix @@ -9,6 +9,15 @@ let if cfg.configText != null then pkgs.writeText "alertmanager.yml" cfg.configText else mkConfigFile; + cmdlineArgs = cfg.extraFlags ++ [ + "--config.file ${alertmanagerYml}" + "--web.listen-address ${cfg.listenAddress}:${toString cfg.port}" + "--log.level ${cfg.logLevel}" + ] ++ (optional (cfg.webExternalUrl != null) + "--web.external-url ${cfg.webExternalUrl}" + ) ++ (optional (cfg.logFormat != null) + "--log.format ${cfg.logFormat}" + ); in { options = { services.prometheus.alertmanager = { @@ -99,6 +108,14 @@ in { Open port in firewall for incoming connections. ''; }; + + extraFlags = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Extra commandline options when launching the Alertmanager. + ''; + }; }; }; @@ -111,11 +128,7 @@ 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}"} + ${concatStringsSep " \\\n " cmdlineArgs} ''; serviceConfig = { diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix index 5dda763bd56b..e2ee995cea80 100644 --- a/nixos/modules/services/monitoring/prometheus/default.nix +++ b/nixos/modules/services/monitoring/prometheus/default.nix @@ -39,6 +39,7 @@ let "-alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity}" "-alertmanager.timeout=${toString cfg.alertmanagerTimeout}s" (optionalString (cfg.alertmanagerURL != []) "-alertmanager.url=${concatStringsSep "," cfg.alertmanagerURL}") + (optionalString (cfg.webExternalUrl != null) "-web.external-url=${cfg.webExternalUrl}") ]; promTypes.globalConfig = types.submodule { @@ -467,6 +468,16 @@ in { Alert manager HTTP API timeout (in seconds). ''; }; + + webExternalUrl = mkOption { + type = types.nullOr types.str; + default = null; + example = "https://example.com/"; + description = '' + The URL under which Prometheus is externally reachable (for example, + if Prometheus is served via a reverse proxy). + ''; + }; }; }; diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix index 1d5f400250fd..950af848c0f6 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -30,6 +30,7 @@ let postfix = import ./exporters/postfix.nix { inherit config lib pkgs; }; snmp = import ./exporters/snmp.nix { inherit config lib pkgs; }; surfboard = import ./exporters/surfboard.nix { inherit config lib pkgs; }; + tor = import ./exporters/tor.nix { inherit config lib pkgs; }; unifi = import ./exporters/unifi.nix { inherit config lib pkgs; }; varnish = import ./exporters/varnish.nix { inherit config lib pkgs; }; }; @@ -123,15 +124,13 @@ let systemd.services."prometheus-${name}-exporter" = mkMerge ([{ wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - serviceConfig = { - Restart = mkDefault "always"; - PrivateTmp = mkDefault true; - WorkingDirectory = mkDefault /tmp; - } // mkIf (!(serviceOpts.serviceConfig.DynamicUser or false)) { - User = conf.user; - Group = conf.group; - }; - } serviceOpts ]); + serviceConfig.Restart = mkDefault "always"; + serviceConfig.PrivateTmp = mkDefault true; + serviceConfig.WorkingDirectory = mkDefault /tmp; + } serviceOpts ] ++ optional (serviceOpts.serviceConfig.DynamicUser or false) { + serviceConfig.User = conf.user; + serviceConfig.Group = conf.group; + }); }; in { @@ -172,5 +171,8 @@ in }) exporterOpts) ); - meta.doc = ./exporters.xml; + meta = { + doc = ./exporters.xml; + maintainers = [ maintainers.willibutz ]; + }; } diff --git a/nixos/modules/services/monitoring/prometheus/exporters.xml b/nixos/modules/services/monitoring/prometheus/exporters.xml index be86abb74b44..7a0a1bdf2c14 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters.xml +++ b/nixos/modules/services/monitoring/prometheus/exporters.xml @@ -3,13 +3,19 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="module-services-prometheus-exporters"> + <title>Prometheus exporters</title> + <para> + Prometheus exporters provide metrics for the + <link xlink:href="https://prometheus.io">prometheus monitoring system</link>. + </para> + <section xml:id="module-services-prometheus-exporters-configuration"> + <title>Configuration</title> -<title>Prometheus exporters</title> - -<para>Prometheus exporters provide metrics for the <link xlink:href="https://prometheus.io">prometheus monitoring system</link>.</para> - -<section xml:id="module-services-prometheus-exporters-configuration"><title>Configuration</title> - <para>One of the most common exporters is the <link xlink:href="https://github.com/prometheus/node_exporter">node exporter</link>, it provides hardware and OS metrics from the host it's running on. The exporter could be configured as follows: + <para> + One of the most common exporters is the + <link xlink:href="https://github.com/prometheus/node_exporter">node + exporter</link>, it provides hardware and OS metrics from the host it's + running on. The exporter could be configured as follows: <programlisting> services.promtheus.exporters.node = { enable = true; @@ -24,43 +30,88 @@ firewallFilter = "-i br0 -p tcp -m tcp --dport 9100"; }; </programlisting> -It should now serve all metrics from the collectors -that are explicitly enabled and the ones that are -<link xlink:href="https://github.com/prometheus/node_exporter#enabled-by-default">enabled by default</link>, via http under <literal>/metrics</literal>. In this example the firewall should just -allow incoming connections to the exporter's port on the bridge interface <literal>br0</literal> -(this would have to be configured seperately of course). -For more information about configuration see <literal>man configuration.nix</literal> or -search through the <link xlink:href="https://nixos.org/nixos/options.html#prometheus.exporters">available options</link>. -</para> -</section> -<section xml:id="module-services-prometheus-exporters-new-exporter"><title>Adding a new exporter</title> - <para>To add a new exporter, it has to be packaged first (see <literal>nixpkgs/pkgs/servers/monitoring/prometheus/</literal> for examples), then a module can be added. The postfix exporter is used in this example:</para> -<itemizedlist> - <listitem> + It should now serve all metrics from the collectors that are explicitly + enabled and the ones that are + <link xlink:href="https://github.com/prometheus/node_exporter#enabled-by-default">enabled + by default</link>, via http under <literal>/metrics</literal>. In this + example the firewall should just allow incoming connections to the + exporter's port on the bridge interface <literal>br0</literal> (this would + have to be configured seperately of course). For more information about + configuration see <literal>man configuration.nix</literal> or search through + the + <link xlink:href="https://nixos.org/nixos/options.html#prometheus.exporters">available + options</link>. + </para> + </section> + <section xml:id="module-services-prometheus-exporters-new-exporter"> + <title>Adding a new exporter</title> + + <para> + To add a new exporter, it has to be packaged first (see + <literal>nixpkgs/pkgs/servers/monitoring/prometheus/</literal> for + examples), then a module can be added. The postfix exporter is used in this + example: + </para> + + <itemizedlist> + <listitem> <para> - Some default options for all exporters are provided by - <literal>nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix</literal>: + Some default options for all exporters are provided by + <literal>nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix</literal>: </para> - </listitem> - <listitem override='none'> + </listitem> + <listitem override='none'> <itemizedlist> - <listitem><para><literal>enable</literal></para></listitem> - <listitem><para><literal>port</literal></para></listitem> - <listitem><para><literal>listenAddress</literal></para></listitem> - <listitem><para><literal>extraFlags</literal></para></listitem> - <listitem><para><literal>openFirewall</literal></para></listitem> - <listitem><para><literal>firewallFilter</literal></para></listitem> - <listitem><para><literal>user</literal></para></listitem> - <listitem><para><literal>group</literal></para></listitem> + <listitem> + <para> + <literal>enable</literal> + </para> + </listitem> + <listitem> + <para> + <literal>port</literal> + </para> + </listitem> + <listitem> + <para> + <literal>listenAddress</literal> + </para> + </listitem> + <listitem> + <para> + <literal>extraFlags</literal> + </para> + </listitem> + <listitem> + <para> + <literal>openFirewall</literal> + </para> + </listitem> + <listitem> + <para> + <literal>firewallFilter</literal> + </para> + </listitem> + <listitem> + <para> + <literal>user</literal> + </para> + </listitem> + <listitem> + <para> + <literal>group</literal> + </para> + </listitem> </itemizedlist> - </listitem> - <listitem> - <para>As there is already a package available, the module can now be added. - This is accomplished by adding a new file to the - <literal>nixos/modules/services/monitoring/prometheus/exporters/</literal> directory, - which will be called postfix.nix and contains all exporter specific options - and configuration: - <programlisting> + </listitem> + <listitem> + <para> + As there is already a package available, the module can now be added. This + is accomplished by adding a new file to the + <literal>nixos/modules/services/monitoring/prometheus/exporters/</literal> + directory, which will be called postfix.nix and contains all exporter + specific options and configuration: +<programlisting> # nixpgs/nixos/modules/services/prometheus/exporters/postfix.nix { config, lib, pkgs }: @@ -121,15 +172,16 @@ search through the <link xlink:href="https://nixos.org/nixos/options.html#promet } </programlisting> </para> - </listitem> - <listitem> + </listitem> + <listitem> <para> - This should already be enough for the postfix exporter. Additionally one could - now add assertions and conditional default values. This can be done in the - 'meta-module' that combines all exporter definitions and generates the submodules: - <literal>nixpkgs/nixos/modules/services/prometheus/exporters.nix</literal> + This should already be enough for the postfix exporter. Additionally one + could now add assertions and conditional default values. This can be done + in the 'meta-module' that combines all exporter definitions and generates + the submodules: + <literal>nixpkgs/nixos/modules/services/prometheus/exporters.nix</literal> </para> - </listitem> -</itemizedlist> -</section> + </listitem> + </itemizedlist> + </section> </chapter> diff --git a/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix b/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix index 404cd0a1896b..0d9194124325 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters/snmp.nix @@ -60,10 +60,10 @@ in DynamicUser = true; ExecStart = '' ${pkgs.prometheus-snmp-exporter.bin}/bin/snmp_exporter \ - -config.file ${configFile} \ - -log.format ${cfg.logFormat} \ - -log.level ${cfg.logLevel} \ - -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + --config.file=${configFile} \ + --log.format=${cfg.logFormat} \ + --log.level=${cfg.logLevel} \ + --web.listen-address=${cfg.listenAddress}:${toString cfg.port} \ ${concatStringsSep " \\\n " cfg.extraFlags} ''; }; diff --git a/nixos/modules/services/monitoring/prometheus/exporters/tor.nix b/nixos/modules/services/monitoring/prometheus/exporters/tor.nix new file mode 100644 index 000000000000..0e2a13c44ab7 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/tor.nix @@ -0,0 +1,40 @@ +{ config, lib, pkgs }: + +with lib; + +let + cfg = config.services.prometheus.exporters.tor; +in +{ + port = 9130; + extraOpts = { + torControlAddress = mkOption { + type = types.str; + default = "127.0.0.1"; + description = '' + Tor control IP address or hostname. + ''; + }; + + torControlPort = mkOption { + type = types.int; + default = 9051; + description = '' + Tor control port. + ''; + }; + }; + serviceOpts = { + serviceConfig = { + DynamicUser = true; + ExecStart = '' + ${pkgs.prometheus-tor-exporter}/bin/prometheus-tor-exporter \ + -b ${cfg.listenAddress} \ + -p ${toString cfg.port} \ + -a ${cfg.torControlAddress} \ + -c ${toString cfg.torControlPort} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix b/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix index 8dbf2d735ab9..aaed76175b84 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters/varnish.nix @@ -69,6 +69,7 @@ in path = [ pkgs.varnish ]; serviceConfig = { DynamicUser = true; + RestartSec = mkDefault 1; ExecStart = '' ${pkgs.prometheus-varnish-exporter}/bin/prometheus_varnish_exporter \ --web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ diff --git a/nixos/modules/services/monitoring/riemann.nix b/nixos/modules/services/monitoring/riemann.nix index 237de53456f9..13d2b1cc0602 100644 --- a/nixos/modules/services/monitoring/riemann.nix +++ b/nixos/modules/services/monitoring/riemann.nix @@ -17,9 +17,9 @@ let launcher = writeScriptBin "riemann" '' #!/bin/sh - exec ${jdk}/bin/java ${concatStringsSep "\n" cfg.extraJavaOpts} \ + exec ${jdk}/bin/java ${concatStringsSep " " cfg.extraJavaOpts} \ -cp ${classpath} \ - riemann.bin ${writeText "riemann-config.clj" riemannConfig} + riemann.bin ${cfg.configFile} ''; in { @@ -37,7 +37,8 @@ in { config = mkOption { type = types.lines; description = '' - Contents of the Riemann configuration file. + Contents of the Riemann configuration file. For more complicated + config you should use configFile. ''; }; configFiles = mkOption { @@ -47,7 +48,15 @@ in { Extra files containing Riemann configuration. These files will be loaded at runtime by Riemann (with Clojure's <literal>load-file</literal> function) at the end of the - configuration. + configuration if you use the config option, this is ignored if you + use configFile. + ''; + }; + configFile = mkOption { + type = types.str; + description = '' + A Riemann config file. Any files in the same directory as this file + will be added to the classpath by Riemann. ''; }; extraClasspathEntries = mkOption { @@ -77,6 +86,10 @@ in { group = "riemann"; }; + services.riemann.configFile = mkDefault ( + writeText "riemann-config.clj" riemannConfig + ); + systemd.services.riemann = { wantedBy = [ "multi-user.target" ]; path = [ inetutils ]; @@ -84,6 +97,7 @@ in { User = "riemann"; ExecStart = "${launcher}/bin/riemann"; }; + serviceConfig.LimitNOFILE = 65536; }; }; diff --git a/nixos/modules/services/network-filesystems/openafs/client.nix b/nixos/modules/services/network-filesystems/openafs/client.nix index 52c0966e05bc..240c1392088f 100644 --- a/nixos/modules/services/network-filesystems/openafs/client.nix +++ b/nixos/modules/services/network-filesystems/openafs/client.nix @@ -149,11 +149,13 @@ in packages = { module = mkOption { default = config.boot.kernelPackages.openafs; + defaultText = "config.boot.kernelPackages.openafs"; type = types.package; description = "OpenAFS kernel module package. MUST match the userland package!"; }; programs = mkOption { default = getBin pkgs.openafs; + defaultText = "config.boot.kernelPackages.openafs"; type = types.package; description = "OpenAFS programs package. MUST match the kernel module package!"; }; diff --git a/nixos/modules/services/network-filesystems/openafs/server.nix b/nixos/modules/services/network-filesystems/openafs/server.nix index 4c80ed0839f7..095024d2c8af 100644 --- a/nixos/modules/services/network-filesystems/openafs/server.nix +++ b/nixos/modules/services/network-filesystems/openafs/server.nix @@ -80,6 +80,7 @@ in { package = mkOption { default = pkgs.openafs.server or pkgs.openafs; + defaultText = "pkgs.openafs.server or pkgs.openafs"; type = types.package; description = "OpenAFS package for the server binaries"; }; diff --git a/nixos/modules/services/networking/bitlbee.nix b/nixos/modules/services/networking/bitlbee.nix index 392a8d5c2e7c..274b36171608 100644 --- a/nixos/modules/services/networking/bitlbee.nix +++ b/nixos/modules/services/networking/bitlbee.nix @@ -7,9 +7,10 @@ let cfg = config.services.bitlbee; bitlbeeUid = config.ids.uids.bitlbee; - bitlbeePkg = if cfg.libpurple_plugins == [] - then pkgs.bitlbee - else pkgs.bitlbee.override { enableLibPurple = true; }; + bitlbeePkg = pkgs.bitlbee.override { + enableLibPurple = cfg.libpurple_plugins != []; + enablePam = cfg.authBackend == "pam"; + }; bitlbeeConfig = pkgs.writeText "bitlbee.conf" '' @@ -20,6 +21,7 @@ let DaemonInterface = ${cfg.interface} DaemonPort = ${toString cfg.portNumber} AuthMode = ${cfg.authMode} + AuthBackend = ${cfg.authBackend} Plugindir = ${pkgs.bitlbee-plugins cfg.plugins}/lib/bitlbee ${lib.optionalString (cfg.hostName != "") "HostName = ${cfg.hostName}"} ${lib.optionalString (cfg.protocols != "") "Protocols = ${cfg.protocols}"} @@ -31,7 +33,7 @@ let purple_plugin_path = lib.concatMapStringsSep ":" - (plugin: "${plugin}/lib/pidgin/") + (plugin: "${plugin}/lib/pidgin/:${plugin}/lib/purple-2/") cfg.libpurple_plugins ; @@ -70,6 +72,16 @@ in ''; }; + authBackend = mkOption { + default = "storage"; + type = types.enum [ "storage" "pam" ]; + description = '' + How users are authenticated + storage -- save passwords internally + pam -- Linux PAM authentication + ''; + }; + authMode = mkOption { default = "Open"; type = types.enum [ "Open" "Closed" "Registered" ]; @@ -147,23 +159,22 @@ in ###### implementation - config = mkIf config.services.bitlbee.enable { - - users.users = singleton - { name = "bitlbee"; + config = mkMerge [ + (mkIf config.services.bitlbee.enable { + users.users = singleton { + name = "bitlbee"; uid = bitlbeeUid; description = "BitlBee user"; home = "/var/lib/bitlbee"; createHome = true; }; - users.groups = singleton - { name = "bitlbee"; + users.groups = singleton { + name = "bitlbee"; gid = config.ids.gids.bitlbee; }; - systemd.services.bitlbee = - { + systemd.services.bitlbee = { environment.PURPLE_PLUGIN_PATH = purple_plugin_path; description = "BitlBee IRC to other chat networks gateway"; after = [ "network.target" ]; @@ -172,8 +183,12 @@ in serviceConfig.ExecStart = "${bitlbeePkg}/sbin/bitlbee -F -n -c ${bitlbeeConfig}"; }; - environment.systemPackages = [ bitlbeePkg ]; + environment.systemPackages = [ bitlbeePkg ]; - }; + }) + (mkIf (config.services.bitlbee.authBackend == "pam") { + security.pam.services.bitlbee = {}; + }) + ]; } diff --git a/nixos/modules/services/networking/charybdis.nix b/nixos/modules/services/networking/charybdis.nix index 6d57faa9ac2b..3d02dc8d1375 100644 --- a/nixos/modules/services/networking/charybdis.nix +++ b/nixos/modules/services/networking/charybdis.nix @@ -90,7 +90,7 @@ in BANDB_DBPATH = "${cfg.statedir}/ban.db"; }; serviceConfig = { - ExecStart = "${charybdis}/bin/charybdis-ircd -foreground -logfile /dev/stdout -configfile ${configFile}"; + ExecStart = "${charybdis}/bin/charybdis -foreground -logfile /dev/stdout -configfile ${configFile}"; Group = cfg.group; User = cfg.user; PermissionsStartOnly = true; # preStart needs to run with root permissions diff --git a/nixos/modules/services/networking/chrony.nix b/nixos/modules/services/networking/chrony.nix index cef30661cc33..a363b545d649 100644 --- a/nixos/modules/services/networking/chrony.nix +++ b/nixos/modules/services/networking/chrony.nix @@ -3,12 +3,10 @@ with lib; let + cfg = config.services.chrony; stateDir = "/var/lib/chrony"; - - keyFile = "/etc/chrony.keys"; - - cfg = config.services.chrony; + keyFile = "${stateDir}/chrony.keys"; configFile = pkgs.writeText "chrony.conf" '' ${concatMapStringsSep "\n" (server: "server " + server) cfg.servers} @@ -19,7 +17,6 @@ let } driftfile ${stateDir}/chrony.drift - keyfile ${keyFile} ${optionalString (!config.time.hardwareClockInLocalTime) "rtconutc"} @@ -27,18 +24,11 @@ let ${cfg.extraConfig} ''; - chronyFlags = "-n -m -u chrony -f ${configFile} ${toString cfg.extraFlags}"; - + chronyFlags = "-m -u chrony -f ${configFile} ${toString cfg.extraFlags}"; in - { - - ###### interface - options = { - services.chrony = { - enable = mkOption { default = false; description = '' @@ -83,15 +73,9 @@ in description = "Extra flags passed to the chronyd command."; }; }; - }; - - ###### implementation - config = mkIf cfg.enable { - - # Make chronyc available in the system path environment.systemPackages = [ pkgs.chrony ]; users.groups = singleton @@ -113,26 +97,30 @@ in { description = "chrony NTP daemon"; wantedBy = [ "multi-user.target" ]; - wants = [ "time-sync.target" ]; - before = [ "time-sync.target" ]; - after = [ "network.target" ]; + wants = [ "time-sync.target" ]; + before = [ "time-sync.target" ]; + after = [ "network.target" ]; conflicts = [ "ntpd.service" "systemd-timesyncd.service" ]; path = [ pkgs.chrony ]; - preStart = - '' - mkdir -m 0755 -p ${stateDir} - touch ${keyFile} - chmod 0640 ${keyFile} - chown chrony:chrony ${stateDir} ${keyFile} - ''; + preStart = '' + mkdir -m 0755 -p ${stateDir} + touch ${keyFile} + chmod 0640 ${keyFile} + chown chrony:chrony ${stateDir} ${keyFile} + ''; serviceConfig = - { ExecStart = "${pkgs.chrony}/bin/chronyd ${chronyFlags}"; + { Type = "forking"; + ExecStart = "${pkgs.chrony}/bin/chronyd ${chronyFlags}"; + + ProtectHome = "yes"; + ProtectSystem = "full"; + PrivateTmp = "yes"; + + ConditionCapability = "CAP_SYS_TIME"; }; }; - }; - } diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix index 9a2e13e9553c..a70967820b32 100644 --- a/nixos/modules/services/networking/ddclient.nix +++ b/nixos/modules/services/networking/ddclient.nix @@ -182,9 +182,10 @@ with lib; serviceConfig = rec { DynamicUser = true; RuntimeDirectory = StateDirectory; + RuntimeDirectoryMode = "0750"; StateDirectory = builtins.baseNameOf dataDir; Type = "oneshot"; - ExecStartPre = "!${lib.getBin pkgs.coreutils}/bin/install -m666 ${cfg.configFile} /run/${RuntimeDirectory}/ddclient.conf"; + ExecStartPre = "!${lib.getBin pkgs.coreutils}/bin/install -m660 ${cfg.configFile} /run/${RuntimeDirectory}/ddclient.conf"; ExecStart = "${lib.getBin pkgs.ddclient}/bin/ddclient -file /run/${RuntimeDirectory}/ddclient.conf"; }; }; diff --git a/nixos/modules/services/networking/dnscrypt-proxy.xml b/nixos/modules/services/networking/dnscrypt-proxy.xml index a97579202523..f90eef69848c 100644 --- a/nixos/modules/services/networking/dnscrypt-proxy.xml +++ b/nixos/modules/services/networking/dnscrypt-proxy.xml @@ -3,67 +3,64 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="sec-dnscrypt-proxy"> - - <title>DNSCrypt client proxy</title> + <title>DNSCrypt client proxy</title> + <para> + The DNSCrypt client proxy relays DNS queries to a DNSCrypt enabled upstream + resolver. The traffic between the client and the upstream resolver is + encrypted and authenticated, mitigating the risk of MITM attacks, DNS + poisoning attacks, and third-party snooping (assuming the upstream is + trustworthy). + </para> + <sect1 xml:id="sec-dnscrypt-proxy-configuration"> + <title>Basic configuration</title> <para> - The DNSCrypt client proxy relays DNS queries to a DNSCrypt enabled - upstream resolver. The traffic between the client and the upstream - resolver is encrypted and authenticated, mitigating the risk of MITM - attacks, DNS poisoning attacks, and third-party snooping (assuming the - upstream is trustworthy). - </para> - - <sect1 xml:id="sec-dnscrypt-proxy-configuration"><title>Basic configuration</title> - - <para> - To enable the client proxy, set - <programlisting> + To enable the client proxy, set +<programlisting> <xref linkend="opt-services.dnscrypt-proxy.enable"/> = true; </programlisting> </para> <para> - Enabling the client proxy does not alter the system nameserver; to - relay local queries, prepend <literal>127.0.0.1</literal> to - <option>networking.nameservers</option>. + Enabling the client proxy does not alter the system nameserver; to relay + local queries, prepend <literal>127.0.0.1</literal> to + <option>networking.nameservers</option>. </para> - - </sect1> - - <sect1 xml:id="sec-dnscrypt-proxy-forwarder"><title>As a forwarder for another DNS client</title> + </sect1> + <sect1 xml:id="sec-dnscrypt-proxy-forwarder"> + <title>As a forwarder for another DNS client</title> <para> - To run the DNSCrypt proxy client as a forwarder for another - DNS client, change the default proxy listening port to a - non-standard value and point the other client to it: - <programlisting> + To run the DNSCrypt proxy client as a forwarder for another DNS client, + change the default proxy listening port to a non-standard value and point + the other client to it: +<programlisting> <xref linkend="opt-services.dnscrypt-proxy.localPort"/> = 43; </programlisting> </para> - <sect2 xml:id="sec-dnscrypt-proxy-forwarder-dsnmasq"><title>dnsmasq</title> - <para> - <programlisting> + <sect2 xml:id="sec-dnscrypt-proxy-forwarder-dsnmasq"> + <title>dnsmasq</title> + <para> +<programlisting> { <xref linkend="opt-services.dnsmasq.enable"/> = true; <xref linkend="opt-services.dnsmasq.servers"/> = [ "127.0.0.1#43" ]; } </programlisting> - </para> + </para> </sect2> - <sect2 xml:id="sec-dnscrypt-proxy-forwarder-unbound"><title>unbound</title> - <para> - <programlisting> + <sect2 xml:id="sec-dnscrypt-proxy-forwarder-unbound"> + <title>unbound</title> + <para> +<programlisting> { <xref linkend="opt-services.unbound.enable"/> = true; <xref linkend="opt-services.unbound.forwardAddresses"/> = [ "127.0.0.1@43" ]; } </programlisting> - </para> + </para> </sect2> - - </sect1> - + </sect1> </chapter> diff --git a/nixos/modules/services/networking/epmd.nix b/nixos/modules/services/networking/epmd.nix new file mode 100644 index 000000000000..692b75e4f086 --- /dev/null +++ b/nixos/modules/services/networking/epmd.nix @@ -0,0 +1,56 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.epmd; + +in + +{ + ###### interface + options.services.epmd = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable socket activation for Erlang Port Mapper Daemon (epmd), + which acts as a name server on all hosts involved in distributed + Erlang computations. + ''; + }; + package = mkOption { + type = types.package; + default = pkgs.erlang; + description = '' + The Erlang package to use to get epmd binary. That way you can re-use + an Erlang runtime that is already installed for other purposes. + ''; + }; + }; + + ###### implementation + config = mkIf cfg.enable { + systemd.sockets.epmd = rec { + description = "Erlang Port Mapper Daemon Activation Socket"; + wantedBy = [ "sockets.target" ]; + before = wantedBy; + socketConfig = { + ListenStream = "4369"; + Accept = "false"; + }; + }; + + systemd.services.epmd = { + description = "Erlang Port Mapper Daemon"; + after = [ "network.target" ]; + requires = [ "epmd.socket" ]; + + serviceConfig = { + DynamicUser = true; + ExecStart = "${cfg.package}/bin/epmd -systemd"; + Type = "notify"; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/eternal-terminal.nix b/nixos/modules/services/networking/eternal-terminal.nix new file mode 100644 index 000000000000..be7337ece7e4 --- /dev/null +++ b/nixos/modules/services/networking/eternal-terminal.nix @@ -0,0 +1,89 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.eternal-terminal; + +in + +{ + + ###### interface + + options = { + + services.eternal-terminal = { + + enable = mkEnableOption "Eternal Terminal server"; + + port = mkOption { + default = 2022; + type = types.int; + description = '' + The port the server should listen on. Will use the server's default (2022) if not specified. + ''; + }; + + verbosity = mkOption { + default = 0; + type = types.enum (lib.range 0 9); + description = '' + The verbosity level (0-9). + ''; + }; + + silent = mkOption { + default = false; + type = types.bool; + description = '' + If enabled, disables all logging. + ''; + }; + + logSize = mkOption { + default = 20971520; + type = types.int; + description = '' + The maximum log size. + ''; + }; + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + + # We need to ensure the et package is fully installed because + # the (remote) et client runs the `etterminal` binary when it + # connects. + environment.systemPackages = [ pkgs.eternal-terminal ]; + + systemd.services = { + eternal-terminal = { + description = "Eternal Terminal server."; + wantedBy = [ "multi-user.target" ]; + after = [ "syslog.target" "network.target" ]; + serviceConfig = { + Type = "forking"; + ExecStart = "${pkgs.eternal-terminal}/bin/etserver --daemon --cfgfile=${pkgs.writeText "et.cfg" '' + ; et.cfg : Config file for Eternal Terminal + ; + + [Networking] + port = ${toString cfg.port} + + [Debug] + verbose = ${toString cfg.verbosity} + silent = ${if cfg.silent then "1" else "0"} + logsize = ${toString cfg.logSize} + ''}"; + Restart = "on-failure"; + KillMode = "process"; + }; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/hostapd.nix b/nixos/modules/services/networking/hostapd.nix index 3af0441a89d8..9f74e4963296 100644 --- a/nixos/modules/services/networking/hostapd.nix +++ b/nixos/modules/services/networking/hostapd.nix @@ -157,9 +157,9 @@ in { description = "hostapd wireless AP"; path = [ pkgs.hostapd ]; - wantedBy = [ "network.target" ]; - - after = [ "${cfg.interface}-cfg.service" "nat.service" "bind.service" "dhcpd.service" "sys-subsystem-net-devices-${cfg.interface}.device" ]; + after = [ "sys-subsystem-net-devices-${cfg.interface}.device" ]; + bindsTo = [ "sys-subsystem-net-devices-${cfg.interface}.device" ]; + requiredBy = [ "network-link-${cfg.interface}.service" ]; serviceConfig = { ExecStart = "${pkgs.hostapd}/bin/hostapd ${configFile}"; diff --git a/nixos/modules/services/networking/hylafax/default.nix b/nixos/modules/services/networking/hylafax/default.nix new file mode 100644 index 000000000000..4c63b822d165 --- /dev/null +++ b/nixos/modules/services/networking/hylafax/default.nix @@ -0,0 +1,29 @@ +{ config, lib, pkgs, ... }: + +{ + + imports = [ + ./options.nix + ./systemd.nix + ]; + + config = lib.modules.mkIf config.services.hylafax.enable { + environment.systemPackages = [ pkgs.hylafaxplus ]; + users.users.uucp = { + uid = config.ids.uids.uucp; + group = "uucp"; + description = "Unix-to-Unix CoPy system"; + isSystemUser = true; + inherit (config.users.users.nobody) home; + }; + assertions = [{ + assertion = config.services.hylafax.modems != {}; + message = '' + HylaFAX cannot be used without modems. + Please define at least one modem with + <option>config.services.hylafax.modems</option>. + ''; + }]; + }; + +} diff --git a/nixos/modules/services/networking/hylafax/faxq-default.nix b/nixos/modules/services/networking/hylafax/faxq-default.nix new file mode 100644 index 000000000000..a2630ce66b71 --- /dev/null +++ b/nixos/modules/services/networking/hylafax/faxq-default.nix @@ -0,0 +1,12 @@ +{ ... }: + +# see man:hylafax-config(5) + +{ + + ModemGroup = [ ''"any:.*"'' ]; + ServerTracing = "0x78701"; + SessionTracing = "0x78701"; + UUCPLockDir = "/var/lock"; + +} diff --git a/nixos/modules/services/networking/hylafax/faxq-wait.sh b/nixos/modules/services/networking/hylafax/faxq-wait.sh new file mode 100755 index 000000000000..8c39e9d20c18 --- /dev/null +++ b/nixos/modules/services/networking/hylafax/faxq-wait.sh @@ -0,0 +1,29 @@ +#! @shell@ -e + +# skip this if there are no modems at all +if ! stat -t "@spoolAreaPath@"/etc/config.* >/dev/null 2>&1 +then + exit 0 +fi + +echo "faxq started, waiting for modem(s) to initialize..." + +for i in `seq @timeoutSec@0 -1 0` # gracefully timeout +do + sleep 0.1 + # done if status files exist, but don't mention initialization + if \ + stat -t "@spoolAreaPath@"/status/* >/dev/null 2>&1 \ + && \ + ! grep --silent --ignore-case 'initializing server' \ + "@spoolAreaPath@"/status/* + then + echo "modem(s) apparently ready" + exit 0 + fi + # if i reached 0, modems probably failed to initialize + if test $i -eq 0 + then + echo "warning: modem initialization timed out" + fi +done diff --git a/nixos/modules/services/networking/hylafax/hfaxd-default.nix b/nixos/modules/services/networking/hylafax/hfaxd-default.nix new file mode 100644 index 000000000000..8999dae57f41 --- /dev/null +++ b/nixos/modules/services/networking/hylafax/hfaxd-default.nix @@ -0,0 +1,10 @@ +{ ... }: + +# see man:hfaxd(8) + +{ + + ServerTracing = "0x91"; + XferLogFile = "/clientlog"; + +} diff --git a/nixos/modules/services/networking/hylafax/modem-default.nix b/nixos/modules/services/networking/hylafax/modem-default.nix new file mode 100644 index 000000000000..7529b5b0aafd --- /dev/null +++ b/nixos/modules/services/networking/hylafax/modem-default.nix @@ -0,0 +1,22 @@ +{ pkgs, ... }: + +# see man:hylafax-config(5) + +{ + + TagLineFont = "etc/LiberationSans-25.pcf"; + TagLineLocale = ''en_US.UTF-8''; + + AdminGroup = "root"; # groups that can change server config + AnswerRotary = "fax"; # don't accept anything else but faxes + LogFileMode = "0640"; + PriorityScheduling = true; + RecvFileMode = "0640"; + ServerTracing = "0x78701"; + SessionTracing = "0x78701"; + UUCPLockDir = "/var/lock"; + + SendPageCmd = ''${pkgs.coreutils}/bin/false''; # prevent pager transmit + SendUUCPCmd = ''${pkgs.coreutils}/bin/false''; # prevent UUCP transmit + +} diff --git a/nixos/modules/services/networking/hylafax/options.nix b/nixos/modules/services/networking/hylafax/options.nix new file mode 100644 index 000000000000..4ac6d3fa8432 --- /dev/null +++ b/nixos/modules/services/networking/hylafax/options.nix @@ -0,0 +1,375 @@ +{ config, lib, pkgs, ... }: + +let + + inherit (lib.options) literalExample mkEnableOption mkOption; + inherit (lib.types) bool enum int lines loaOf nullOr path str submodule; + inherit (lib.modules) mkDefault mkIf mkMerge; + + commonDescr = '' + Values can be either strings or integers + (which will be added to the config file verbatimly) + or lists thereof + (which will be translated to multiple + lines with the same configuration key). + Boolean values are translated to "Yes" or "No". + The default contains some reasonable + configuration to yield an operational system. + ''; + + str1 = lib.types.addCheck str (s: s!=""); # non-empty string + int1 = lib.types.addCheck int (i: i>0); # positive integer + + configAttrType = + # Options in HylaFAX configuration files can be + # booleans, strings, integers, or list thereof + # representing multiple config directives with the same key. + # This type definition resolves all + # those types into a list of strings. + let + inherit (lib.types) attrsOf coercedTo listOf; + innerType = coercedTo bool (x: if x then "Yes" else "No") + (coercedTo int (toString) str); + in + attrsOf (coercedTo innerType lib.singleton (listOf innerType)); + + cfg = config.services.hylafax; + + modemConfigOptions = { name, config, ... }: { + options = { + name = mkOption { + type = str1; + example = "ttyS1"; + description = '' + Name of modem device, + will be searched for in <filename>/dev</filename>. + ''; + }; + type = mkOption { + type = str1; + example = "cirrus"; + description = '' + Name of modem configuration file, + will be searched for in <filename>config</filename> + in the spooling area directory. + ''; + }; + config = mkOption { + type = configAttrType; + example = { + AreaCode = "49"; + LocalCode = "30"; + FAXNumber = "123456"; + LocalIdentifier = "LostInBerlin"; + }; + description = '' + Attribute set of values for the given modem. + ${commonDescr} + Options defined here override options in + <option>commonModemConfig</option> for this modem. + ''; + }; + }; + config.name = mkDefault name; + config.config.Include = [ "config/${config.type}" ]; + }; + + defaultConfig = + let + inherit (config.security) wrapperDir; + inherit (config.services.mail.sendmailSetuidWrapper) program; + mkIfDefault = cond: value: mkIf cond (mkDefault value); + noWrapper = config.services.mail.sendmailSetuidWrapper==null; + # If a sendmail setuid wrapper exists, + # we add the path to the default configuration file. + # Otherwise, we use `false` to provoke + # an error if hylafax tries to use it. + c.sendmailPath = mkMerge [ + (mkIfDefault noWrapper ''${pkgs.coreutils}/bin/false'') + (mkIfDefault (!noWrapper) ''${wrapperDir}/${program}'') + ]; + importDefaultConfig = file: + lib.attrsets.mapAttrs + (lib.trivial.const mkDefault) + (import file { inherit pkgs; }); + c.commonModemConfig = importDefaultConfig ./modem-default.nix; + c.faxqConfig = importDefaultConfig ./faxq-default.nix; + c.hfaxdConfig = importDefaultConfig ./hfaxd-default.nix; + in + c; + + localConfig = + let + c.hfaxdConfig.UserAccessFile = cfg.userAccessFile; + c.faxqConfig = lib.attrsets.mapAttrs + (lib.trivial.const (v: mkIf (v!=null) v)) + { + AreaCode = cfg.areaCode; + CountryCode = cfg.countryCode; + LongDistancePrefix = cfg.longDistancePrefix; + InternationalPrefix = cfg.internationalPrefix; + }; + c.commonModemConfig = c.faxqConfig; + in + c; + +in + + +{ + + + options.services.hylafax = { + + enable = mkEnableOption ''HylaFAX server''; + + autostart = mkOption { + type = bool; + default = true; + example = false; + description = '' + Autostart the HylaFAX queue manager at system start. + If this is <literal>false</literal>, the queue manager + will still be started if there are pending + jobs or if a user tries to connect to it. + ''; + }; + + countryCode = mkOption { + type = nullOr str1; + default = null; + example = "49"; + description = ''Country code for server and all modems.''; + }; + + areaCode = mkOption { + type = nullOr str1; + default = null; + example = "30"; + description = ''Area code for server and all modems.''; + }; + + longDistancePrefix = mkOption { + type = nullOr str; + default = null; + example = "0"; + description = ''Long distance prefix for server and all modems.''; + }; + + internationalPrefix = mkOption { + type = nullOr str; + default = null; + example = "00"; + description = ''International prefix for server and all modems.''; + }; + + spoolAreaPath = mkOption { + type = path; + default = "/var/spool/fax"; + description = '' + The spooling area will be created/maintained + at the location given here. + ''; + }; + + userAccessFile = mkOption { + type = path; + default = "/etc/hosts.hfaxd"; + description = '' + The <filename>hosts.hfaxd</filename> + file entry in the spooling area + will be symlinked to the location given here. + This file must exist and be + readable only by the <literal>uucp</literal> user. + See hosts.hfaxd(5) for details. + This configuration permits access for all users: + <literal> + environment.etc."hosts.hfaxd" = { + mode = "0600"; + user = "uucp"; + text = ".*"; + }; + </literal> + Note that host-based access can be controlled with + <option>config.systemd.sockets.hylafax-hfaxd.listenStreams</option>; + by default, only 127.0.0.1 is permitted to connect. + ''; + }; + + sendmailPath = mkOption { + type = path; + example = literalExample "''${pkgs.postfix}/bin/sendmail"; + # '' ; # fix vim + description = '' + Path to <filename>sendmail</filename> program. + The default uses the local sendmail wrapper + (see <option>config.services.mail.sendmailSetuidWrapper</option>), + otherwise the <filename>false</filename> + binary to cause an error if used. + ''; + }; + + hfaxdConfig = mkOption { + type = configAttrType; + example.RecvqProtection = "0400"; + description = '' + Attribute set of lines for the global + hfaxd config file <filename>etc/hfaxd.conf</filename>. + ${commonDescr} + ''; + }; + + faxqConfig = mkOption { + type = configAttrType; + example = { + InternationalPrefix = "00"; + LongDistancePrefix = "0"; + }; + description = '' + Attribute set of lines for the global + faxq config file <filename>etc/config</filename>. + ${commonDescr} + ''; + }; + + commonModemConfig = mkOption { + type = configAttrType; + example = { + InternationalPrefix = "00"; + LongDistancePrefix = "0"; + }; + description = '' + Attribute set of default values for + modem config files <filename>etc/config.*</filename>. + ${commonDescr} + Think twice before changing + paths of fax-processing scripts. + ''; + }; + + modems = mkOption { + type = loaOf (submodule [ modemConfigOptions ]); + default = {}; + example.ttyS1 = { + type = "cirrus"; + config = { + FAXNumber = "123456"; + LocalIdentifier = "Smith"; + }; + }; + description = '' + Description of installed modems. + At least on modem must be defined + to enable the HylaFAX server. + ''; + }; + + spoolExtraInit = mkOption { + type = lines; + default = ""; + example = ''chmod 0755 . # everyone may read my faxes''; + description = '' + Additional shell code that is executed within the + spooling area directory right after its setup. + ''; + }; + + faxcron.enable.spoolInit = mkEnableOption '' + Purge old files from the spooling area with + <filename>faxcron</filename> + each time the spooling area is initialized. + ''; + faxcron.enable.frequency = mkOption { + type = nullOr str1; + default = null; + example = "daily"; + description = '' + Purge old files from the spooling area with + <filename>faxcron</filename> with the given frequency + (see systemd.time(7)). + ''; + }; + faxcron.infoDays = mkOption { + type = int1; + default = 30; + description = '' + Set the expiration time for data in the + remote machine information directory in days. + ''; + }; + faxcron.logDays = mkOption { + type = int1; + default = 30; + description = '' + Set the expiration time for + session trace log files in days. + ''; + }; + faxcron.rcvDays = mkOption { + type = int1; + default = 7; + description = '' + Set the expiration time for files in + the received facsimile queue in days. + ''; + }; + + faxqclean.enable.spoolInit = mkEnableOption '' + Purge old files from the spooling area with + <filename>faxqclean</filename> + each time the spooling area is initialized. + ''; + faxqclean.enable.frequency = mkOption { + type = nullOr str1; + default = null; + example = "daily"; + description = '' + Purge old files from the spooling area with + <filename>faxcron</filename> with the given frequency + (see systemd.time(7)). + ''; + }; + faxqclean.archiving = mkOption { + type = enum [ "never" "as-flagged" "always" ]; + default = "as-flagged"; + example = "always"; + description = '' + Enable or suppress job archiving: + <literal>never</literal> disables job archiving, + <literal>as-flagged</literal> archives jobs that + have been flagged for archiving by sendfax, + <literal>always</literal> forces archiving of all jobs. + See also sendfax(1) and faxqclean(8). + ''; + }; + faxqclean.doneqMinutes = mkOption { + type = int1; + default = 15; + example = literalExample ''24*60''; + description = '' + Set the job + age threshold (in minutes) that controls how long + jobs may reside in the doneq directory. + ''; + }; + faxqclean.docqMinutes = mkOption { + type = int1; + default = 60; + example = literalExample ''24*60''; + description = '' + Set the document + age threshold (in minutes) that controls how long + unreferenced files may reside in the docq directory. + ''; + }; + + }; + + + config.services.hylafax = + mkIf + (config.services.hylafax.enable) + (mkMerge [ defaultConfig localConfig ]) + ; + +} diff --git a/nixos/modules/services/networking/hylafax/spool.sh b/nixos/modules/services/networking/hylafax/spool.sh new file mode 100755 index 000000000000..31e930e8c597 --- /dev/null +++ b/nixos/modules/services/networking/hylafax/spool.sh @@ -0,0 +1,111 @@ +#! @shell@ -e + +# The following lines create/update the HylaFAX spool directory: +# Subdirectories/files with persistent data are kept, +# other directories/files are removed/recreated, +# mostly from the template spool +# directory in the HylaFAX package. + +# This block explains how the spool area is +# derived from the spool template in the HylaFAX package: +# +# + capital letter: directory; file otherwise +# + P/p: persistent directory +# + F/f: directory with symlinks per entry +# + T/t: temporary data +# + S/s: single symlink into package +# | +# | + u: change ownership to uucp:uucp +# | + U: ..also change access mode to user-only +# | | +# archive P U +# bin S +# client T u (client connection info) +# config S +# COPYRIGHT s +# dev T u (maybe some FIFOs) +# docq P U +# doneq P U +# etc F contains customized config files! +# etc/hosts.hfaxd f +# etc/xferfaxlog f +# info P u (database of called devices) +# log P u (communication logs) +# pollq P U +# recvq P u +# sendq P U +# status T u (modem status info files) +# tmp T U + + +shopt -s dotglob # if bash sees "*", it also includes dot files +lnsym () { ln --symbol "$@" ; } +lnsymfrc () { ln --symbolic --force "$@" ; } +cprd () { cp --remove-destination "$@" ; } +update () { install --owner=@faxuser@ --group=@faxgroup@ "$@" ; } + + +## create/update spooling area + +update --mode=0750 -d "@spoolAreaPath@" +cd "@spoolAreaPath@" + +persist=(archive docq doneq info log pollq recvq sendq) + +# remove entries that don't belong here +touch dummy # ensure "*" resolves to something +for k in * +do + keep=0 + for j in "${persist[@]}" xferfaxlog clientlog faxcron.lastrun + do + if test "$k" == "$j" + then + keep=1 + break + fi + done + if test "$keep" == "0" + then + rm --recursive "$k" + fi +done + +# create persistent data directories (unless they exist already) +update --mode=0700 -d "${persist[@]}" +chmod 0755 info log recvq + +# create ``xferfaxlog``, ``faxcron.lastrun``, ``clientlog`` +touch clientlog faxcron.lastrun xferfaxlog +chown @faxuser@:@faxgroup@ clientlog faxcron.lastrun xferfaxlog + +# create symlinks for frozen directories/files +lnsym --target-directory=. "@hylafax@"/spool/{COPYRIGHT,bin,config} + +# create empty temporary directories +update --mode=0700 -d client dev status +update -d tmp + + +## create and fill etc + +install -d "@spoolAreaPath@/etc" +cd "@spoolAreaPath@/etc" + +# create symlinks to all files in template's etc +lnsym --target-directory=. "@hylafax@/spool/etc"/* + +# set LOCKDIR in setup.cache +sed --regexp-extended 's|^(UUCP_LOCKDIR=).*$|\1'"'@lockPath@'|g" --in-place setup.cache + +# etc/{xferfaxlog,lastrun} are stored in the spool root +lnsymfrc --target-directory=. ../xferfaxlog +lnsymfrc --no-target-directory ../faxcron.lastrun lastrun + +# etc/hosts.hfaxd is provided by the NixOS configuration +lnsymfrc --no-target-directory "@userAccessFile@" hosts.hfaxd + +# etc/config and etc/config.${DEVID} must be copied: +# hfaxd reads these file after locking itself up in a chroot +cprd --no-target-directory "@globalConfigPath@" config +cprd --target-directory=. "@modemConfigPath@"/* diff --git a/nixos/modules/services/networking/hylafax/systemd.nix b/nixos/modules/services/networking/hylafax/systemd.nix new file mode 100644 index 000000000000..91d9c1a37da6 --- /dev/null +++ b/nixos/modules/services/networking/hylafax/systemd.nix @@ -0,0 +1,249 @@ +{ config, lib, pkgs, ... }: + + +let + + inherit (lib) mkIf mkMerge; + inherit (lib) concatStringsSep optionalString; + + cfg = config.services.hylafax; + mapModems = lib.flip map (lib.attrValues cfg.modems); + + mkConfigFile = name: conf: + # creates hylafax config file, + # makes sure "Include" is listed *first* + let + mkLines = conf: + (lib.concatLists + (lib.flip lib.mapAttrsToList conf + (k: map (v: ''${k}: ${v}'') + ))); + include = mkLines { Include = conf.Include or []; }; + other = mkLines ( conf // { Include = []; } ); + in + pkgs.writeText ''hylafax-config${name}'' + (concatStringsSep "\n" (include ++ other)); + + globalConfigPath = mkConfigFile "" cfg.faxqConfig; + + modemConfigPath = + let + mkModemConfigFile = { config, name, ... }: + mkConfigFile ''.${name}'' + (cfg.commonModemConfig // config); + mkLine = { name, type, ... }@modem: '' + # check if modem config file exists: + test -f "${pkgs.hylafaxplus}/spool/config/${type}" + ln \ + --symbolic \ + --no-target-directory \ + "${mkModemConfigFile modem}" \ + "$out/config.${name}" + ''; + in + pkgs.runCommand "hylafax-config-modems" {} + ''mkdir --parents "$out/" ${concatStringsSep "\n" (mapModems mkLine)}''; + + setupSpoolScript = pkgs.substituteAll { + name = "hylafax-setup-spool.sh"; + src = ./spool.sh; + isExecutable = true; + inherit (pkgs.stdenv) shell; + hylafax = pkgs.hylafaxplus; + faxuser = "uucp"; + faxgroup = "uucp"; + lockPath = "/var/lock"; + inherit globalConfigPath modemConfigPath; + inherit (cfg) sendmailPath spoolAreaPath userAccessFile; + }; + + waitFaxqScript = pkgs.substituteAll { + # This script checks the modems status files + # and waits until all modems report readiness. + name = "hylafax-faxq-wait-start.sh"; + src = ./faxq-wait.sh; + isExecutable = true; + timeoutSec = toString 10; + inherit (pkgs.stdenv) shell; + inherit (cfg) spoolAreaPath; + }; + + sockets."hylafax-hfaxd" = { + description = "HylaFAX server socket"; + documentation = [ "man:hfaxd(8)" ]; + wantedBy = [ "multi-user.target" ]; + listenStreams = [ "127.0.0.1:4559" ]; + socketConfig.FreeBind = true; + socketConfig.Accept = true; + }; + + paths."hylafax-faxq" = { + description = "HylaFAX queue manager sendq watch"; + documentation = [ "man:faxq(8)" "man:sendq(5)" ]; + wantedBy = [ "multi-user.target" ]; + pathConfig.PathExistsGlob = [ ''${cfg.spoolAreaPath}/sendq/q*'' ]; + }; + + timers = mkMerge [ + ( + mkIf (cfg.faxcron.enable.frequency!=null) + { "hylafax-faxcron".timerConfig.Persistent = true; } + ) + ( + mkIf (cfg.faxqclean.enable.frequency!=null) + { "hylafax-faxqclean".timerConfig.Persistent = true; } + ) + ]; + + hardenService = + # Add some common systemd service hardening settings, + # but allow each service (here) to override + # settings by explicitely setting those to `null`. + # More hardening would be nice but makes + # customizing hylafax setups very difficult. + # If at all, it should only be added along + # with some options to customize it. + let + hardening = { + PrivateDevices = true; # breaks /dev/tty... + PrivateNetwork = true; + PrivateTmp = true; + ProtectControlGroups = true; + #ProtectHome = true; # breaks custom spool dirs + ProtectKernelModules = true; + ProtectKernelTunables = true; + #ProtectSystem = "strict"; # breaks custom spool dirs + RestrictNamespaces = true; + RestrictRealtime = true; + }; + filter = key: value: (value != null) || ! (lib.hasAttr key hardening); + apply = service: lib.filterAttrs filter (hardening // (service.serviceConfig or {})); + in + service: service // { serviceConfig = apply service; }; + + services."hylafax-spool" = { + description = "HylaFAX spool area preparation"; + documentation = [ "man:hylafax-server(4)" ]; + script = '' + ${setupSpoolScript} + cd "${cfg.spoolAreaPath}" + ${cfg.spoolExtraInit} + if ! test -f "${cfg.spoolAreaPath}/etc/hosts.hfaxd" + then + echo hosts.hfaxd is missing + exit 1 + fi + ''; + serviceConfig.ExecStop = ''${setupSpoolScript}''; + serviceConfig.RemainAfterExit = true; + serviceConfig.Type = "oneshot"; + unitConfig.RequiresMountsFor = [ cfg.spoolAreaPath ]; + }; + + services."hylafax-faxq" = { + description = "HylaFAX queue manager"; + documentation = [ "man:faxq(8)" ]; + requires = [ "hylafax-spool.service" ]; + after = [ "hylafax-spool.service" ]; + wants = mapModems ( { name, ... }: ''hylafax-faxgetty@${name}.service'' ); + wantedBy = mkIf cfg.autostart [ "multi-user.target" ]; + serviceConfig.Type = "forking"; + serviceConfig.ExecStart = ''${pkgs.hylafaxplus}/spool/bin/faxq -q "${cfg.spoolAreaPath}"''; + # This delays the "readiness" of this service until + # all modems are initialized (or a timeout is reached). + # Otherwise, sending a fax with the fax service + # stopped will always yield a failed send attempt: + # The fax service is started when the job is created with + # `sendfax`, but modems need some time to initialize. + serviceConfig.ExecStartPost = [ ''${waitFaxqScript}'' ]; + # faxquit fails if the pipe is already gone + # (e.g. the service is already stopping) + serviceConfig.ExecStop = ''-${pkgs.hylafaxplus}/spool/bin/faxquit -q "${cfg.spoolAreaPath}"''; + # disable some systemd hardening settings + serviceConfig.PrivateDevices = null; + serviceConfig.RestrictRealtime = null; + }; + + services."hylafax-hfaxd@" = { + description = "HylaFAX server"; + documentation = [ "man:hfaxd(8)" ]; + after = [ "hylafax-faxq.service" ]; + requires = [ "hylafax-faxq.service" ]; + serviceConfig.StandardInput = "socket"; + serviceConfig.StandardOutput = "socket"; + serviceConfig.ExecStart = ''${pkgs.hylafaxplus}/spool/bin/hfaxd -q "${cfg.spoolAreaPath}" -d -I''; + unitConfig.RequiresMountsFor = [ cfg.userAccessFile ]; + # disable some systemd hardening settings + serviceConfig.PrivateDevices = null; + serviceConfig.PrivateNetwork = null; + }; + + services."hylafax-faxcron" = rec { + description = "HylaFAX spool area maintenance"; + documentation = [ "man:faxcron(8)" ]; + after = [ "hylafax-spool.service" ]; + requires = [ "hylafax-spool.service" ]; + wantedBy = mkIf cfg.faxcron.enable.spoolInit requires; + startAt = mkIf (cfg.faxcron.enable.frequency!=null) cfg.faxcron.enable.frequency; + serviceConfig.ExecStart = concatStringsSep " " [ + ''${pkgs.hylafaxplus}/spool/bin/faxcron'' + ''-q "${cfg.spoolAreaPath}"'' + ''-info ${toString cfg.faxcron.infoDays}'' + ''-log ${toString cfg.faxcron.logDays}'' + ''-rcv ${toString cfg.faxcron.rcvDays}'' + ]; + }; + + services."hylafax-faxqclean" = rec { + description = "HylaFAX spool area queue cleaner"; + documentation = [ "man:faxqclean(8)" ]; + after = [ "hylafax-spool.service" ]; + requires = [ "hylafax-spool.service" ]; + wantedBy = mkIf cfg.faxqclean.enable.spoolInit requires; + startAt = mkIf (cfg.faxqclean.enable.frequency!=null) cfg.faxqclean.enable.frequency; + serviceConfig.ExecStart = concatStringsSep " " [ + ''${pkgs.hylafaxplus}/spool/bin/faxqclean'' + ''-q "${cfg.spoolAreaPath}"'' + ''-v'' + (optionalString (cfg.faxqclean.archiving!="never") ''-a'') + (optionalString (cfg.faxqclean.archiving=="always") ''-A'') + ''-j ${toString (cfg.faxqclean.doneqMinutes*60)}'' + ''-d ${toString (cfg.faxqclean.docqMinutes*60)}'' + ]; + }; + + mkFaxgettyService = { name, ... }: + lib.nameValuePair ''hylafax-faxgetty@${name}'' rec { + description = "HylaFAX faxgetty for %I"; + documentation = [ "man:faxgetty(8)" ]; + bindsTo = [ "dev-%i.device" ]; + requires = [ "hylafax-spool.service" ]; + after = bindsTo ++ requires; + before = [ "hylafax-faxq.service" "getty.target" ]; + unitConfig.StopWhenUnneeded = true; + unitConfig.AssertFileNotEmpty = ''${cfg.spoolAreaPath}/etc/config.%I''; + serviceConfig.UtmpIdentifier = "%I"; + serviceConfig.TTYPath = "/dev/%I"; + serviceConfig.Restart = "always"; + serviceConfig.KillMode = "process"; + serviceConfig.IgnoreSIGPIPE = false; + serviceConfig.ExecStart = ''-${pkgs.hylafaxplus}/spool/bin/faxgetty -q "${cfg.spoolAreaPath}" /dev/%I''; + # faxquit fails if the pipe is already gone + # (e.g. the service is already stopping) + serviceConfig.ExecStop = ''-${pkgs.hylafaxplus}/spool/bin/faxquit -q "${cfg.spoolAreaPath}" %I''; + # disable some systemd hardening settings + serviceConfig.PrivateDevices = null; + serviceConfig.RestrictRealtime = null; + }; + + modemServices = + lib.listToAttrs (mapModems mkFaxgettyService); + +in + +{ + config.systemd = mkIf cfg.enable { + inherit sockets timers paths; + services = lib.mapAttrs (lib.const hardenService) (services // modemServices); + }; +} diff --git a/nixos/modules/services/networking/i2pd.nix b/nixos/modules/services/networking/i2pd.nix index 3afafaf3fed5..0e9b354cfcaf 100644 --- a/nixos/modules/services/networking/i2pd.nix +++ b/nixos/modules/services/networking/i2pd.nix @@ -8,6 +8,17 @@ let homeDir = "/var/lib/i2pd"; + strOpt = k: v: k + " = " + v; + boolOpt = k: v: k + " = " + boolToString v; + intOpt = k: v: k + " = " + toString v; + lstOpt = k: xs: k + " = " + concatStringsSep "," xs; + optionalNullString = o: s: optional (! isNull s) (strOpt o s); + optionalNullBool = o: b: optional (! isNull b) (boolOpt o b); + optionalNullInt = o: i: optional (! isNull i) (intOpt o i); + optionalEmptyList = o: l: optional ([] != l) (lstOpt o l); + + mkEnableTrueOption = name: mkEnableOption name // { default = true; }; + mkEndpointOpt = name: addr: port: { enable = mkEnableOption name; name = mkOption { @@ -18,42 +29,54 @@ let address = mkOption { type = types.str; default = addr; - description = "Bind address for ${name} endpoint. Default: " + addr; + description = "Bind address for ${name} endpoint."; }; port = mkOption { type = types.int; default = port; - description = "Bind port for ${name} endoint. Default: " + toString port; + description = "Bind port for ${name} endoint."; }; }; - mkKeyedEndpointOpt = name: addr: port: keyFile: + i2cpOpts = name: { + length = mkOption { + type = types.int; + description = "Guaranteed minimum hops for ${name} tunnels."; + default = 3; + }; + quantity = mkOption { + type = types.int; + description = "Number of simultaneous ${name} tunnels."; + default = 5; + }; + }; + + mkKeyedEndpointOpt = name: addr: port: keyloc: (mkEndpointOpt name addr port) // { keys = mkOption { - type = types.str; - default = ""; + type = with types; nullOr str; + default = keyloc; description = '' File to persist ${lib.toUpper name} keys. ''; }; - }; - - commonTunOpts = let - i2cpOpts = { - length = mkOption { - type = types.int; - description = "Guaranteed minimum hops."; - default = 3; + inbound = i2cpOpts name; + outbound = i2cpOpts name; + latency.min = mkOption { + type = with types; nullOr int; + description = "Min latency for tunnels."; + default = null; }; - quantity = mkOption { - type = types.int; - description = "Number of simultaneous tunnels."; - default = 5; + latency.max = mkOption { + type = with types; nullOr int; + description = "Max latency for tunnels."; + default = null; }; }; - in name: { - outbound = i2cpOpts; - inbound = i2cpOpts; + + commonTunOpts = name: { + outbound = i2cpOpts name; + inbound = i2cpOpts name; crypto.tagsToSend = mkOption { type = types.int; description = "Number of ElGamal/AES tags to send."; @@ -70,94 +93,142 @@ let }; } // mkEndpointOpt name "127.0.0.1" 0; - i2pdConf = pkgs.writeText "i2pd.conf" '' - # DO NOT EDIT -- this file has been generated automatically. - loglevel = ${cfg.logLevel} - - ipv4 = ${boolToString cfg.enableIPv4} - ipv6 = ${boolToString cfg.enableIPv6} - notransit = ${boolToString cfg.notransit} - floodfill = ${boolToString cfg.floodfill} - netid = ${toString cfg.netid} - ${if isNull cfg.bandwidth then "" else "bandwidth = ${toString cfg.bandwidth}" } - ${if isNull cfg.port then "" else "port = ${toString cfg.port}"} - - [limits] - transittunnels = ${toString cfg.limits.transittunnels} - - [upnp] - enabled = ${boolToString cfg.upnp.enable} - name = ${cfg.upnp.name} - - [precomputation] - elgamal = ${boolToString cfg.precomputation.elgamal} - - [reseed] - verify = ${boolToString cfg.reseed.verify} - file = ${cfg.reseed.file} - urls = ${builtins.concatStringsSep "," cfg.reseed.urls} - - [addressbook] - defaulturl = ${cfg.addressbook.defaulturl} - subscriptions = ${builtins.concatStringsSep "," cfg.addressbook.subscriptions} - - ${flip concatMapStrings + sec = name: "\n[" + name + "]"; + notice = "# DO NOT EDIT -- this file has been generated automatically."; + i2pdConf = let + opts = [ + notice + (strOpt "loglevel" cfg.logLevel) + (boolOpt "logclftime" cfg.logCLFTime) + (boolOpt "ipv4" cfg.enableIPv4) + (boolOpt "ipv6" cfg.enableIPv6) + (boolOpt "notransit" cfg.notransit) + (boolOpt "floodfill" cfg.floodfill) + (intOpt "netid" cfg.netid) + ] ++ (optionalNullInt "bandwidth" cfg.bandwidth) + ++ (optionalNullInt "port" cfg.port) + ++ (optionalNullString "family" cfg.family) + ++ (optionalNullString "datadir" cfg.dataDir) + ++ (optionalNullInt "share" cfg.share) + ++ (optionalNullBool "ssu" cfg.ssu) + ++ (optionalNullBool "ntcp" cfg.ntcp) + ++ (optionalNullString "ntcpproxy" cfg.ntcpProxy) + ++ (optionalNullString "ifname" cfg.ifname) + ++ (optionalNullString "ifname4" cfg.ifname4) + ++ (optionalNullString "ifname6" cfg.ifname6) + ++ [ + (sec "limits") + (intOpt "transittunnels" cfg.limits.transittunnels) + (intOpt "coresize" cfg.limits.coreSize) + (intOpt "openfiles" cfg.limits.openFiles) + (intOpt "ntcphard" cfg.limits.ntcpHard) + (intOpt "ntcpsoft" cfg.limits.ntcpSoft) + (intOpt "ntcpthreads" cfg.limits.ntcpThreads) + (sec "upnp") + (boolOpt "enabled" cfg.upnp.enable) + (sec "precomputation") + (boolOpt "elgamal" cfg.precomputation.elgamal) + (sec "reseed") + (boolOpt "verify" cfg.reseed.verify) + ] ++ (optionalNullString "file" cfg.reseed.file) + ++ (optionalEmptyList "urls" cfg.reseed.urls) + ++ (optionalNullString "floodfill" cfg.reseed.floodfill) + ++ (optionalNullString "zipfile" cfg.reseed.zipfile) + ++ (optionalNullString "proxy" cfg.reseed.proxy) + ++ [ + (sec "trust") + (boolOpt "enabled" cfg.trust.enable) + (boolOpt "hidden" cfg.trust.hidden) + ] ++ (optionalEmptyList "routers" cfg.trust.routers) + ++ (optionalNullString "family" cfg.trust.family) + ++ [ + (sec "websockets") + (boolOpt "enabled" cfg.websocket.enable) + (strOpt "address" cfg.websocket.address) + (intOpt "port" cfg.websocket.port) + (sec "exploratory") + (intOpt "inbound.length" cfg.exploratory.inbound.length) + (intOpt "inbound.quantity" cfg.exploratory.inbound.quantity) + (intOpt "outbound.length" cfg.exploratory.outbound.length) + (intOpt "outbound.quantity" cfg.exploratory.outbound.quantity) + (sec "ntcp2") + (boolOpt "enabled" cfg.ntcp2.enable) + (boolOpt "published" cfg.ntcp2.published) + (intOpt "port" cfg.ntcp2.port) + (sec "addressbook") + (strOpt "defaulturl" cfg.addressbook.defaulturl) + ] ++ (optionalEmptyList "subscriptions" cfg.addressbook.subscriptions) + ++ (flip map (collect (proto: proto ? port && proto ? address && proto ? name) cfg.proto) - (proto: '' - [${proto.name}] - enabled = ${boolToString proto.enable} - address = ${proto.address} - port = ${toString proto.port} - ${if proto ? keys then "keys = ${proto.keys}" else ""} - ${if proto ? auth then "auth = ${boolToString proto.auth}" else ""} - ${if proto ? user then "user = ${proto.user}" else ""} - ${if proto ? pass then "pass = ${proto.pass}" else ""} - ${if proto ? outproxy then "outproxy = ${proto.outproxy}" else ""} - ${if proto ? outproxyPort then "outproxyport = ${toString proto.outproxyPort}" else ""} - '') - } - ''; - - i2pdTunnelConf = pkgs.writeText "i2pd-tunnels.conf" '' - # DO NOT EDIT -- this file has been generated automatically. - ${flip concatMapStrings + (proto: let protoOpts = [ + (sec proto.name) + (boolOpt "enabled" proto.enable) + (strOpt "address" proto.address) + (intOpt "port" proto.port) + ] ++ (if proto ? keys then optionalNullString "keys" proto.keys else []) + ++ (if proto ? auth then optionalNullBool "auth" proto.auth else []) + ++ (if proto ? user then optionalNullString "user" proto.user else []) + ++ (if proto ? pass then optionalNullString "pass" proto.pass else []) + ++ (if proto ? strictHeaders then optionalNullBool "strictheaders" proto.strictHeaders else []) + ++ (if proto ? hostname then optionalNullString "hostname" proto.hostname else []) + ++ (if proto ? outproxy then optionalNullString "outproxy" proto.outproxy else []) + ++ (if proto ? outproxyPort then optionalNullInt "outproxyport" proto.outproxyPort else []) + ++ (if proto ? outproxyEnable then optionalNullBool "outproxy.enabled" proto.outproxyEnable else []); + in (concatStringsSep "\n" protoOpts) + )); + in + pkgs.writeText "i2pd.conf" (concatStringsSep "\n" opts); + + tunnelConf = let opts = [ + notice + (flip map (collect (tun: tun ? port && tun ? destination) cfg.outTunnels) - (tun: '' - [${tun.name}] - type = client - destination = ${tun.destination} - destinationport = ${toString tun.destinationPort} - keys = ${tun.keys} - address = ${tun.address} - port = ${toString tun.port} - inbound.length = ${toString tun.inbound.length} - outbound.length = ${toString tun.outbound.length} - inbound.quantity = ${toString tun.inbound.quantity} - outbound.quantity = ${toString tun.outbound.quantity} - crypto.tagsToSend = ${toString tun.crypto.tagsToSend} - '') - } - ${flip concatMapStrings + (tun: let outTunOpts = [ + (sec tun.name) + "type = client" + (intOpt "port" tun.port) + (strOpt "destination" tun.destination) + ] ++ (if tun ? destinationPort then optionalNullInt "destinationport" tun.destinationPort else []) + ++ (if tun ? keys then + optionalNullString "keys" tun.keys else []) + ++ (if tun ? address then + optionalNullString "address" tun.address else []) + ++ (if tun ? inbound.length then + optionalNullInt "inbound.length" tun.inbound.length else []) + ++ (if tun ? inbound.quantity then + optionalNullInt "inbound.quantity" tun.inbound.quantity else []) + ++ (if tun ? outbound.length then + optionalNullInt "outbound.length" tun.outbound.length else []) + ++ (if tun ? outbound.quantity then + optionalNullInt "outbound.quantity" tun.outbound.quantity else []) + ++ (if tun ? crypto.tagsToSend then + optionalNullInt "crypto.tagstosend" tun.crypto.tagsToSend else []); + in concatStringsSep "\n" outTunOpts)) + (flip map (collect (tun: tun ? port && tun ? address) cfg.inTunnels) - (tun: '' - [${tun.name}] - type = server - destination = ${tun.destination} - keys = ${tun.keys} - host = ${tun.address} - port = ${toString tun.port} - inport = ${toString tun.inPort} - accesslist = ${builtins.concatStringsSep "," tun.accessList} - '') - } - ''; + (tun: let inTunOpts = [ + (sec tun.name) + "type = server" + (intOpt "port" tun.port) + (strOpt "host" tun.address) + ] ++ (if tun ? destination then + optionalNullString "destination" tun.destination else []) + ++ (if tun ? keys then + optionalNullString "keys" tun.keys else []) + ++ (if tun ? inPort then + optionalNullInt "inport" tun.inPort else []) + ++ (if tun ? accessList then + optionalEmptyList "accesslist" tun.accessList else []); + in concatStringsSep "\n" inTunOpts))]; + in pkgs.writeText "i2pd-tunnels.conf" opts; i2pdSh = pkgs.writeScriptBin "i2pd" '' #!/bin/sh exec ${pkgs.i2pd}/bin/i2pd \ ${if isNull cfg.address then "" else "--host="+cfg.address} \ + --service \ --conf=${i2pdConf} \ - --tunconf=${i2pdTunnelConf} + --tunconf=${tunnelConf} ''; in @@ -170,9 +241,7 @@ in services.i2pd = { - enable = mkOption { - type = types.bool; - default = false; + enable = mkEnableOption "I2Pd daemon" // { description = '' Enables I2Pd as a running service upon activation. Please read http://i2pd.readthedocs.io/en/latest/ for further @@ -192,6 +261,8 @@ in ''; }; + logCLFTime = mkEnableOption "Full CLF-formatted date and time to log"; + address = mkOption { type = with types; nullOr str; default = null; @@ -200,17 +271,72 @@ in ''; }; - notransit = mkOption { - type = types.bool; - default = false; + family = mkOption { + type = with types; nullOr str; + default = null; + description = '' + Specify a family the router belongs to. + ''; + }; + + dataDir = mkOption { + type = with types; nullOr str; + default = null; + description = '' + Alternative path to storage of i2pd data (RI, keys, peer profiles, ...) + ''; + }; + + share = mkOption { + type = types.int; + default = 100; + description = '' + Limit of transit traffic from max bandwidth in percents. + ''; + }; + + ifname = mkOption { + type = with types; nullOr str; + default = null; + description = '' + Network interface to bind to. + ''; + }; + + ifname4 = mkOption { + type = with types; nullOr str; + default = null; + description = '' + IPv4 interface to bind to. + ''; + }; + + ifname6 = mkOption { + type = with types; nullOr str; + default = null; + description = '' + IPv6 interface to bind to. + ''; + }; + + ntcpProxy = mkOption { + type = with types; nullOr str; + default = null; + description = '' + Proxy URL for NTCP transport. + ''; + }; + + ntcp = mkEnableTrueOption "ntcp"; + ssu = mkEnableTrueOption "ssu"; + + notransit = mkEnableOption "notransit" // { description = '' Tells the router to not accept transit tunnels during startup. ''; }; - floodfill = mkOption { - type = types.bool; - default = false; + floodfill = mkEnableOption "floodfill" // { description = '' If the router is declared to be unreachable and needs introduction nodes. ''; @@ -241,131 +367,178 @@ in ''; }; - enableIPv4 = mkOption { - type = types.bool; - default = true; + enableIPv4 = mkEnableTrueOption "IPv4 connectivity"; + enableIPv6 = mkEnableOption "IPv6 connectivity"; + nat = mkEnableTrueOption "NAT bypass"; + + upnp.enable = mkEnableOption "UPnP service discovery"; + upnp.name = mkOption { + type = types.str; + default = "I2Pd"; description = '' - Enables IPv4 connectivity. Enabled by default. + Name i2pd appears in UPnP forwardings list. ''; }; - enableIPv6 = mkOption { - type = types.bool; - default = false; + precomputation.elgamal = mkEnableTrueOption "Precomputed ElGamal tables" // { description = '' - Enables IPv6 connectivity. Disabled by default. + Whenever to use precomputated tables for ElGamal. + <command>i2pd</command> defaults to <literal>false</literal> + to save 64M of memory (and looses some performance). + + We default to <literal>true</literal> as that is what most + users want anyway. ''; }; - nat = mkOption { - type = types.bool; - default = true; + reseed.verify = mkEnableOption "SU3 signature verification"; + + reseed.file = mkOption { + type = with types; nullOr str; + default = null; description = '' - Assume router is NATed. Enabled by default. + Full path to SU3 file to reseed from. ''; }; - upnp = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Enables UPnP. - ''; - }; + reseed.urls = mkOption { + type = with types; listOf str; + default = []; + description = '' + Reseed URLs. + ''; + }; - name = mkOption { - type = types.str; - default = "I2Pd"; - description = '' - Name i2pd appears in UPnP forwardings list. - ''; - }; + reseed.floodfill = mkOption { + type = with types; nullOr str; + default = null; + description = '' + Path to router info of floodfill to reseed from. + ''; }; - precomputation.elgamal = mkOption { - type = types.bool; - default = true; + reseed.zipfile = mkOption { + type = with types; nullOr str; + default = null; description = '' - Whenever to use precomputated tables for ElGamal. - <command>i2pd</command> defaults to <literal>false</literal> - to save 64M of memory (and looses some performance). + Path to local .zip file to reseed from. + ''; + }; - We default to <literal>true</literal> as that is what most - users want anyway. + reseed.proxy = mkOption { + type = with types; nullOr str; + default = null; + description = '' + URL for reseed proxy, supports http/socks. ''; }; - reseed = { - verify = mkOption { - type = types.bool; - default = false; - description = '' - Request SU3 signature verification - ''; - }; + addressbook.defaulturl = mkOption { + type = types.str; + default = "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt"; + description = '' + AddressBook subscription URL for initial setup + ''; + }; + addressbook.subscriptions = mkOption { + type = with types; listOf str; + default = [ + "http://inr.i2p/export/alive-hosts.txt" + "http://i2p-projekt.i2p/hosts.txt" + "http://stats.i2p/cgi-bin/newhosts.txt" + ]; + description = '' + AddressBook subscription URLs + ''; + }; - file = mkOption { - type = types.str; - default = ""; - description = '' - Full path to SU3 file to reseed from - ''; - }; + trust.enable = mkEnableOption "Explicit trust options"; - urls = mkOption { - type = with types; listOf str; - default = [ - "https://reseed.i2p-project.de/" - "https://i2p.mooo.com/netDb/" - "https://netdb.i2p2.no/" - "https://us.reseed.i2p2.no:444/" - "https://uk.reseed.i2p2.no:444/" - "https://i2p.manas.ca:8443/" - ]; - description = '' - Reseed URLs - ''; - }; + trust.family = mkOption { + type = with types; nullOr str; + default = null; + description = '' + Router Familiy to trust for first hops. + ''; }; - addressbook = { - defaulturl = mkOption { - type = types.str; - default = "http://joajgazyztfssty4w2on5oaqksz6tqoxbduy553y34mf4byv6gpq.b32.i2p/export/alive-hosts.txt"; - description = '' - AddressBook subscription URL for initial setup - ''; - }; - subscriptions = mkOption { - type = with types; listOf str; - default = [ - "http://inr.i2p/export/alive-hosts.txt" - "http://i2p-projekt.i2p/hosts.txt" - "http://stats.i2p/cgi-bin/newhosts.txt" - ]; - description = '' - AddressBook subscription URLs - ''; - }; + trust.routers = mkOption { + type = with types; listOf str; + default = []; + description = '' + Only connect to the listed routers. + ''; + }; + + trust.hidden = mkEnableOption "Router concealment."; + + websocket = mkEndpointOpt "websockets" "127.0.0.1" 7666; + + exploratory.inbound = i2cpOpts "exploratory"; + exploratory.outbound = i2cpOpts "exploratory"; + + ntcp2.enable = mkEnableTrueOption "NTCP2."; + ntcp2.published = mkEnableOption "NTCP2 publication."; + ntcp2.port = mkOption { + type = types.int; + default = 0; + description = '' + Port to listen for incoming NTCP2 connections (0=auto). + ''; }; limits.transittunnels = mkOption { type = types.int; default = 2500; description = '' - Maximum number of active transit sessions + Maximum number of active transit sessions. + ''; + }; + + limits.coreSize = mkOption { + type = types.int; + default = 0; + description = '' + Maximum size of corefile in Kb (0 - use system limit). + ''; + }; + + limits.openFiles = mkOption { + type = types.int; + default = 0; + description = '' + Maximum number of open files (0 - use system default). + ''; + }; + + limits.ntcpHard = mkOption { + type = types.int; + default = 0; + description = '' + Maximum number of active transit sessions. + ''; + }; + + limits.ntcpSoft = mkOption { + type = types.int; + default = 0; + description = '' + Threshold to start probabalistic backoff with ntcp sessions (default: use system limit). + ''; + }; + + limits.ntcpThreads = mkOption { + type = types.int; + default = 1; + description = '' + Maximum number of threads used by NTCP DH worker. ''; }; proto.http = (mkEndpointOpt "http" "127.0.0.1" 7070) // { - auth = mkOption { - type = types.bool; - default = false; - description = '' - Enable authentication for webconsole. - ''; - }; + + auth = mkEnableOption "Webconsole authentication"; + user = mkOption { type = types.str; default = "i2pd"; @@ -373,6 +546,7 @@ in Username for webconsole access ''; }; + pass = mkOption { type = types.str; default = "i2pd"; @@ -380,11 +554,35 @@ in Password for webconsole access. ''; }; + + strictHeaders = mkOption { + type = with types; nullOr bool; + default = null; + description = '' + Enable strict host checking on WebUI. + ''; + }; + + hostname = mkOption { + type = with types; nullOr str; + default = null; + description = '' + Expected hostname for WebUI. + ''; + }; }; - proto.httpProxy = mkKeyedEndpointOpt "httpproxy" "127.0.0.1" 4444 ""; - proto.socksProxy = (mkKeyedEndpointOpt "socksproxy" "127.0.0.1" 4447 "") + proto.httpProxy = (mkKeyedEndpointOpt "httpproxy" "127.0.0.1" 4444 "httpproxy-keys.dat") + // { + outproxy = mkOption { + type = with types; nullOr str; + default = null; + description = "Upstream outproxy bind address."; + }; + }; + proto.socksProxy = (mkKeyedEndpointOpt "socksproxy" "127.0.0.1" 4447 "socksproxy-keys.dat") // { + outproxyEnable = mkEnableOption "SOCKS outproxy"; outproxy = mkOption { type = types.str; default = "127.0.0.1"; @@ -408,8 +606,8 @@ in { name, ... }: { options = { destinationPort = mkOption { - type = types.int; - default = 0; + type = with types; nullOr int; + default = null; description = "Connect to particular port at destination."; }; } // commonTunOpts name; diff --git a/nixos/modules/services/networking/iperf3.nix b/nixos/modules/services/networking/iperf3.nix new file mode 100644 index 000000000000..742404a5692f --- /dev/null +++ b/nixos/modules/services/networking/iperf3.nix @@ -0,0 +1,87 @@ +{ config, lib, pkgs, ... }: with lib; +let + cfg = config.services.iperf3; + + api = { + enable = mkEnableOption "iperf3 network throughput testing server"; + port = mkOption { + type = types.ints.u16; + default = 5201; + description = "Server port to listen on for iperf3 client requsts."; + }; + affinity = mkOption { + type = types.nullOr types.ints.unsigned; + default = null; + description = "CPU affinity for the process."; + }; + bind = mkOption { + type = types.nullOr types.str; + default = null; + description = "Bind to the specific interface associated with the given address."; + }; + verbose = mkOption { + type = types.bool; + default = false; + description = "Give more detailed output."; + }; + forceFlush = mkOption { + type = types.bool; + default = false; + description = "Force flushing output at every interval."; + }; + debug = mkOption { + type = types.bool; + default = false; + description = "Emit debugging output."; + }; + rsaPrivateKey = mkOption { + type = types.nullOr types.path; + default = null; + description = "Path to the RSA private key (not password-protected) used to decrypt authentication credentials from the client."; + }; + authorizedUsersFile = mkOption { + type = types.nullOr types.path; + default = null; + description = "Path to the configuration file containing authorized users credentials to run iperf tests."; + }; + extraFlags = mkOption { + type = types.listOf types.str; + default = [ ]; + description = "Extra flags to pass to iperf3(1)."; + }; + }; + + imp = { + systemd.services.iperf3 = { + description = "iperf3 daemon"; + unitConfig.Documentation = "man:iperf3(1) https://iperf.fr/iperf-doc.php"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + serviceConfig = { + Restart = "on-failure"; + RestartSec = 2; + DynamicUser = true; + PrivateDevices = true; + CapabilityBoundingSet = ""; + NoNewPrivileges = true; + ExecStart = '' + ${pkgs.iperf3}/bin/iperf \ + --server \ + --port ${toString cfg.port} \ + ${optionalString (cfg.affinity != null) "--affinity ${toString cfg.affinity}"} \ + ${optionalString (cfg.bind != null) "--bind ${cfg.bind}"} \ + ${optionalString (cfg.rsaPrivateKey != null) "--rsa-private-key-path ${cfg.rsaPrivateKey}"} \ + ${optionalString (cfg.authorizedUsersFile != null) "--authorized-users-path ${cfg.authorizedUsersFile}"} \ + ${optionalString cfg.verbose "--verbose"} \ + ${optionalString cfg.debug "--debug"} \ + ${optionalString cfg.forceFlush "--forceflush"} \ + ${escapeShellArgs cfg.extraFlags} + ''; + }; + }; + }; +in { + options.services.iperf3 = api; + config = mkIf cfg.enable imp; +} diff --git a/nixos/modules/services/networking/iwd.nix b/nixos/modules/services/networking/iwd.nix index eb03d2e1d632..18ed20e28886 100644 --- a/nixos/modules/services/networking/iwd.nix +++ b/nixos/modules/services/networking/iwd.nix @@ -22,6 +22,8 @@ in { systemd.packages = [ pkgs.iwd ]; + systemd.services.iwd.wantedBy = [ "multi-user.target" ]; + systemd.tmpfiles.rules = [ "d /var/lib/iwd 0700 root root -" ]; diff --git a/nixos/modules/services/networking/miniupnpd.nix b/nixos/modules/services/networking/miniupnpd.nix index 19400edb68f9..ab714a6ac75e 100644 --- a/nixos/modules/services/networking/miniupnpd.nix +++ b/nixos/modules/services/networking/miniupnpd.nix @@ -57,32 +57,12 @@ in }; config = mkIf cfg.enable { - # from miniupnpd/netfilter/iptables_init.sh networking.firewall.extraCommands = '' - iptables -t nat -N MINIUPNPD - iptables -t nat -A PREROUTING -i ${cfg.externalInterface} -j MINIUPNPD - iptables -t mangle -N MINIUPNPD - iptables -t mangle -A PREROUTING -i ${cfg.externalInterface} -j MINIUPNPD - iptables -t filter -N MINIUPNPD - iptables -t filter -A FORWARD -i ${cfg.externalInterface} ! -o ${cfg.externalInterface} -j MINIUPNPD - iptables -t nat -N MINIUPNPD-PCP-PEER - iptables -t nat -A POSTROUTING -o ${cfg.externalInterface} -j MINIUPNPD-PCP-PEER + ${pkgs.bash}/bin/bash -x ${pkgs.miniupnpd}/etc/miniupnpd/iptables_init.sh -i ${cfg.externalInterface} ''; - # from miniupnpd/netfilter/iptables_removeall.sh networking.firewall.extraStopCommands = '' - iptables -t nat -F MINIUPNPD - iptables -t nat -D PREROUTING -i ${cfg.externalInterface} -j MINIUPNPD - iptables -t nat -X MINIUPNPD - iptables -t mangle -F MINIUPNPD - iptables -t mangle -D PREROUTING -i ${cfg.externalInterface} -j MINIUPNPD - iptables -t mangle -X MINIUPNPD - iptables -t filter -F MINIUPNPD - iptables -t filter -D FORWARD -i ${cfg.externalInterface} ! -o ${cfg.externalInterface} -j MINIUPNPD - iptables -t filter -X MINIUPNPD - iptables -t nat -F MINIUPNPD-PCP-PEER - iptables -t nat -D POSTROUTING -o ${cfg.externalInterface} -j MINIUPNPD-PCP-PEER - iptables -t nat -X MINIUPNPD-PCP-PEER + ${pkgs.bash}/bin/bash -x ${pkgs.miniupnpd}/etc/miniupnpd/iptables_removeall.sh -i ${cfg.externalInterface} ''; systemd.services.miniupnpd = { diff --git a/nixos/modules/services/networking/murmur.nix b/nixos/modules/services/networking/murmur.nix index fcc813e6898f..a6e90feff7ea 100644 --- a/nixos/modules/services/networking/murmur.nix +++ b/nixos/modules/services/networking/murmur.nix @@ -50,7 +50,7 @@ in enable = mkOption { type = types.bool; default = false; - description = "If enabled, start the Murmur Service."; + description = "If enabled, start the Murmur Mumble server."; }; autobanAttempts = mkOption { diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix index d5af4648e8f9..2d76e0676b24 100644 --- a/nixos/modules/services/networking/networkmanager.nix +++ b/nixos/modules/services/networking/networkmanager.nix @@ -406,25 +406,25 @@ in { { source = configFile; target = "NetworkManager/NetworkManager.conf"; } - { source = "${networkmanager-openvpn}/etc/NetworkManager/VPN/nm-openvpn-service.name"; + { source = "${networkmanager-openvpn}/lib/NetworkManager/VPN/nm-openvpn-service.name"; target = "NetworkManager/VPN/nm-openvpn-service.name"; } - { source = "${networkmanager-vpnc}/etc/NetworkManager/VPN/nm-vpnc-service.name"; + { source = "${networkmanager-vpnc}/lib/NetworkManager/VPN/nm-vpnc-service.name"; target = "NetworkManager/VPN/nm-vpnc-service.name"; } - { source = "${networkmanager-openconnect}/etc/NetworkManager/VPN/nm-openconnect-service.name"; + { source = "${networkmanager-openconnect}/lib/NetworkManager/VPN/nm-openconnect-service.name"; target = "NetworkManager/VPN/nm-openconnect-service.name"; } - { source = "${networkmanager-fortisslvpn}/etc/NetworkManager/VPN/nm-fortisslvpn-service.name"; + { source = "${networkmanager-fortisslvpn}/lib/NetworkManager/VPN/nm-fortisslvpn-service.name"; target = "NetworkManager/VPN/nm-fortisslvpn-service.name"; } - { source = "${networkmanager-l2tp}/etc/NetworkManager/VPN/nm-l2tp-service.name"; + { source = "${networkmanager-l2tp}/lib/NetworkManager/VPN/nm-l2tp-service.name"; target = "NetworkManager/VPN/nm-l2tp-service.name"; } - { source = "${networkmanager_strongswan}/etc/NetworkManager/VPN/nm-strongswan-service.name"; + { source = "${networkmanager_strongswan}/lib/NetworkManager/VPN/nm-strongswan-service.name"; target = "NetworkManager/VPN/nm-strongswan-service.name"; } - { source = "${networkmanager-iodine}/etc/NetworkManager/VPN/nm-iodine-service.name"; + { source = "${networkmanager-iodine}/lib/NetworkManager/VPN/nm-iodine-service.name"; target = "NetworkManager/VPN/nm-iodine-service.name"; } ] ++ optional (cfg.appendNameservers == [] || cfg.insertNameservers == []) diff --git a/nixos/modules/services/networking/nullidentdmod.nix b/nixos/modules/services/networking/nullidentdmod.nix new file mode 100644 index 000000000000..786b5227dbad --- /dev/null +++ b/nixos/modules/services/networking/nullidentdmod.nix @@ -0,0 +1,34 @@ +{ config, lib, pkgs, ... }: with lib; let + cfg = config.services.nullidentdmod; + +in { + options.services.nullidentdmod = with types; { + enable = mkEnableOption "Enable the nullidentdmod identd daemon"; + + userid = mkOption { + type = nullOr str; + description = "User ID to return. Set to null to return a random string each time."; + default = null; + example = "alice"; + }; + }; + + config = mkIf cfg.enable { + systemd.sockets.nullidentdmod = { + description = "Socket for identd (NullidentdMod)"; + listenStreams = [ "113" ]; + socketConfig.Accept = true; + wantedBy = [ "sockets.target" ]; + }; + + systemd.services."nullidentdmod@" = { + description = "NullidentdMod service"; + serviceConfig = { + DynamicUser = true; + ExecStart = "${pkgs.nullidentdmod}/bin/nullidentdmod${optionalString (cfg.userid != null) " ${cfg.userid}"}"; + StandardInput = "socket"; + StandardOutput = "socket"; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/pptpd.nix b/nixos/modules/services/networking/pptpd.nix index 56a612b91052..d8b9e8f8341a 100644 --- a/nixos/modules/services/networking/pptpd.nix +++ b/nixos/modules/services/networking/pptpd.nix @@ -5,7 +5,7 @@ with lib; { options = { services.pptpd = { - enable = mkEnableOption "Whether pptpd should be run on startup."; + enable = mkEnableOption "pptpd, the Point-to-Point Tunneling Protocol daemon"; serverIp = mkOption { type = types.string; diff --git a/nixos/modules/services/networking/redsocks.nix b/nixos/modules/services/networking/redsocks.nix index a47a78f1005e..8481f9debf39 100644 --- a/nixos/modules/services/networking/redsocks.nix +++ b/nixos/modules/services/networking/redsocks.nix @@ -267,4 +267,6 @@ in "ip46tables -t nat -D OUTPUT -p tcp ${redCond block} -j ${chain} 2>/dev/null || true" ) cfg.redsocks; }; + + meta.maintainers = with lib.maintainers; [ ekleog ]; } diff --git a/nixos/modules/services/networking/shairport-sync.nix b/nixos/modules/services/networking/shairport-sync.nix index 0b87140b0d8d..36ecb74ffc95 100644 --- a/nixos/modules/services/networking/shairport-sync.nix +++ b/nixos/modules/services/networking/shairport-sync.nix @@ -27,7 +27,7 @@ in }; arguments = mkOption { - default = "-v -o pulse"; + default = "-v -d pulse"; description = '' Arguments to pass to the daemon. Defaults to a local pulseaudio server. @@ -72,6 +72,7 @@ in serviceConfig = { User = cfg.user; ExecStart = "${pkgs.shairport-sync}/bin/shairport-sync ${cfg.arguments}"; + RuntimeDirectory = "shairport-sync"; }; }; diff --git a/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix b/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix index b16d299917fe..d4f7e95f859f 100644 --- a/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix +++ b/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix @@ -248,6 +248,14 @@ in { </itemizedlist> ''; + ppk_id = mkOptionalStrParam '' + String identifying the Postquantum Preshared Key (PPK) to be used. + ''; + + ppk_required = mkYesNoParam no '' + Whether a Postquantum Preshared Key (PPK) is required for this connection. + ''; + keyingtries = mkIntParam 1 '' Number of retransmission sequences to perform during initial connect. Instead of giving up initiation after the first retransmission @@ -922,6 +930,36 @@ in { <literal>0xffffffff</literal>. ''; + set_mark_in = mkStrParam "0/0x00000000" '' + Netfilter mark applied to packets after the inbound IPsec SA processed + them. This way it's not necessary to mark packets via Netfilter before + decryption or right afterwards to match policies or process them + differently (e.g. via policy routing). + + An additional mask may be appended to the mark, separated by + <literal>/</literal>. The default mask if omitted is 0xffffffff. The + special value <literal>%same</literal> uses the value (but not the mask) + from <option>mark_in</option> as mark value, which can be fixed, + <literal>%unique</literal> or <literal>%unique-dir</literal>. + + Setting marks in XFRM input requires Linux 4.19 or higher. + ''; + + set_mark_out = mkStrParam "0/0x00000000" '' + Netfilter mark applied to packets after the outbound IPsec SA processed + them. This allows processing ESP packets differently than the original + traffic (e.g. via policy routing). + + An additional mask may be appended to the mark, separated by + <literal>/</literal>. The default mask if omitted is 0xffffffff. The + special value <literal>%same</literal> uses the value (but not the mask) + from <option>mark_out</option> as mark value, which can be fixed, + <literal>%unique_</literal> or <literal>%unique-dir</literal>. + + Setting marks in XFRM output is supported since Linux 4.14. Setting a + mask requires at least Linux 4.19. + ''; + tfc_padding = mkParamOfType (with lib.types; either int (enum ["mtu"])) 0 '' Pads ESP packets with additional data to have a consistent ESP packet size for improved Traffic Flow Confidentiality. The padding defines the @@ -946,6 +984,33 @@ in { supported, but the installation does not fail otherwise. ''; + copy_df = mkYesNoParam yes '' + Whether to copy the DF bit to the outer IPv4 header in tunnel mode. This + effectively disables Path MTU discovery (PMTUD). Controlling this + behavior is not supported by all kernel interfaces. + ''; + + copy_ecn = mkYesNoParam yes '' + Whether to copy the ECN (Explicit Congestion Notification) header field + to/from the outer IP header in tunnel mode. Controlling this behavior is + not supported by all kernel interfaces. + ''; + + copy_dscp = mkEnumParam [ "out" "in" "yes" "no" ] "out" '' + Whether to copy the DSCP (Differentiated Services Field Codepoint) + header field to/from the outer IP header in tunnel mode. The value + <literal>out</literal> only copies the field from the inner to the outer + header, the value <literal>in</literal> does the opposite and only + copies the field from the outer to the inner header when decapsulating, + the value <literal>yes</literal> copies the field in both directions, + and the value <literal>no</literal> disables copying the field + altogether. Setting this to <literal>yes</literal> or + <literal>in</literal> could allow an attacker to adversely affect other + traffic at the receiver, which is why the default is + <literal>out</literal>. Controlling this behavior is not supported by + all kernel interfaces. + ''; + start_action = mkEnumParam ["none" "trap" "start"] "none" '' Action to perform after loading the configuration. <itemizedlist> @@ -1060,6 +1125,24 @@ in { defined in a unique section having the <literal>ike</literal> prefix. ''; + ppk = mkPrefixedAttrsOfParams { + secret = mkOptionalStrParam '' + Value of the PPK. It may either be an ASCII string, a hex encoded string + if it has a <literal>0x</literal> prefix or a Base64 encoded string if + it has a <literal>0s</literal> prefix in its value. Should have at least + 256 bits of entropy for 128-bit security. + ''; + + id = mkPrefixedAttrsOfParam (mkOptionalStrParam "") '' + PPK identity the PPK belongs to. Multiple unique identities may be + specified, each having an <literal>id</literal> prefix, if a secret is + shared between multiple peers. + ''; + } '' + Postquantum Preshared Key (PPK) section for a specific secret. Each PPK is + defined in a unique section having the <literal>ppk</literal> prefix. + ''; + private = mkPrefixedAttrsOfParams { file = mkOptionalStrParam '' File name in the private folder for which this passphrase should be used. diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix index c610b3b66606..fd31b2a67687 100644 --- a/nixos/modules/services/networking/syncthing.nix +++ b/nixos/modules/services/networking/syncthing.nix @@ -16,6 +16,14 @@ in { available on http://127.0.0.1:8384/. ''; + guiAddress = mkOption { + type = types.str; + default = "127.0.0.1:8384"; + description = '' + Address to serve the GUI. + ''; + }; + systemService = mkOption { type = types.bool; default = true; @@ -23,7 +31,7 @@ in { }; user = mkOption { - type = types.string; + type = types.str; default = defaultUser; description = '' Syncthing will be run under this user (user will be created if it doesn't exist. @@ -32,7 +40,7 @@ in { }; group = mkOption { - type = types.string; + type = types.str; default = "nogroup"; description = '' Syncthing will be run under this group (group will not be created if it doesn't exist. @@ -41,7 +49,7 @@ in { }; all_proxy = mkOption { - type = types.nullOr types.string; + type = with types; nullOr str; default = null; example = "socks5://address.com:1234"; description = '' @@ -132,7 +140,12 @@ in { User = cfg.user; Group = cfg.group; PermissionsStartOnly = true; - ExecStart = "${cfg.package}/bin/syncthing -no-browser -home=${cfg.dataDir}"; + ExecStart = '' + ${cfg.package}/bin/syncthing \ + -no-browser \ + -gui-address=${cfg.guiAddress} \ + -home=${cfg.dataDir} + ''; }; }; diff --git a/nixos/modules/services/networking/teamspeak3.nix b/nixos/modules/services/networking/teamspeak3.nix index 3703921ff703..410d650b1f64 100644 --- a/nixos/modules/services/networking/teamspeak3.nix +++ b/nixos/modules/services/networking/teamspeak3.nix @@ -124,7 +124,7 @@ in dbsqlpath=${ts3}/lib/teamspeak/sql/ logpath=${cfg.logPath} \ voice_ip=${cfg.voiceIP} default_voice_port=${toString cfg.defaultVoicePort} \ filetransfer_ip=${cfg.fileTransferIP} filetransfer_port=${toString cfg.fileTransferPort} \ - query_ip=${cfg.queryIP} query_port=${toString cfg.queryPort} + query_ip=${cfg.queryIP} query_port=${toString cfg.queryPort} license_accepted=1 ''; WorkingDirectory = cfg.dataDir; User = user; diff --git a/nixos/modules/services/networking/tinc.nix b/nixos/modules/services/networking/tinc.nix index 35cdddc590b8..3379efd1afce 100644 --- a/nixos/modules/services/networking/tinc.nix +++ b/nixos/modules/services/networking/tinc.nix @@ -148,14 +148,6 @@ in } )); - networking.interfaces = flip mapAttrs' cfg.networks (network: data: nameValuePair - ("tinc.${network}") - ({ - virtual = true; - virtualType = "${data.interfaceType}"; - }) - ); - systemd.services = flip mapAttrs' cfg.networks (network: data: nameValuePair ("tinc.${network}") ({ diff --git a/nixos/modules/services/networking/xl2tpd.nix b/nixos/modules/services/networking/xl2tpd.nix index 46111a76af80..d0a3ed7bb5e0 100644 --- a/nixos/modules/services/networking/xl2tpd.nix +++ b/nixos/modules/services/networking/xl2tpd.nix @@ -5,7 +5,7 @@ with lib; { options = { services.xl2tpd = { - enable = mkEnableOption "Whether xl2tpd should be run on startup."; + enable = mkEnableOption "xl2tpd, the Layer 2 Tunnelling Protocol Daemon"; serverIp = mkOption { type = types.string; diff --git a/nixos/modules/services/networking/xrdp.nix b/nixos/modules/services/networking/xrdp.nix index 61f22a366a02..9ed3025e47d4 100644 --- a/nixos/modules/services/networking/xrdp.nix +++ b/nixos/modules/services/networking/xrdp.nix @@ -36,7 +36,7 @@ in services.xrdp = { - enable = mkEnableOption "Whether xrdp should be run on startup."; + enable = mkEnableOption "xrdp, the Remote Desktop Protocol server"; package = mkOption { type = types.package; diff --git a/nixos/modules/services/networking/zeronet.nix b/nixos/modules/services/networking/zeronet.nix index 2377cb2c8f11..8b60799891ca 100644 --- a/nixos/modules/services/networking/zeronet.nix +++ b/nixos/modules/services/networking/zeronet.nix @@ -12,6 +12,8 @@ let log_dir = ${cfg.logDir} '' + lib.optionalString (cfg.port != null) '' ui_port = ${toString cfg.port} + '' + lib.optionalString (cfg.torAlways) '' + tor = always '' + cfg.extraConfig; }; in with lib; { @@ -35,13 +37,19 @@ in with lib; { port = mkOption { type = types.nullOr types.int; default = null; - example = 15441; - description = "Optional zeronet port."; + example = 43110; + description = "Optional zeronet web UI port."; }; tor = mkOption { type = types.bool; default = false; + description = "Use TOR for zeronet traffic where possible."; + }; + + torAlways = mkOption { + type = types.bool; + default = false; description = "Use TOR for all zeronet traffic."; }; @@ -60,9 +68,13 @@ in with lib; { services.tor = mkIf cfg.tor { enable = true; controlPort = 9051; - extraConfig = "CookieAuthentication 1"; + extraConfig = '' + CacheDirectoryGroupReadable 1 + CookieAuthentication 1 + CookieAuthFileGroupReadable 1 + ''; }; - + systemd.services.zeronet = { description = "zeronet"; after = [ "network.target" (optionalString cfg.tor "tor.service") ]; diff --git a/nixos/modules/services/networking/znc.nix b/nixos/modules/services/networking/znc.nix deleted file mode 100644 index f817db2ad000..000000000000 --- a/nixos/modules/services/networking/znc.nix +++ /dev/null @@ -1,431 +0,0 @@ -{ config, lib, pkgs, ...}: - -with lib; - -let - cfg = config.services.znc; - - defaultUser = "znc"; # Default user to own process. - - # Default user and pass: - # un=znc - # pw=nixospass - - defaultUserName = "znc"; - defaultPassBlock = " - <Pass password> - Method = sha256 - Hash = e2ce303c7ea75c571d80d8540a8699b46535be6a085be3414947d638e48d9e93 - Salt = l5Xryew4g*!oa(ECfX2o - </Pass> - "; - - modules = pkgs.buildEnv { - name = "znc-modules"; - paths = cfg.modulePackages; - }; - - # Keep znc.conf in nix store, then symlink or copy into `dataDir`, depending on `mutable`. - mkZncConf = confOpts: '' - Version = 1.6.3 - ${concatMapStrings (n: "LoadModule = ${n}\n") confOpts.modules} - - <Listener l> - Port = ${toString confOpts.port} - IPv4 = true - IPv6 = true - SSL = ${boolToString confOpts.useSSL} - ${lib.optionalString (confOpts.uriPrefix != null) "URIPrefix = ${confOpts.uriPrefix}"} - </Listener> - - <User ${confOpts.userName}> - ${confOpts.passBlock} - Admin = true - Nick = ${confOpts.nick} - AltNick = ${confOpts.nick}_ - Ident = ${confOpts.nick} - RealName = ${confOpts.nick} - ${concatMapStrings (n: "LoadModule = ${n}\n") confOpts.userModules} - - ${ lib.concatStringsSep "\n" (lib.mapAttrsToList (name: net: '' - <Network ${name}> - ${concatMapStrings (m: "LoadModule = ${m}\n") net.modules} - Server = ${net.server} ${lib.optionalString net.useSSL "+"}${toString net.port} ${net.password} - ${concatMapStrings (c: "<Chan #${c}>\n</Chan>\n") net.channels} - ${lib.optionalString net.hasBitlbeeControlChannel '' - <Chan &bitlbee> - </Chan> - ''} - ${net.extraConf} - </Network> - '') confOpts.networks) } - </User> - ${confOpts.extraZncConf} - ''; - - zncConfFile = pkgs.writeTextFile { - name = "znc.conf"; - text = if cfg.zncConf != "" - then cfg.zncConf - else mkZncConf cfg.confOptions; - }; - - networkOpts = { ... }: { - options = { - server = mkOption { - type = types.str; - example = "chat.freenode.net"; - description = '' - IRC server address. - ''; - }; - - port = mkOption { - type = types.int; - default = 6697; - example = 6697; - description = '' - IRC server port. - ''; - }; - - userName = mkOption { - default = ""; - example = "johntron"; - type = types.string; - description = '' - A nick identity specific to the IRC server. - ''; - }; - - password = mkOption { - type = types.str; - default = ""; - description = '' - IRC server password, such as for a Slack gateway. - ''; - }; - - useSSL = mkOption { - type = types.bool; - default = true; - description = '' - Whether to use SSL to connect to the IRC server. - ''; - }; - - modulePackages = mkOption { - type = types.listOf types.package; - default = []; - example = [ "pkgs.zncModules.push" "pkgs.zncModules.fish" ]; - description = '' - External ZNC modules to build. - ''; - }; - - modules = mkOption { - type = types.listOf types.str; - default = [ "simple_away" ]; - example = literalExample "[ simple_away sasl ]"; - description = '' - ZNC modules to load. - ''; - }; - - channels = mkOption { - type = types.listOf types.str; - default = []; - example = [ "nixos" ]; - description = '' - IRC channels to join. - ''; - }; - - hasBitlbeeControlChannel = mkOption { - type = types.bool; - default = false; - description = '' - Whether to add the special Bitlbee operations channel. - ''; - }; - - extraConf = mkOption { - default = ""; - type = types.lines; - example = '' - Encoding = ^UTF-8 - FloodBurst = 4 - FloodRate = 1.00 - IRCConnectEnabled = true - Ident = johntron - JoinDelay = 0 - Nick = johntron - ''; - description = '' - Extra config for the network. - ''; - }; - }; - }; - -in - -{ - - ###### Interface - - options = { - services.znc = { - enable = mkOption { - default = false; - type = types.bool; - description = '' - Enable a ZNC service for a user. - ''; - }; - - user = mkOption { - default = "znc"; - example = "john"; - type = types.string; - description = '' - The name of an existing user account to use to own the ZNC server process. - If not specified, a default user will be created to own the process. - ''; - }; - - group = mkOption { - default = ""; - example = "users"; - type = types.string; - description = '' - Group to own the ZNCserver process. - ''; - }; - - dataDir = mkOption { - default = "/var/lib/znc/"; - example = "/home/john/.znc/"; - type = types.path; - description = '' - The data directory. Used for configuration files and modules. - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = false; - description = '' - Whether to open ports in the firewall for ZNC. - ''; - }; - - zncConf = mkOption { - default = ""; - example = "See: http://wiki.znc.in/Configuration"; - type = types.lines; - description = '' - Config file as generated with `znc --makeconf` to use for the whole ZNC configuration. - If specified, `confOptions` will be ignored, and this value, as-is, will be used. - If left empty, a conf file with default values will be used. - ''; - }; - - confOptions = { - modules = mkOption { - type = types.listOf types.str; - default = [ "webadmin" "adminlog" ]; - example = [ "partyline" "webadmin" "adminlog" "log" ]; - description = '' - A list of modules to include in the `znc.conf` file. - ''; - }; - - userModules = mkOption { - type = types.listOf types.str; - default = [ "chansaver" "controlpanel" ]; - example = [ "chansaver" "controlpanel" "fish" "push" ]; - description = '' - A list of user modules to include in the `znc.conf` file. - ''; - }; - - userName = mkOption { - default = defaultUserName; - example = "johntron"; - type = types.string; - description = '' - The user name used to log in to the ZNC web admin interface. - ''; - }; - - networks = mkOption { - default = { }; - type = with types; attrsOf (submodule networkOpts); - description = '' - IRC networks to connect the user to. - ''; - example = { - "freenode" = { - server = "chat.freenode.net"; - port = 6697; - useSSL = true; - modules = [ "simple_away" ]; - }; - }; - }; - - nick = mkOption { - default = "znc-user"; - example = "john"; - type = types.string; - description = '' - The IRC nick. - ''; - }; - - passBlock = mkOption { - example = defaultPassBlock; - type = types.string; - description = '' - Generate with `nix-shell -p znc --command "znc --makepass"`. - This is the password used to log in to the ZNC web admin interface. - ''; - }; - - port = mkOption { - default = 5000; - example = 5000; - type = types.int; - description = '' - Specifies the port on which to listen. - ''; - }; - - useSSL = mkOption { - default = true; - type = types.bool; - description = '' - Indicates whether the ZNC server should use SSL when listening on the specified port. A self-signed certificate will be generated. - ''; - }; - - uriPrefix = mkOption { - type = types.nullOr types.str; - default = null; - example = "/znc/"; - description = '' - An optional URI prefix for the ZNC web interface. Can be - used to make ZNC available behind a reverse proxy. - ''; - }; - - extraZncConf = mkOption { - default = ""; - type = types.lines; - description = '' - Extra config to `znc.conf` file. - ''; - }; - }; - - modulePackages = mkOption { - type = types.listOf types.package; - default = [ ]; - example = literalExample "[ pkgs.zncModules.fish pkgs.zncModules.push ]"; - description = '' - A list of global znc module packages to add to znc. - ''; - }; - - mutable = mkOption { - default = true; - type = types.bool; - description = '' - Indicates whether to allow the contents of the `dataDir` directory to be changed - by the user at run-time. - If true, modifications to the ZNC configuration after its initial creation are not - overwritten by a NixOS system rebuild. - If false, the ZNC configuration is rebuilt by every system rebuild. - If the user wants to manage the ZNC service using the web admin interface, this value - should be set to true. - ''; - }; - - extraFlags = mkOption { - default = [ ]; - example = [ "--debug" ]; - type = types.listOf types.str; - description = '' - Extra flags to use when executing znc command. - ''; - }; - }; - }; - - - ###### Implementation - - config = mkIf cfg.enable { - - networking.firewall = mkIf cfg.openFirewall { - allowedTCPPorts = [ cfg.confOptions.port ]; - }; - - systemd.services.znc = { - description = "ZNC Server"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.service" ]; - serviceConfig = { - User = cfg.user; - Group = cfg.group; - Restart = "always"; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID"; - }; - preStart = '' - ${pkgs.coreutils}/bin/mkdir -p ${cfg.dataDir}/configs - - # If mutable, regenerate conf file every time. - ${optionalString (!cfg.mutable) '' - ${pkgs.coreutils}/bin/echo "znc is set to be system-managed. Now deleting old znc.conf file to be regenerated." - ${pkgs.coreutils}/bin/rm -f ${cfg.dataDir}/configs/znc.conf - ''} - - # Ensure essential files exist. - if [[ ! -f ${cfg.dataDir}/configs/znc.conf ]]; then - ${pkgs.coreutils}/bin/echo "No znc.conf file found in ${cfg.dataDir}. Creating one now." - ${pkgs.coreutils}/bin/cp --no-clobber ${zncConfFile} ${cfg.dataDir}/configs/znc.conf - ${pkgs.coreutils}/bin/chmod u+rw ${cfg.dataDir}/configs/znc.conf - ${pkgs.coreutils}/bin/chown ${cfg.user} ${cfg.dataDir}/configs/znc.conf - fi - - if [[ ! -f ${cfg.dataDir}/znc.pem ]]; then - ${pkgs.coreutils}/bin/echo "No znc.pem file found in ${cfg.dataDir}. Creating one now." - ${pkgs.znc}/bin/znc --makepem --datadir ${cfg.dataDir} - fi - - # Symlink modules - rm ${cfg.dataDir}/modules || true - ln -fs ${modules}/lib/znc ${cfg.dataDir}/modules - ''; - script = "${pkgs.znc}/bin/znc --foreground --datadir ${cfg.dataDir} ${toString cfg.extraFlags}"; - }; - - users.users = optional (cfg.user == defaultUser) - { name = defaultUser; - description = "ZNC server daemon owner"; - group = defaultUser; - uid = config.ids.uids.znc; - home = cfg.dataDir; - createHome = true; - }; - - users.groups = optional (cfg.user == defaultUser) - { name = defaultUser; - gid = config.ids.gids.znc; - members = [ defaultUser ]; - }; - - }; -} diff --git a/nixos/modules/services/networking/znc/default.nix b/nixos/modules/services/networking/znc/default.nix new file mode 100644 index 000000000000..bce5b15a19ec --- /dev/null +++ b/nixos/modules/services/networking/znc/default.nix @@ -0,0 +1,306 @@ +{ config, lib, pkgs, ...}: + +with lib; + +let + + cfg = config.services.znc; + + defaultUser = "znc"; + + modules = pkgs.buildEnv { + name = "znc-modules"; + paths = cfg.modulePackages; + }; + + listenerPorts = concatMap (l: optional (l ? Port) l.Port) + (attrValues (cfg.config.Listener or {})); + + # Converts the config option to a string + semanticString = let + + sortedAttrs = set: sort (l: r: + if l == "extraConfig" then false # Always put extraConfig last + else if isAttrs set.${l} == isAttrs set.${r} then l < r + else isAttrs set.${r} # Attrsets should be last, makes for a nice config + # This last case occurs when any side (but not both) is an attrset + # The order of these is correct when the attrset is on the right + # which we're just returning + ) (attrNames set); + + # Specifies an attrset that encodes the value according to its type + encode = name: value: { + null = []; + bool = [ "${name} = ${boolToString value}" ]; + int = [ "${name} = ${toString value}" ]; + + # extraConfig should be inserted verbatim + string = [ (if name == "extraConfig" then value else "${name} = ${value}") ]; + + # Values like `Foo = [ "bar" "baz" ];` should be transformed into + # Foo=bar + # Foo=baz + list = concatMap (encode name) value; + + # Values like `Foo = { bar = { Baz = "baz"; Qux = "qux"; Florps = null; }; };` should be transmed into + # <Foo bar> + # Baz=baz + # Qux=qux + # </Foo> + set = concatMap (subname: [ + "<${name} ${subname}>" + ] ++ map (line: "\t${line}") (toLines value.${subname}) ++ [ + "</${name}>" + ]) (filter (v: v != null) (attrNames value)); + + }.${builtins.typeOf value}; + + # One level "above" encode, acts upon a set and uses encode on each name,value pair + toLines = set: concatMap (name: encode name set.${name}) (sortedAttrs set); + + in + concatStringsSep "\n" (toLines cfg.config); + + semanticTypes = with types; rec { + zncAtom = nullOr (either (either int bool) str); + zncAttr = attrsOf (nullOr zncConf); + zncAll = either (either zncAtom (listOf zncAtom)) zncAttr; + zncConf = attrsOf (zncAll // { + # Since this is a recursive type and the description by default contains + # the description of its subtypes, infinite recursion would occur without + # explicitly breaking this cycle + description = "znc values (null, atoms (str, int, bool), list of atoms, or attrsets of znc values)"; + }); + }; + +in + +{ + + imports = [ ./options.nix ]; + + options = { + services.znc = { + enable = mkEnableOption "ZNC"; + + user = mkOption { + default = "znc"; + example = "john"; + type = types.str; + description = '' + The name of an existing user account to use to own the ZNC server + process. If not specified, a default user will be created. + ''; + }; + + group = mkOption { + default = defaultUser; + example = "users"; + type = types.str; + description = '' + Group to own the ZNC process. + ''; + }; + + dataDir = mkOption { + default = "/var/lib/znc/"; + example = "/home/john/.znc/"; + type = types.path; + description = '' + The state directory for ZNC. The config and the modules will be linked + to from this directory as well. + ''; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = '' + Whether to open ports in the firewall for ZNC. Does work with + ports for listeners specified in + <option>services.znc.config.Listener</option>. + ''; + }; + + config = mkOption { + type = semanticTypes.zncConf; + default = {}; + example = literalExample '' + { + LoadModule = [ "webadmin" "adminlog" ]; + User.paul = { + Admin = true; + Nick = "paul"; + AltNick = "paul1"; + LoadModule = [ "chansaver" "controlpanel" ]; + Network.freenode = { + Server = "chat.freenode.net +6697"; + LoadModule = [ "simple_away" ]; + Chan = { + "#nixos" = { Detached = false; }; + "##linux" = { Disabled = true; }; + }; + }; + Pass.password = { + Method = "sha256"; + Hash = "e2ce303c7ea75c571d80d8540a8699b46535be6a085be3414947d638e48d9e93"; + Salt = "l5Xryew4g*!oa(ECfX2o"; + }; + }; + } + ''; + description = '' + Configuration for ZNC, see + <literal>https://wiki.znc.in/Configuration</literal> for details. The + Nix value declared here will be translated directly to the xml-like + format ZNC expects. This is much more flexible than the legacy options + under <option>services.znc.confOptions.*</option>, but also can't do + any type checking. + </para> + <para> + You can use <command>nix-instantiate --eval --strict '<nixpkgs/nixos>' -A config.services.znc.config</command> + to view the current value. By default it contains a listener for port + 5000 with SSL enabled. + </para> + <para> + Nix attributes called <literal>extraConfig</literal> will be inserted + verbatim into the resulting config file. + </para> + <para> + If <option>services.znc.useLegacyConfig</option> is turned on, the + option values in <option>services.znc.confOptions.*</option> will be + gracefully be applied to this option. + </para> + <para> + If you intend to update the configuration through this option, be sure + to enable <option>services.znc.mutable</option>, otherwise none of the + changes here will be applied after the initial deploy. + ''; + }; + + configFile = mkOption { + type = types.path; + example = "~/.znc/configs/znc.conf"; + description = '' + Configuration file for ZNC. It is recommended to use the + <option>config</option> option instead. + </para> + <para> + Setting this option will override any auto-generated config file + through the <option>confOptions</option> or <option>config</option> + options. + ''; + }; + + modulePackages = mkOption { + type = types.listOf types.package; + default = [ ]; + example = literalExample "[ pkgs.zncModules.fish pkgs.zncModules.push ]"; + description = '' + A list of global znc module packages to add to znc. + ''; + }; + + mutable = mkOption { + default = true; # TODO: Default to true when config is set, make sure to not delete the old config if present + type = types.bool; + description = '' + Indicates whether to allow the contents of the + <literal>dataDir</literal> directory to be changed by the user at + run-time. + </para> + <para> + If enabled, modifications to the ZNC configuration after its initial + creation are not overwritten by a NixOS rebuild. If disabled, the + ZNC configuration is rebuilt on every NixOS rebuild. + </para> + <para> + If the user wants to manage the ZNC service using the web admin + interface, this option should be enabled. + ''; + }; + + extraFlags = mkOption { + default = [ ]; + example = [ "--debug" ]; + type = types.listOf types.str; + description = '' + Extra arguments to use for executing znc. + ''; + }; + }; + }; + + + ###### Implementation + + config = mkIf cfg.enable { + + services.znc = { + configFile = mkDefault (pkgs.writeText "znc-generated.conf" semanticString); + config = { + Version = (builtins.parseDrvName pkgs.znc.name).version; + Listener.l.Port = mkDefault 5000; + Listener.l.SSL = mkDefault true; + }; + }; + + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall listenerPorts; + + systemd.services.znc = { + description = "ZNC Server"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + serviceConfig = { + User = cfg.user; + Group = cfg.group; + Restart = "always"; + ExecStart = "${pkgs.znc}/bin/znc --foreground --datadir ${cfg.dataDir} ${escapeShellArgs cfg.extraFlags}"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID"; + }; + preStart = '' + mkdir -p ${cfg.dataDir}/configs + + # If mutable, regenerate conf file every time. + ${optionalString (!cfg.mutable) '' + echo "znc is set to be system-managed. Now deleting old znc.conf file to be regenerated." + rm -f ${cfg.dataDir}/configs/znc.conf + ''} + + # Ensure essential files exist. + if [[ ! -f ${cfg.dataDir}/configs/znc.conf ]]; then + echo "No znc.conf file found in ${cfg.dataDir}. Creating one now." + cp --no-clobber ${cfg.configFile} ${cfg.dataDir}/configs/znc.conf + chmod u+rw ${cfg.dataDir}/configs/znc.conf + chown ${cfg.user} ${cfg.dataDir}/configs/znc.conf + fi + + if [[ ! -f ${cfg.dataDir}/znc.pem ]]; then + echo "No znc.pem file found in ${cfg.dataDir}. Creating one now." + ${pkgs.znc}/bin/znc --makepem --datadir ${cfg.dataDir} + fi + + # Symlink modules + rm ${cfg.dataDir}/modules || true + ln -fs ${modules}/lib/znc ${cfg.dataDir}/modules + ''; + }; + + users.users = optional (cfg.user == defaultUser) + { name = defaultUser; + description = "ZNC server daemon owner"; + group = defaultUser; + uid = config.ids.uids.znc; + home = cfg.dataDir; + createHome = true; + }; + + users.groups = optional (cfg.user == defaultUser) + { name = defaultUser; + gid = config.ids.gids.znc; + members = [ defaultUser ]; + }; + + }; +} diff --git a/nixos/modules/services/networking/znc/options.nix b/nixos/modules/services/networking/znc/options.nix new file mode 100644 index 000000000000..048dbd738630 --- /dev/null +++ b/nixos/modules/services/networking/znc/options.nix @@ -0,0 +1,270 @@ +{ lib, config, ... }: + +with lib; + +let + + cfg = config.services.znc; + + networkOpts = { + options = { + + server = mkOption { + type = types.str; + example = "chat.freenode.net"; + description = '' + IRC server address. + ''; + }; + + port = mkOption { + type = types.ints.u16; + default = 6697; + description = '' + IRC server port. + ''; + }; + + password = mkOption { + type = types.str; + default = ""; + description = '' + IRC server password, such as for a Slack gateway. + ''; + }; + + useSSL = mkOption { + type = types.bool; + default = true; + description = '' + Whether to use SSL to connect to the IRC server. + ''; + }; + + modules = mkOption { + type = types.listOf types.str; + default = [ "simple_away" ]; + example = literalExample "[ simple_away sasl ]"; + description = '' + ZNC network modules to load. + ''; + }; + + channels = mkOption { + type = types.listOf types.str; + default = []; + example = [ "nixos" ]; + description = '' + IRC channels to join. + ''; + }; + + hasBitlbeeControlChannel = mkOption { + type = types.bool; + default = false; + description = '' + Whether to add the special Bitlbee operations channel. + ''; + }; + + extraConf = mkOption { + default = ""; + type = types.lines; + example = '' + Encoding = ^UTF-8 + FloodBurst = 4 + FloodRate = 1.00 + IRCConnectEnabled = true + Ident = johntron + JoinDelay = 0 + Nick = johntron + ''; + description = '' + Extra config for the network. Consider using + <option>services.znc.config</option> instead. + ''; + }; + }; + }; + +in + +{ + + options = { + services.znc = { + + useLegacyConfig = mkOption { + default = true; + type = types.bool; + description = '' + Whether to propagate the legacy options under + <option>services.znc.confOptions.*</option> to the znc config. If this + is turned on, the znc config will contain a user with the default name + "znc", global modules "webadmin" and "adminlog" will be enabled by + default, and more, all controlled through the + <option>services.znc.confOptions.*</option> options. + You can use <command>nix-instantiate --eval --strict '<nixpkgs/nixos>' -A config.services.znc.config</command> + to view the current value of the config. + </para> + <para> + In any case, if you need more flexibility, + <option>services.znc.config</option> can be used to override/add to + all of the legacy options. + ''; + }; + + confOptions = { + modules = mkOption { + type = types.listOf types.str; + default = [ "webadmin" "adminlog" ]; + example = [ "partyline" "webadmin" "adminlog" "log" ]; + description = '' + A list of modules to include in the `znc.conf` file. + ''; + }; + + userModules = mkOption { + type = types.listOf types.str; + default = [ "chansaver" "controlpanel" ]; + example = [ "chansaver" "controlpanel" "fish" "push" ]; + description = '' + A list of user modules to include in the `znc.conf` file. + ''; + }; + + userName = mkOption { + default = "znc"; + example = "johntron"; + type = types.str; + description = '' + The user name used to log in to the ZNC web admin interface. + ''; + }; + + networks = mkOption { + default = { }; + type = with types; attrsOf (submodule networkOpts); + description = '' + IRC networks to connect the user to. + ''; + example = literalExample '' + { + "freenode" = { + server = "chat.freenode.net"; + port = 6697; + useSSL = true; + modules = [ "simple_away" ]; + }; + }; + ''; + }; + + nick = mkOption { + default = "znc-user"; + example = "john"; + type = types.str; + description = '' + The IRC nick. + ''; + }; + + passBlock = mkOption { + example = literalExample '' + <Pass password> + Method = sha256 + Hash = e2ce303c7ea75c571d80d8540a8699b46535be6a085be3414947d638e48d9e93 + Salt = l5Xryew4g*!oa(ECfX2o + </Pass> + ''; + type = types.str; + description = '' + Generate with `nix-shell -p znc --command "znc --makepass"`. + This is the password used to log in to the ZNC web admin interface. + You can also set this through + <option>services.znc.config.User.<username>.Pass.Method</option> + and co. + ''; + }; + + port = mkOption { + default = 5000; + type = types.int; + description = '' + Specifies the port on which to listen. + ''; + }; + + useSSL = mkOption { + default = true; + type = types.bool; + description = '' + Indicates whether the ZNC server should use SSL when listening on + the specified port. A self-signed certificate will be generated. + ''; + }; + + uriPrefix = mkOption { + type = types.nullOr types.str; + default = null; + example = "/znc/"; + description = '' + An optional URI prefix for the ZNC web interface. Can be + used to make ZNC available behind a reverse proxy. + ''; + }; + + extraZncConf = mkOption { + default = ""; + type = types.lines; + description = '' + Extra config to `znc.conf` file. + ''; + }; + }; + + }; + }; + + config = mkIf cfg.useLegacyConfig { + + services.znc.config = let + c = cfg.confOptions; + # defaults here should override defaults set in the non-legacy part + mkDefault = mkOverride 900; + in { + LoadModule = mkDefault c.modules; + Listener.l = { + Port = mkDefault c.port; + IPv4 = mkDefault true; + IPv6 = mkDefault true; + SSL = mkDefault c.useSSL; + URIPrefix = c.uriPrefix; + }; + User.${c.userName} = { + Admin = mkDefault true; + Nick = mkDefault c.nick; + AltNick = mkDefault "${c.nick}_"; + Ident = mkDefault c.nick; + RealName = mkDefault c.nick; + LoadModule = mkDefault c.userModules; + Network = mapAttrs (name: net: { + LoadModule = mkDefault net.modules; + Server = mkDefault "${net.server} ${optionalString net.useSSL "+"}${toString net.port} ${net.password}"; + Chan = optionalAttrs net.hasBitlbeeControlChannel { "&bitlbee" = mkDefault {}; } // + listToAttrs (map (n: nameValuePair "#${n}" (mkDefault {})) net.channels); + extraConfig = if net.extraConf == "" then mkDefault null else net.extraConf; + }) c.networks; + extraConfig = [ c.passBlock ]; + }; + extraConfig = optional (c.extraZncConf != "") c.extraZncConf; + }; + }; + + imports = [ + (mkRemovedOptionModule ["services" "znc" "zncConf"] '' + Instead of `services.znc.zncConf = "... foo ...";`, use + `services.znc.configFile = pkgs.writeText "znc.conf" "... foo ...";`. + '') + ]; +} diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix index dbf18ec1d114..1031d6f3d7e2 100644 --- a/nixos/modules/services/printing/cupsd.nix +++ b/nixos/modules/services/printing/cupsd.nix @@ -250,7 +250,7 @@ in drivers = mkOption { type = types.listOf types.path; default = []; - example = literalExample "[ pkgs.gutenprint pkgs.hplip pkgs.splix ]"; + example = literalExample "with pkgs; [ gutenprint hplip splix cups-googlecloudprint ]"; description = '' CUPS drivers to use. Drivers provided by CUPS, cups-filters, Ghostscript and Samba are added unconditionally. If this list contains diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix index 9ad0095252de..04b433f8f2bf 100644 --- a/nixos/modules/services/security/clamav.nix +++ b/nixos/modules/services/security/clamav.nix @@ -95,7 +95,7 @@ in environment.etc."clamav/freshclam.conf".source = freshclamConfigFile; environment.etc."clamav/clamd.conf".source = clamdConfigFile; - systemd.services.clamav-daemon = optionalAttrs cfg.daemon.enable { + systemd.services.clamav-daemon = mkIf cfg.daemon.enable { description = "ClamAV daemon (clamd)"; after = optional cfg.updater.enable "clamav-freshclam.service"; requires = optional cfg.updater.enable "clamav-freshclam.service"; @@ -116,7 +116,7 @@ in }; }; - systemd.timers.clamav-freshclam = optionalAttrs cfg.updater.enable { + systemd.timers.clamav-freshclam = mkIf cfg.updater.enable { description = "Timer for ClamAV virus database updater (freshclam)"; wantedBy = [ "timers.target" ]; timerConfig = { @@ -125,7 +125,7 @@ in }; }; - systemd.services.clamav-freshclam = optionalAttrs cfg.updater.enable { + systemd.services.clamav-freshclam = mkIf cfg.updater.enable { description = "ClamAV virus database updater (freshclam)"; restartTriggers = [ freshclamConfigFile ]; @@ -137,6 +137,7 @@ in serviceConfig = { Type = "oneshot"; ExecStart = "${pkg}/bin/freshclam"; + SuccessExitStatus = "1"; # if databases are up to date PrivateTmp = "yes"; PrivateDevices = "yes"; }; diff --git a/nixos/modules/services/security/munge.nix b/nixos/modules/services/security/munge.nix index 5bca15833544..fda864f2c30a 100644 --- a/nixos/modules/services/security/munge.nix +++ b/nixos/modules/services/security/munge.nix @@ -53,8 +53,6 @@ in chmod 0700 ${cfg.password} mkdir -p /var/lib/munge -m 0711 chown -R munge:munge /var/lib/munge - mkdir -p /var/log/munge -m 0700 - chown -R munge:munge /var/log/munge mkdir -p /run/munge -m 0755 chown -R munge:munge /run/munge ''; diff --git a/nixos/modules/services/security/sks.nix b/nixos/modules/services/security/sks.nix index 62308428f326..9f0261038d5b 100644 --- a/nixos/modules/services/security/sks.nix +++ b/nixos/modules/services/security/sks.nix @@ -3,78 +3,112 @@ with lib; let - cfg = config.services.sks; - sksPkg = cfg.package; -in - -{ +in { + meta.maintainers = with maintainers; [ primeos calbrecht jcumming ]; options = { services.sks = { - enable = mkEnableOption "sks"; + enable = mkEnableOption '' + SKS (synchronizing key server for OpenPGP) and start the database + server. You need to create "''${dataDir}/dump/*.gpg" for the initial + import''; package = mkOption { default = pkgs.sks; defaultText = "pkgs.sks"; type = types.package; - description = " - Which sks derivation to use. - "; + description = "Which SKS derivation to use."; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/db/sks"; + example = "/var/lib/sks"; + # TODO: The default might change to "/var/lib/sks" as this is more + # common. There's also https://github.com/NixOS/nixpkgs/issues/26256 + # and "/var/db" is not FHS compliant (seems to come from BSD). + description = '' + Data directory (-basedir) for SKS, where the database and all + configuration files are located (e.g. KDB, PTree, membership and + sksconf). + ''; }; hkpAddress = mkOption { default = [ "127.0.0.1" "::1" ]; type = types.listOf types.str; - description = " - Wich ip addresses the sks-keyserver is listening on. - "; + description = '' + Domain names, IPv4 and/or IPv6 addresses to listen on for HKP + requests. + ''; }; hkpPort = mkOption { default = 11371; - type = types.int; - description = " - Which port the sks-keyserver is listening on. - "; + type = types.ints.u16; + description = "HKP port to listen on."; + }; + + webroot = mkOption { + type = types.nullOr types.path; + default = "${sksPkg.webSamples}/OpenPKG"; + defaultText = "\${pkgs.sks.webSamples}/OpenPKG"; + description = '' + Source directory (will be symlinked, if not null) for the files the + built-in webserver should serve. SKS (''${pkgs.sks.webSamples}) + provides the following examples: "HTML5", "OpenPKG", and "XHTML+ES". + The index file can be named index.html, index.htm, index.xhtm, or + index.xhtml. Files with the extensions .css, .es, .js, .jpg, .jpeg, + .png, or .gif are supported. Subdirectories and filenames with + anything other than alphanumeric characters and the '.' character + will be ignored. + ''; }; }; }; config = mkIf cfg.enable { - environment.systemPackages = [ sksPkg ]; - - users.users.sks = { - createHome = true; - home = "/var/db/sks"; - isSystemUser = true; - shell = "${pkgs.coreutils}/bin/true"; + users = { + users.sks = { + isSystemUser = true; + description = "SKS user"; + home = cfg.dataDir; + createHome = true; + group = "sks"; + useDefaultShell = true; + packages = [ sksPkg pkgs.db ]; + }; + groups.sks = { }; }; systemd.services = let hkpAddress = "'" + (builtins.concatStringsSep " " cfg.hkpAddress) + "'" ; hkpPort = builtins.toString cfg.hkpPort; - home = config.users.users.sks.home; - user = config.users.users.sks.name; in { - sks-keyserver = { + "sks-db" = { + description = "SKS database server"; + after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; preStart = '' - mkdir -p ${home}/dump - ${pkgs.sks}/bin/sks build ${home}/dump/*.gpg -n 10 -cache 100 || true #*/ - ${pkgs.sks}/bin/sks cleandb || true - ${pkgs.sks}/bin/sks pbuild -cache 20 -ptree_cache 70 || true + ${lib.optionalString (cfg.webroot != null) + "ln -sfT \"${cfg.webroot}\" web"} + mkdir -p dump + ${sksPkg}/bin/sks build dump/*.gpg -n 10 -cache 100 || true #*/ + ${sksPkg}/bin/sks cleandb || true + ${sksPkg}/bin/sks pbuild -cache 20 -ptree_cache 70 || true ''; serviceConfig = { - WorkingDirectory = home; - User = user; + WorkingDirectory = "~"; + User = "sks"; + Group = "sks"; Restart = "always"; - ExecStart = "${pkgs.sks}/bin/sks db -hkp_address ${hkpAddress} -hkp_port ${hkpPort}"; + ExecStart = "${sksPkg}/bin/sks db -hkp_address ${hkpAddress} -hkp_port ${hkpPort}"; }; }; }; diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix index def77ba69e58..aca2cf8cdeaa 100644 --- a/nixos/modules/services/security/tor.nix +++ b/nixos/modules/services/security/tor.nix @@ -57,6 +57,11 @@ let AutomapHostsSuffixes ${concatStringsSep "," cfg.client.dns.automapHostsSuffixes} ''} '' + # Explicitly disable the SOCKS server if the client is disabled. In + # particular, this makes non-anonymous hidden services possible. + + optionalString (! cfg.client.enable) '' + SOCKSPort 0 + '' # Relay config + optionalString cfg.relay.enable '' ORPort ${toString cfg.relay.port} @@ -208,7 +213,7 @@ in enable = mkOption { type = types.bool; default = false; - description = "Whether to enable tor transaprent proxy"; + description = "Whether to enable tor transparent proxy"; }; listenAddress = mkOption { diff --git a/nixos/modules/services/system/kerberos.nix b/nixos/modules/services/system/kerberos.nix index d151385d2f9b..e2c45ed64ac0 100644 --- a/nixos/modules/services/system/kerberos.nix +++ b/nixos/modules/services/system/kerberos.nix @@ -42,7 +42,7 @@ in protocol = "tcp"; user = "root"; server = "${pkgs.tcp_wrappers}/bin/tcpd"; - serverArgs = "${pkgs.heimdalFull}/bin/kadmind"; + serverArgs = "${pkgs.heimdalFull}/libexec/heimdal/kadmind"; }; systemd.services.kdc = { @@ -51,13 +51,13 @@ in preStart = '' mkdir -m 0755 -p ${stateDir} ''; - script = "${heimdalFull}/bin/kdc"; + script = "${heimdalFull}/libexec/heimdal/kdc"; }; systemd.services.kpasswdd = { description = "Kerberos Password Changing daemon"; wantedBy = [ "multi-user.target" ]; - script = "${heimdalFull}/bin/kpasswdd"; + script = "${heimdalFull}/libexec/heimdal/kpasswdd"; }; }; diff --git a/nixos/modules/services/system/saslauthd.nix b/nixos/modules/services/system/saslauthd.nix index c8ddca9a0db6..8fcf4fb91fc4 100644 --- a/nixos/modules/services/system/saslauthd.nix +++ b/nixos/modules/services/system/saslauthd.nix @@ -16,7 +16,7 @@ in services.saslauthd = { - enable = mkEnableOption "Whether to enable the Cyrus SASL authentication daemon."; + enable = mkEnableOption "saslauthd, the Cyrus SASL authentication daemon"; package = mkOption { default = pkgs.cyrus_sasl.bin; diff --git a/nixos/modules/services/ttys/kmscon.nix b/nixos/modules/services/ttys/kmscon.nix index 59c45fcb44ee..82b6a51028e3 100644 --- a/nixos/modules/services/ttys/kmscon.nix +++ b/nixos/modules/services/ttys/kmscon.nix @@ -4,6 +4,8 @@ let cfg = config.services.kmscon; + autologinArg = lib.optionalString (cfg.autologinUser != null) "-f ${cfg.autologinUser}"; + configDir = pkgs.writeTextFile { name = "kmscon-config"; destination = "/kmscon.conf"; text = cfg.extraConfig; }; in { options = { @@ -39,6 +41,15 @@ in { default = ""; example = "--term xterm-256color"; }; + + autologinUser = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Username of the account that will be automatically logged in at the console. + If unspecified, a login prompt is shown as usual. + ''; + }; }; }; @@ -61,7 +72,7 @@ in { [Service] ExecStart= - ExecStart=${pkgs.kmscon}/bin/kmscon "--vt=%I" ${cfg.extraOptions} --seats=seat0 --no-switchvt --configdir ${configDir} --login -- ${pkgs.shadow}/bin/login -p + ExecStart=${pkgs.kmscon}/bin/kmscon "--vt=%I" ${cfg.extraOptions} --seats=seat0 --no-switchvt --configdir ${configDir} --login -- ${pkgs.shadow}/bin/login -p ${autologinArg} UtmpIdentifier=%I TTYPath=/dev/%I TTYReset=yes diff --git a/nixos/modules/services/web-apps/codimd.nix b/nixos/modules/services/web-apps/codimd.nix new file mode 100644 index 000000000000..a0af28eac7cc --- /dev/null +++ b/nixos/modules/services/web-apps/codimd.nix @@ -0,0 +1,920 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.codimd; + + prettyJSON = conf: + pkgs.runCommand "codimd-config.json" { } '' + echo '${builtins.toJSON conf}' | ${pkgs.jq}/bin/jq \ + '{production:del(.[]|nulls)|del(.[][]?|nulls)}' > $out + ''; +in +{ + options.services.codimd = { + enable = mkEnableOption "the CodiMD Markdown Editor"; + + groups = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Groups to which the codimd user should be added. + ''; + }; + + workDir = mkOption { + type = types.path; + default = "/var/lib/codimd"; + description = '' + Working directory for the CodiMD service. + ''; + }; + + configuration = { + debug = mkEnableOption "debug mode"; + domain = mkOption { + type = types.nullOr types.str; + default = null; + example = "codimd.org"; + description = '' + Domain name for the CodiMD instance. + ''; + }; + urlPath = mkOption { + type = types.nullOr types.str; + default = null; + example = "/url/path/to/codimd"; + description = '' + Path under which CodiMD is accessible. + ''; + }; + host = mkOption { + type = types.str; + default = "localhost"; + description = '' + Address to listen on. + ''; + }; + port = mkOption { + type = types.int; + default = 3000; + example = "80"; + description = '' + Port to listen on. + ''; + }; + path = mkOption { + type = types.nullOr types.str; + default = null; + example = "/var/run/codimd.sock"; + description = '' + Specify where a UNIX domain socket should be placed. + ''; + }; + allowOrigin = mkOption { + type = types.listOf types.str; + default = []; + example = [ "localhost" "codimd.org" ]; + description = '' + List of domains to whitelist. + ''; + }; + useSSL = mkOption { + type = types.bool; + default = false; + description = '' + Enable to use SSL server. This will also enable + <option>protocolUseSSL</option>. + ''; + }; + hsts = { + enable = mkOption { + type = types.bool; + default = true; + description = '' + Wheter to enable HSTS if HTTPS is also enabled. + ''; + }; + maxAgeSeconds = mkOption { + type = types.int; + default = 31536000; + description = '' + Max duration for clients to keep the HSTS status. + ''; + }; + includeSubdomains = mkOption { + type = types.bool; + default = true; + description = '' + Whether to include subdomains in HSTS. + ''; + }; + preload = mkOption { + type = types.bool; + default = true; + description = '' + Whether to allow preloading of the site's HSTS status. + ''; + }; + }; + csp = mkOption { + type = types.nullOr types.attrs; + default = null; + example = literalExample '' + { + enable = true; + directives = { + scriptSrc = "trustworthy.scripts.example.com"; + }; + upgradeInsecureRequest = "auto"; + addDefaults = true; + } + ''; + description = '' + Specify the Content Security Policy which is passed to Helmet. + For configuration details see <link xlink:href="https://helmetjs.github.io/docs/csp/" + >https://helmetjs.github.io/docs/csp/</link>. + ''; + }; + protocolUseSSL = mkOption { + type = types.bool; + default = false; + description = '' + Enable to use TLS for resource paths. + This only applies when <option>domain</option> is set. + ''; + }; + urlAddPort = mkOption { + type = types.bool; + default = false; + description = '' + Enable to add the port to callback URLs. + This only applies when <option>domain</option> is set + and only for ports other than 80 and 443. + ''; + }; + useCDN = mkOption { + type = types.bool; + default = true; + description = '' + Whether to use CDN resources or not. + ''; + }; + allowAnonymous = mkOption { + type = types.bool; + default = true; + description = '' + Whether to allow anonymous usage. + ''; + }; + allowAnonymousEdits = mkOption { + type = types.bool; + default = false; + description = '' + Whether to allow guests to edit existing notes with the `freely' permission, + when <option>allowAnonymous</option> is enabled. + ''; + }; + allowFreeURL = mkOption { + type = types.bool; + default = false; + description = '' + Whether to allow note creation by accessing a nonexistent note URL. + ''; + }; + defaultPermission = mkOption { + type = types.enum [ "freely" "editable" "limited" "locked" "private" ]; + default = "editable"; + description = '' + Default permissions for notes. + This only applies for signed-in users. + ''; + }; + dbURL = mkOption { + type = types.nullOr types.str; + default = null; + example = '' + postgres://user:pass@host:5432/dbname + ''; + description = '' + Specify which database to use. + CodiMD supports mysql, postgres, sqlite and mssql. + See <link xlink:href="https://sequelize.readthedocs.io/en/v3/"> + https://sequelize.readthedocs.io/en/v3/</link> for more information. + Note: This option overrides <option>db</option>. + ''; + }; + db = mkOption { + type = types.attrs; + default = {}; + example = literalExample '' + { + dialect = "sqlite"; + storage = "/var/lib/codimd/db.codimd.sqlite"; + } + ''; + description = '' + Specify the configuration for sequelize. + CodiMD supports mysql, postgres, sqlite and mssql. + See <link xlink:href="https://sequelize.readthedocs.io/en/v3/"> + https://sequelize.readthedocs.io/en/v3/</link> for more information. + Note: This option overrides <option>db</option>. + ''; + }; + sslKeyPath= mkOption { + type = types.nullOr types.str; + default = null; + example = "/var/lib/codimd/codimd.key"; + description = '' + Path to the SSL key. Needed when <option>useSSL</option> is enabled. + ''; + }; + sslCertPath = mkOption { + type = types.nullOr types.str; + default = null; + example = "/var/lib/codimd/codimd.crt"; + description = '' + Path to the SSL cert. Needed when <option>useSSL</option> is enabled. + ''; + }; + sslCAPath = mkOption { + type = types.listOf types.str; + default = []; + example = [ "/var/lib/codimd/ca.crt" ]; + description = '' + SSL ca chain. Needed when <option>useSSL</option> is enabled. + ''; + }; + dhParamPath = mkOption { + type = types.nullOr types.str; + default = null; + example = "/var/lib/codimd/dhparam.pem"; + description = '' + Path to the SSL dh params. Needed when <option>useSSL</option> is enabled. + ''; + }; + tmpPath = mkOption { + type = types.str; + default = "/tmp"; + description = '' + Path to the temp directory CodiMD should use. + Note that <option>serviceConfig.PrivateTmp</option> is enabled for + the CodiMD systemd service by default. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + defaultNotePath = mkOption { + type = types.nullOr types.str; + default = "./public/default.md"; + description = '' + Path to the default Note file. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + docsPath = mkOption { + type = types.nullOr types.str; + default = "./public/docs"; + description = '' + Path to the docs directory. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + indexPath = mkOption { + type = types.nullOr types.str; + default = "./public/views/index.ejs"; + description = '' + Path to the index template file. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + hackmdPath = mkOption { + type = types.nullOr types.str; + default = "./public/views/hackmd.ejs"; + description = '' + Path to the hackmd template file. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + errorPath = mkOption { + type = types.nullOr types.str; + default = null; + defaultText = "./public/views/error.ejs"; + description = '' + Path to the error template file. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + prettyPath = mkOption { + type = types.nullOr types.str; + default = null; + defaultText = "./public/views/pretty.ejs"; + description = '' + Path to the pretty template file. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + slidePath = mkOption { + type = types.nullOr types.str; + default = null; + defaultText = "./public/views/slide.hbs"; + description = '' + Path to the slide template file. + (Non-canonical paths are relative to CodiMD's base directory) + ''; + }; + uploadsPath = mkOption { + type = types.str; + default = "${cfg.workDir}/uploads"; + defaultText = "/var/lib/codimd/uploads"; + description = '' + Path under which uploaded files are saved. + ''; + }; + sessionName = mkOption { + type = types.str; + default = "connect.sid"; + description = '' + Specify the name of the session cookie. + ''; + }; + sessionSecret = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Specify the secret used to sign the session cookie. + If unset, one will be generated on startup. + ''; + }; + sessionLife = mkOption { + type = types.int; + default = 1209600000; + description = '' + Session life time in milliseconds. + ''; + }; + heartbeatInterval = mkOption { + type = types.int; + default = 5000; + description = '' + Specify the socket.io heartbeat interval. + ''; + }; + heartbeatTimeout = mkOption { + type = types.int; + default = 10000; + description = '' + Specify the socket.io heartbeat timeout. + ''; + }; + documentMaxLength = mkOption { + type = types.int; + default = 100000; + description = '' + Specify the maximum document length. + ''; + }; + email = mkOption { + type = types.bool; + default = true; + description = '' + Whether to enable email sign-in. + ''; + }; + allowEmailRegister = mkOption { + type = types.bool; + default = true; + description = '' + Wether to enable email registration. + ''; + }; + allowGravatar = mkOption { + type = types.bool; + default = true; + description = '' + Whether to use gravatar as profile picture source. + ''; + }; + imageUploadType = mkOption { + type = types.enum [ "imgur" "s3" "minio" "filesystem" ]; + default = "filesystem"; + description = '' + Specify where to upload images. + ''; + }; + minio = mkOption { + type = types.nullOr (types.submodule { + options = { + accessKey = mkOption { + type = types.str; + description = '' + Minio access key. + ''; + }; + secretKey = mkOption { + type = types.str; + description = '' + Minio secret key. + ''; + }; + endpoint = mkOption { + type = types.str; + description = '' + Minio endpoint. + ''; + }; + port = mkOption { + type = types.int; + default = 9000; + description = '' + Minio listen port. + ''; + }; + secure = mkOption { + type = types.bool; + default = true; + description = '' + Whether to use HTTPS for Minio. + ''; + }; + }; + }); + default = null; + description = "Configure the minio third-party integration."; + }; + s3 = mkOption { + type = types.nullOr (types.submodule { + options = { + accessKeyId = mkOption { + type = types.str; + description = '' + AWS access key id. + ''; + }; + secretAccessKey = mkOption { + type = types.str; + description = '' + AWS access key. + ''; + }; + region = mkOption { + type = types.str; + description = '' + AWS S3 region. + ''; + }; + }; + }); + default = null; + description = "Configure the s3 third-party integration."; + }; + s3bucket = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Specify the bucket name for upload types <literal>s3</literal> and <literal>minio</literal>. + ''; + }; + allowPDFExport = mkOption { + type = types.bool; + default = true; + description = '' + Whether to enable PDF exports. + ''; + }; + imgur.clientId = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Imgur API client ID. + ''; + }; + azure = mkOption { + type = types.nullOr (types.submodule { + options = { + connectionString = mkOption { + type = types.str; + description = '' + Azure Blob Storage connection string. + ''; + }; + container = mkOption { + type = types.str; + description = '' + Azure Blob Storage container name. + It will be created if non-existent. + ''; + }; + }; + }); + default = null; + description = "Configure the azure third-party integration."; + }; + oauth2 = mkOption { + type = types.nullOr (types.submodule { + options = { + authorizationURL = mkOption { + type = types.str; + description = '' + Specify the OAuth authorization URL. + ''; + }; + tokenURL = mkOption { + type = types.str; + description = '' + Specify the OAuth token URL. + ''; + }; + clientID = mkOption { + type = types.str; + description = '' + Specify the OAuth client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + description = '' + Specify the OAuth client secret. + ''; + }; + }; + }); + default = null; + description = "Configure the OAuth integration."; + }; + facebook = mkOption { + type = types.nullOr (types.submodule { + options = { + clientID = mkOption { + type = types.str; + description = '' + Facebook API client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + description = '' + Facebook API client secret. + ''; + }; + }; + }); + default = null; + description = "Configure the facebook third-party integration"; + }; + twitter = mkOption { + type = types.nullOr (types.submodule { + options = { + consumerKey = mkOption { + type = types.str; + description = '' + Twitter API consumer key. + ''; + }; + consumerSecret = mkOption { + type = types.str; + description = '' + Twitter API consumer secret. + ''; + }; + }; + }); + default = null; + description = "Configure the Twitter third-party integration."; + }; + github = mkOption { + type = types.nullOr (types.submodule { + options = { + clientID = mkOption { + type = types.str; + description = '' + GitHub API client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + description = '' + Github API client secret. + ''; + }; + }; + }); + default = null; + description = "Configure the GitHub third-party integration."; + }; + gitlab = mkOption { + type = types.nullOr (types.submodule { + options = { + baseURL = mkOption { + type = types.str; + default = ""; + description = '' + GitLab API authentication endpoint. + Only needed for other endpoints than gitlab.com. + ''; + }; + clientID = mkOption { + type = types.str; + description = '' + GitLab API client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + description = '' + GitLab API client secret. + ''; + }; + scope = mkOption { + type = types.enum [ "api" "read_user" ]; + default = "api"; + description = '' + GitLab API requested scope. + GitLab snippet import/export requires api scope. + ''; + }; + }; + }); + default = null; + description = "Configure the GitLab third-party integration."; + }; + mattermost = mkOption { + type = types.nullOr (types.submodule { + options = { + baseURL = mkOption { + type = types.str; + description = '' + Mattermost authentication endpoint. + ''; + }; + clientID = mkOption { + type = types.str; + description = '' + Mattermost API client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + description = '' + Mattermost API client secret. + ''; + }; + }; + }); + default = null; + description = "Configure the Mattermost third-party integration."; + }; + dropbox = mkOption { + type = types.nullOr (types.submodule { + options = { + clientID = mkOption { + type = types.str; + description = '' + Dropbox API client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + description = '' + Dropbox API client secret. + ''; + }; + appKey = mkOption { + type = types.str; + description = '' + Dropbox app key. + ''; + }; + }; + }); + default = null; + description = "Configure the Dropbox third-party integration."; + }; + google = mkOption { + type = types.nullOr (types.submodule { + options = { + clientID = mkOption { + type = types.str; + description = '' + Google API client ID. + ''; + }; + clientSecret = mkOption { + type = types.str; + description = '' + Google API client secret. + ''; + }; + }; + }); + default = null; + description = "Configure the Google third-party integration."; + }; + ldap = mkOption { + type = types.nullOr (types.submodule { + options = { + providerName = mkOption { + type = types.str; + default = ""; + description = '' + Optional name to be displayed at login form, indicating the LDAP provider. + ''; + }; + url = mkOption { + type = types.str; + example = "ldap://localhost"; + description = '' + URL of LDAP server. + ''; + }; + bindDn = mkOption { + type = types.str; + description = '' + Bind DN for LDAP access. + ''; + }; + bindCredentials = mkOption { + type = types.str; + description = '' + Bind credentials for LDAP access. + ''; + }; + searchBase = mkOption { + type = types.str; + example = "o=users,dc=example,dc=com"; + description = '' + LDAP directory to begin search from. + ''; + }; + searchFilter = mkOption { + type = types.str; + example = "(uid={{username}})"; + description = '' + LDAP filter to search with. + ''; + }; + searchAttributes = mkOption { + type = types.listOf types.str; + example = [ "displayName" "mail" ]; + description = '' + LDAP attributes to search with. + ''; + }; + userNameField = mkOption { + type = types.str; + default = ""; + description = '' + LDAP field which is used as the username on CodiMD. + By default <option>useridField</option> is used. + ''; + }; + useridField = mkOption { + type = types.str; + example = "uid"; + description = '' + LDAP field which is a unique identifier for users on CodiMD. + ''; + }; + tlsca = mkOption { + type = types.str; + example = "server-cert.pem,root.pem"; + description = '' + Root CA for LDAP TLS in PEM format. + ''; + }; + }; + }); + default = null; + description = "Configure the LDAP integration."; + }; + saml = mkOption { + type = types.nullOr (types.submodule { + options = { + idpSsoUrl = mkOption { + type = types.str; + example = "https://idp.example.com/sso"; + description = '' + IdP authentication endpoint. + ''; + }; + idpCert = mkOption { + type = types.path; + example = "/path/to/cert.pem"; + description = '' + Path to IdP certificate file in PEM format. + ''; + }; + issuer = mkOption { + type = types.str; + default = ""; + description = '' + Optional identity of the service provider. + This defaults to the server URL. + ''; + }; + identifierFormat = mkOption { + type = types.str; + default = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"; + description = '' + Optional name identifier format. + ''; + }; + groupAttribute = mkOption { + type = types.str; + default = ""; + example = "memberOf"; + description = '' + Optional attribute name for group list. + ''; + }; + externalGroups = mkOption { + type = types.listOf types.str; + default = []; + example = [ "Temporary-staff" "External-users" ]; + description = '' + Excluded group names. + ''; + }; + requiredGroups = mkOption { + type = types.listOf types.str; + default = []; + example = [ "Hackmd-users" "Codimd-users" ]; + description = '' + Required group names. + ''; + }; + attribute = { + id = mkOption { + type = types.str; + default = ""; + description = '' + Attribute map for `id'. + Defaults to `NameID' of SAML response. + ''; + }; + username = mkOption { + type = types.str; + default = ""; + description = '' + Attribute map for `username'. + Defaults to `NameID' of SAML response. + ''; + }; + email = mkOption { + type = types.str; + default = ""; + description = '' + Attribute map for `email'. + Defaults to `NameID' of SAML response if + <option>identifierFormat</option> has + the default value. + ''; + }; + }; + }; + }); + default = null; + description = "Configure the SAML integration."; + }; + }; + }; + + config = mkIf cfg.enable { + assertions = [ + { assertion = cfg.configuration.db == {} -> ( + cfg.configuration.dbURL != "" && cfg.configuration.dbURL != null + ); + message = "Database configuration for CodiMD missing."; } + ]; + users.groups.codimd = {}; + users.users.codimd = { + description = "CodiMD service user"; + group = "codimd"; + extraGroups = cfg.groups; + home = cfg.workDir; + createHome = true; + }; + + systemd.services.codimd = { + description = "CodiMD Service"; + wantedBy = [ "multi-user.target" ]; + after = [ "networking.target" ]; + preStart = '' + mkdir -p ${cfg.workDir} + chown -R codimd: ${cfg.workDir} + ''; + serviceConfig = { + WorkingDirectory = cfg.workDir; + ExecStart = "${pkgs.codimd}/bin/codimd"; + Environment = [ + "CMD_CONFIG_FILE=${prettyJSON cfg.configuration}" + "NODE_ENV=production" + ]; + Restart = "always"; + User = "codimd"; + PermissionsStartOnly = true; + PrivateTmp = true; + }; + }; + }; +} diff --git a/nixos/modules/services/web-apps/matomo-doc.xml b/nixos/modules/services/web-apps/matomo-doc.xml index 6f878015c514..510a335edc3b 100644 --- a/nixos/modules/services/web-apps/matomo-doc.xml +++ b/nixos/modules/services/web-apps/matomo-doc.xml @@ -3,28 +3,24 @@ xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="module-services-matomo"> + <title>Matomo</title> + <para> + Matomo is a real-time web analytics application. This module configures + php-fpm as backend for Matomo, optionally configuring an nginx vhost as well. + </para> + <para> + An automatic setup is not suported by Matomo, so you need to configure Matomo + itself in the browser-based Matomo setup. + </para> + <section xml:id="module-services-matomo-database-setup"> + <title>Database Setup</title> - <title>Matomo</title> <para> - Matomo is a real-time web analytics application. - This module configures php-fpm as backend for Matomo, optionally configuring an nginx vhost as well. - </para> - - <para> - An automatic setup is not suported by Matomo, so you need to configure Matomo itself in the browser-based Matomo setup. - </para> - - - <section xml:id="module-services-matomo-database-setup"> - <title>Database Setup</title> - - <para> - You also need to configure a MariaDB or MySQL database and -user for Matomo yourself, - and enter those credentials in your browser. - You can use passwordless database authentication via the UNIX_SOCKET authentication plugin - with the following SQL commands: - - <programlisting> + You also need to configure a MariaDB or MySQL database and -user for Matomo + yourself, and enter those credentials in your browser. You can use + passwordless database authentication via the UNIX_SOCKET authentication + plugin with the following SQL commands: +<programlisting> # For MariaDB INSTALL PLUGIN unix_socket SONAME 'auth_socket'; CREATE DATABASE matomo; @@ -37,59 +33,58 @@ CREATE USER 'matomo'@'localhost' IDENTIFIED WITH auth_socket; GRANT ALL PRIVILEGES ON matomo.* TO 'matomo'@'localhost'; </programlisting> + Then fill in <literal>matomo</literal> as database user and database name, + and leave the password field blank. This authentication works by allowing + only the <literal>matomo</literal> unix user to authenticate as the + <literal>matomo</literal> database user (without needing a password), but no + other users. For more information on passwordless login, see + <link xlink:href="https://mariadb.com/kb/en/mariadb/unix_socket-authentication-plugin/" />. + </para> - Then fill in <literal>matomo</literal> as database user and database name, and leave the password field blank. - This authentication works by allowing only the <literal>matomo</literal> unix user to authenticate as the - <literal>matomo</literal> database user (without needing a password), but no other users. - For more information on passwordless login, see - <link xlink:href="https://mariadb.com/kb/en/mariadb/unix_socket-authentication-plugin/" />. - </para> - - <para> - Of course, you can use password based authentication as well, e.g. when the database is not on the same host. - </para> - </section> + <para> + Of course, you can use password based authentication as well, e.g. when the + database is not on the same host. + </para> + </section> + <section xml:id="module-services-matomo-backups"> + <title>Backup</title> + <para> + You only need to take backups of your MySQL database and the + <filename>/var/lib/matomo/config/config.ini.php</filename> file. Use a user + in the <literal>matomo</literal> group or root to access the file. For more + information, see + <link xlink:href="https://matomo.org/faq/how-to-install/faq_138/" />. + </para> + </section> + <section xml:id="module-services-matomo-issues"> + <title>Issues</title> - <section xml:id="module-services-matomo-backups"> - <title>Backup</title> + <itemizedlist> + <listitem> <para> - You only need to take backups of your MySQL database and the - <filename>/var/lib/matomo/config/config.ini.php</filename> file. - Use a user in the <literal>matomo</literal> group or root to access the file. - For more information, see <link xlink:href="https://matomo.org/faq/how-to-install/faq_138/" />. + Matomo's file integrity check will warn you. This is due to the patches + necessary for NixOS, you can safely ignore this. </para> - </section> - - - <section xml:id="module-services-matomo-issues"> - <title>Issues</title> - <itemizedlist> - <listitem> - <para> - Matomo's file integrity check will warn you. - This is due to the patches necessary for NixOS, you can safely ignore this. - </para> - </listitem> - - <listitem> - <para> - Matomo will warn you that the JavaScript tracker is not writable. - This is because it's located in the read-only nix store. - You can safely ignore this, unless you need a plugin that needs JavaScript tracker access. - </para> - </listitem> - </itemizedlist> - </section> - - - <section xml:id="module-services-matomo-other-web-servers"> - <title>Using other Web Servers than nginx</title> - + </listitem> + <listitem> <para> - You can use other web servers by forwarding calls for <filename>index.php</filename> and - <filename>piwik.php</filename> to the <literal>/run/phpfpm-matomo.sock</literal> fastcgi unix socket. - You can use the nginx configuration in the module code as a reference to what else should be configured. + Matomo will warn you that the JavaScript tracker is not writable. This is + because it's located in the read-only nix store. You can safely ignore + this, unless you need a plugin that needs JavaScript tracker access. </para> - </section> + </listitem> + </itemizedlist> + </section> + <section xml:id="module-services-matomo-other-web-servers"> + <title>Using other Web Servers than nginx</title> + + <para> + You can use other web servers by forwarding calls for + <filename>index.php</filename> and <filename>piwik.php</filename> to the + <literal>/run/phpfpm-matomo.sock</literal> fastcgi unix socket. You can use + the nginx configuration in the module code as a reference to what else + should be configured. + </para> + </section> </chapter> diff --git a/nixos/modules/services/web-apps/matomo.nix b/nixos/modules/services/web-apps/matomo.nix index fbbd7715c6b3..9fddf8320748 100644 --- a/nixos/modules/services/web-apps/matomo.nix +++ b/nixos/modules/services/web-apps/matomo.nix @@ -34,6 +34,13 @@ in { ''; }; + package = mkOption { + type = types.package; + description = "Matomo package to use"; + default = pkgs.matomo; + defaultText = "pkgs.matomo"; + }; + webServerUser = mkOption { type = types.nullOr types.str; default = null; @@ -124,7 +131,7 @@ in { # the update part of the script can only work if the database is already up and running requires = [ databaseService ]; after = [ databaseService ]; - path = [ pkgs.matomo ]; + path = [ cfg.package ]; serviceConfig = { Type = "oneshot"; User = user; @@ -151,7 +158,7 @@ in { # Use User-Private Group scheme to protect matomo data, but allow administration / backup via matomo group # Copy config folder chmod g+s "${dataDir}" - cp -r "${pkgs.matomo}/config" "${dataDir}/" + cp -r "${cfg.package}/config" "${dataDir}/" chmod -R u+rwX,g+rwX,o-rwx "${dataDir}" # check whether user setup has already been done @@ -164,7 +171,7 @@ in { systemd.services.${phpExecutionUnit} = { # stop phpfpm on package upgrade, do database upgrade via matomo_setup_update, and then restart - restartTriggers = [ pkgs.matomo ]; + restartTriggers = [ cfg.package ]; # stop config.ini.php from getting written with read permission for others serviceConfig.UMask = "0007"; }; @@ -195,7 +202,7 @@ in { "${user}.${fqdn}" = mkMerge [ cfg.nginx { # don't allow to override the root easily, as it will almost certainly break matomo. # disadvantage: not shown as default in docs. - root = mkForce "${pkgs.matomo}/share"; + root = mkForce "${cfg.package}/share"; # define locations here instead of as the submodule option's default # so that they can easily be extended with additional locations if required diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix new file mode 100644 index 000000000000..c7e97bbeba9a --- /dev/null +++ b/nixos/modules/services/web-apps/nextcloud.nix @@ -0,0 +1,482 @@ +{ config, lib, pkgs, ... }@args: + +with lib; + +let + cfg = config.services.nextcloud; + + toKeyValue = generators.toKeyValue { + mkKeyValue = generators.mkKeyValueDefault {} " = "; + }; + + phpOptionsExtensions = '' + ${optionalString cfg.caching.apcu "extension=${cfg.phpPackages.apcu}/lib/php/extensions/apcu.so"} + ${optionalString cfg.caching.redis "extension=${cfg.phpPackages.redis}/lib/php/extensions/redis.so"} + ${optionalString cfg.caching.memcached "extension=${cfg.phpPackages.memcached}/lib/php/extensions/memcached.so"} + zend_extension = opcache.so + opcache.enable = 1 + ''; + phpOptions = { + upload_max_filesize = cfg.maxUploadSize; + post_max_size = cfg.maxUploadSize; + memory_limit = cfg.maxUploadSize; + } // cfg.phpOptions; + phpOptionsStr = phpOptionsExtensions + (toKeyValue phpOptions); + + occ = pkgs.writeScriptBin "nextcloud-occ" '' + #! ${pkgs.stdenv.shell} + cd ${pkgs.nextcloud} + exec /run/wrappers/bin/sudo -u nextcloud \ + NEXTCLOUD_CONFIG_DIR="${cfg.home}/config" \ + ${config.services.phpfpm.phpPackage}/bin/php \ + -c ${pkgs.writeText "php.ini" phpOptionsStr}\ + occ $* + ''; + +in { + options.services.nextcloud = { + enable = mkEnableOption "nextcloud"; + hostName = mkOption { + type = types.str; + description = "FQDN for the nextcloud instance."; + }; + home = mkOption { + type = types.str; + default = "/var/lib/nextcloud"; + description = "Storage path of nextcloud."; + }; + https = mkOption { + type = types.bool; + default = false; + description = "Enable if there is a TLS terminating proxy in front of nextcloud."; + }; + + maxUploadSize = mkOption { + default = "512M"; + type = types.str; + description = '' + Defines the upload limit for files. This changes the relevant options + in php.ini and nginx if enabled. + ''; + }; + + skeletonDirectory = mkOption { + default = ""; + type = types.str; + description = '' + The directory where the skeleton files are located. These files will be + copied to the data directory of new users. Leave empty to not copy any + skeleton files. + ''; + }; + + nginx.enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable nginx virtual host management. + Further nginx configuration can be done by adapting <literal>services.nginx.virtualHosts.<name></literal>. + See <xref linkend="opt-services.nginx.virtualHosts"/> for further information. + ''; + }; + + webfinger = mkOption { + type = types.bool; + default = false; + description = '' + Enable this option if you plan on using the webfinger plugin. + The appropriate nginx rewrite rules will be added to your configuration. + ''; + }; + + phpPackages = mkOption { + type = types.attrs; + default = pkgs.php71Packages; + defaultText = "pkgs.php71Packages"; + description = '' + Overridable attribute of the PHP packages set to use. If any caching + module is enabled, it will be taken from here. Therefore it should + match the version of PHP given to + <literal>services.phpfpm.phpPackage</literal>. + ''; + }; + + phpOptions = mkOption { + type = types.attrsOf types.str; + default = { + "short_open_tag" = "Off"; + "expose_php" = "Off"; + "error_reporting" = "E_ALL & ~E_DEPRECATED & ~E_STRICT"; + "display_errors" = "stderr"; + "opcache.enable_cli" = "1"; + "opcache.interned_strings_buffer" = "8"; + "opcache.max_accelerated_files" = "10000"; + "opcache.memory_consumption" = "128"; + "opcache.revalidate_freq" = "1"; + "opcache.fast_shutdown" = "1"; + "openssl.cafile" = "/etc/ssl/certs/ca-certificates.crt"; + "catch_workers_output" = "yes"; + }; + description = '' + Options for PHP's php.ini file for nextcloud. + ''; + }; + + poolConfig = mkOption { + type = types.lines; + default = '' + pm = dynamic + pm.max_children = 32 + pm.start_servers = 2 + pm.min_spare_servers = 2 + pm.max_spare_servers = 4 + pm.max_requests = 500 + ''; + description = '' + Options for nextcloud's PHP pool. See the documentation on <literal>php-fpm.conf</literal> for details on configuration directives. + ''; + }; + + config = { + dbtype = mkOption { + type = types.enum [ "sqlite" "pgsql" "mysql" ]; + default = "sqlite"; + description = "Database type."; + }; + dbname = mkOption { + type = types.nullOr types.str; + default = "nextcloud"; + description = "Database name."; + }; + dbuser = mkOption { + type = types.nullOr types.str; + default = "nextcloud"; + description = "Database user."; + }; + dbpass = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Database password. Use <literal>dbpassFile</literal> to avoid this + being world-readable in the <literal>/nix/store</literal>. + ''; + }; + dbpassFile = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + The full path to a file that contains the database password. + ''; + }; + dbhost = mkOption { + type = types.nullOr types.str; + default = "localhost"; + description = "Database host."; + }; + dbport = mkOption { + type = with types; nullOr (either int str); + default = null; + description = "Database port."; + }; + dbtableprefix = mkOption { + type = types.nullOr types.str; + default = null; + description = "Table prefix in Nextcloud database."; + }; + adminuser = mkOption { + type = types.str; + default = "root"; + description = "Admin username."; + }; + adminpass = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Admin password. Use <literal>adminpassFile</literal> to avoid this + being world-readable in the <literal>/nix/store</literal>. + ''; + }; + adminpassFile = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + The full path to a file that contains the admin's password. + ''; + }; + + extraTrustedDomains = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Trusted domains, from which the nextcloud installation will be + acessible. You don't need to add + <literal>services.nextcloud.hostname</literal> here. + ''; + }; + }; + + caching = { + apcu = mkOption { + type = types.bool; + default = true; + description = '' + Whether to load the APCu module into PHP. + ''; + }; + redis = mkOption { + type = types.bool; + default = false; + description = '' + Whether to load the Redis module into PHP. + You still need to enable Redis in your config.php. + See https://docs.nextcloud.com/server/14/admin_manual/configuration_server/caching_configuration.html + ''; + }; + memcached = mkOption { + type = types.bool; + default = false; + description = '' + Whether to load the Memcached module into PHP. + You still need to enable Memcached in your config.php. + See https://docs.nextcloud.com/server/14/admin_manual/configuration_server/caching_configuration.html + ''; + }; + }; + }; + + config = mkIf cfg.enable (mkMerge [ + { assertions = let acfg = cfg.config; in [ + { assertion = !(acfg.dbpass != null && acfg.dbpassFile != null); + message = "Please specify no more than one of dbpass or dbpassFile"; + } + { assertion = ((acfg.adminpass != null || acfg.adminpassFile != null) + && !(acfg.adminpass != null && acfg.adminpassFile != null)); + message = "Please specify exactly one of adminpass or adminpassFile"; + } + ]; + } + + { systemd.timers."nextcloud-cron" = { + wantedBy = [ "timers.target" ]; + timerConfig.OnBootSec = "5m"; + timerConfig.OnUnitActiveSec = "15m"; + timerConfig.Unit = "nextcloud-cron.service"; + }; + + systemd.services = { + "nextcloud-setup" = let + overrideConfig = pkgs.writeText "nextcloud-config.php" '' + <?php + $CONFIG = [ + 'apps_paths' => [ + [ 'path' => '${cfg.home}/apps', 'url' => '/apps', 'writable' => false ], + [ 'path' => '${cfg.home}/store-apps', 'url' => '/store-apps', 'writable' => true ], + ], + 'datadirectory' => '${cfg.home}/data', + 'skeletondirectory' => '${cfg.skeletonDirectory}', + ${optionalString cfg.caching.apcu "'memcache.local' => '\\OC\\Memcache\\APCu',"} + 'log_type' => 'syslog', + ]; + ''; + occInstallCmd = let + c = cfg.config; + adminpass = if c.adminpassFile != null + then ''"$(<"${toString c.adminpassFile}")"'' + else ''"${toString c.adminpass}"''; + dbpass = if c.dbpassFile != null + then ''"$(<"${toString c.dbpassFile}")"'' + else if c.dbpass != null + then ''"${toString c.dbpass}"'' + else null; + installFlags = concatStringsSep " \\\n " + (mapAttrsToList (k: v: "${k} ${toString v}") { + "--database" = ''"${c.dbtype}"''; + # The following attributes are optional depending on the type of + # database. Those that evaluate to null on the left hand side + # will be omitted. + ${if c.dbname != null then "--database-name" else null} = ''"${c.dbname}"''; + ${if c.dbhost != null then "--database-host" else null} = ''"${c.dbhost}"''; + ${if c.dbport != null then "--database-port" else null} = ''"${toString c.dbport}"''; + ${if c.dbuser != null then "--database-user" else null} = ''"${c.dbuser}"''; + ${if (any (x: x != null) [c.dbpass c.dbpassFile]) + then "--database-pass" else null} = dbpass; + ${if c.dbtableprefix != null + then "--database-table-prefix" else null} = ''"${toString c.dbtableprefix}"''; + "--admin-user" = ''"${c.adminuser}"''; + "--admin-pass" = adminpass; + "--data-dir" = ''"${cfg.home}/data"''; + }); + in '' + ${occ}/bin/nextcloud-occ maintenance:install \ + ${installFlags} + ''; + occSetTrustedDomainsCmd = concatStringsSep "\n" (imap0 + (i: v: '' + ${occ}/bin/nextcloud-occ config:system:set trusted_domains \ + ${toString i} --value="${toString v}" + '') ([ cfg.hostName ] ++ cfg.config.extraTrustedDomains)); + + in { + wantedBy = [ "multi-user.target" ]; + before = [ "phpfpm-nextcloud.service" ]; + script = '' + chmod og+x ${cfg.home} + ln -sf ${pkgs.nextcloud}/apps ${cfg.home}/ + mkdir -p ${cfg.home}/config ${cfg.home}/data ${cfg.home}/store-apps + ln -sf ${overrideConfig} ${cfg.home}/config/override.config.php + + chown -R nextcloud:nginx ${cfg.home}/config ${cfg.home}/data ${cfg.home}/store-apps + + # Do not install if already installed + if [[ ! -e ${cfg.home}/config/config.php ]]; then + ${occInstallCmd} + fi + + ${occ}/bin/nextcloud-occ upgrade + + ${occ}/bin/nextcloud-occ config:system:delete trusted_domains + ${occSetTrustedDomainsCmd} + ''; + serviceConfig.Type = "oneshot"; + }; + "nextcloud-cron" = { + environment.NEXTCLOUD_CONFIG_DIR = "${cfg.home}/config"; + serviceConfig.Type = "oneshot"; + serviceConfig.User = "nextcloud"; + serviceConfig.ExecStart = "${pkgs.php}/bin/php -f ${pkgs.nextcloud}/cron.php"; + }; + }; + + services.phpfpm = { + phpOptions = phpOptionsExtensions; + phpPackage = pkgs.php71; + pools.nextcloud = let + phpAdminValues = (toKeyValue + (foldr (a: b: a // b) {} + (mapAttrsToList (k: v: { "php_admin_value[${k}]" = v; }) + phpOptions))); + in { + listen = "/run/phpfpm/nextcloud"; + extraConfig = '' + listen.owner = nginx + listen.group = nginx + user = nextcloud + group = nginx + ${cfg.poolConfig} + env[NEXTCLOUD_CONFIG_DIR] = ${cfg.home}/config + env[PATH] = /run/wrappers/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/usr/bin:/bin + ${phpAdminValues} + ''; + }; + }; + + users.extraUsers.nextcloud = { + home = "${cfg.home}"; + group = "nginx"; + createHome = true; + }; + + environment.systemPackages = [ occ ]; + } + + (mkIf cfg.nginx.enable { + services.nginx = { + enable = true; + virtualHosts = { + "${cfg.hostName}" = { + root = pkgs.nextcloud; + locations = { + "= /robots.txt" = { + priority = 100; + extraConfig = '' + allow all; + log_not_found off; + access_log off; + ''; + }; + "/" = { + priority = 200; + extraConfig = "rewrite ^ /index.php$uri;"; + }; + "~ ^/store-apps" = { + priority = 201; + extraConfig = "root ${cfg.home};"; + }; + "= /.well-known/carddav" = { + priority = 210; + extraConfig = "return 301 $scheme://$host/remote.php/dav;"; + }; + "= /.well-known/caldav" = { + priority = 210; + extraConfig = "return 301 $scheme://$host/remote.php/dav;"; + }; + "~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/" = { + priority = 300; + extraConfig = "deny all;"; + }; + "~ ^/(?:\\.|autotest|occ|issue|indie|db_|console)" = { + priority = 300; + extraConfig = "deny all;"; + }; + "~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\\.php(?:$|/)" = { + priority = 500; + extraConfig = '' + include ${pkgs.nginxMainline}/conf/fastcgi.conf; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param HTTPS ${if cfg.https then "on" else "off"}; + fastcgi_param modHeadersAvailable true; + fastcgi_param front_controller_active true; + fastcgi_pass unix:/run/phpfpm/nextcloud; + fastcgi_intercept_errors on; + fastcgi_request_buffering off; + fastcgi_read_timeout 120s; + ''; + }; + "~ ^/(?:updater|ocs-provider)(?:$|/)".extraConfig = '' + try_files $uri/ =404; + index index.php; + ''; + "~ \\.(?:css|js|woff|svg|gif)$".extraConfig = '' + try_files $uri /index.php$uri$is_args$args; + add_header Cache-Control "public, max-age=15778463"; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Robots-Tag none; + add_header X-Download-Options noopen; + add_header X-Permitted-Cross-Domain-Policies none; + access_log off; + ''; + "~ \\.(?:png|html|ttf|ico|jpg|jpeg)$".extraConfig = '' + try_files $uri /index.php$uri$is_args$args; + access_log off; + ''; + }; + extraConfig = '' + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Robots-Tag none; + add_header X-Download-Options noopen; + add_header X-Permitted-Cross-Domain-Policies none; + error_page 403 /core/templates/403.php; + error_page 404 /core/templates/404.php; + client_max_body_size ${cfg.maxUploadSize}; + fastcgi_buffers 64 4K; + gzip on; + gzip_vary on; + gzip_comp_level 4; + gzip_min_length 256; + gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; + gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; + + ${optionalString cfg.webfinger '' + rewrite ^/.well-known/host-meta /public.php?service=host-meta last; + rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last; + ''} + ''; + }; + }; + }; + }) + ]); +} diff --git a/nixos/modules/services/web-apps/tt-rss.nix b/nixos/modules/services/web-apps/tt-rss.nix index 2b171aa1b2b2..90b35d19ea11 100644 --- a/nixos/modules/services/web-apps/tt-rss.nix +++ b/nixos/modules/services/web-apps/tt-rss.nix @@ -624,7 +624,11 @@ let }; users = optionalAttrs (cfg.user == "tt_rss") { - users.tt_rss.group = "tt_rss"; + users.tt_rss = { + description = "tt-rss service user"; + isSystemUser = true; + group = "tt_rss"; + }; groups.tt_rss = {}; }; }; diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index b231ee5a3f01..6c733f093ba8 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -46,7 +46,7 @@ let configFile = pkgs.writeText "nginx.conf" '' user ${cfg.user} ${cfg.group}; - error_log stderr; + error_log ${cfg.logError}; daemon off; ${cfg.config} @@ -245,8 +245,8 @@ let } '' ) virtualHosts); - mkLocations = locations: concatStringsSep "\n" (mapAttrsToList (location: config: '' - location ${location} { + mkLocations = locations: concatStringsSep "\n" (map (config: '' + location ${config.location} { ${optionalString (config.proxyPass != null && !cfg.proxyResolveWhileRunning) "proxy_pass ${config.proxyPass};" } @@ -266,7 +266,18 @@ let ${config.extraConfig} ${optionalString (config.proxyPass != null && cfg.recommendedProxySettings) "include ${recommendedProxyConfig};"} } - '') locations); + '') (sortProperties (mapAttrsToList (k: v: v // { location = k; }) locations))); + mkBasicAuth = vhostName: authDef: let + htpasswdFile = pkgs.writeText "${vhostName}.htpasswd" ( + concatStringsSep "\n" (mapAttrsToList (user: password: '' + ${user}:{PLAIN}${password} + '') authDef) + ); + in '' + auth_basic secured; + auth_basic_user_file ${htpasswdFile}; + ''; + mkHtpasswd = vhostName: authDef: pkgs.writeText "${vhostName}.htpasswd" ( concatStringsSep "\n" (mapAttrsToList (user: password: '' ${user}:{PLAIN}${password} @@ -330,6 +341,35 @@ in "; }; + logError = mkOption { + default = "stderr"; + description = " + Configures logging. + The first parameter defines a file that will store the log. The + special value stderr selects the standard error file. Logging to + syslog can be configured by specifying the “syslog:” prefix. + The second parameter determines the level of logging, and can be + one of the following: debug, info, notice, warn, error, crit, + alert, or emerg. Log levels above are listed in the order of + increasing severity. Setting a certain log level will cause all + messages of the specified and more severe log levels to be logged. + If this parameter is omitted then error is used. + "; + }; + + preStart = mkOption { + type = types.lines; + default = '' + test -d ${cfg.stateDir}/logs || mkdir -m 750 -p ${cfg.stateDir}/logs + test `stat -c %a ${cfg.stateDir}` = "750" || chmod 750 ${cfg.stateDir} + test `stat -c %a ${cfg.stateDir}/logs` = "750" || chmod 750 ${cfg.stateDir}/logs + chown -R ${cfg.user}:${cfg.group} ${cfg.stateDir} + ''; + description = " + Shell commands executed before the service's nginx is started. + "; + }; + config = mkOption { default = ""; description = " @@ -597,9 +637,7 @@ in stopIfChanged = false; preStart = '' - mkdir -p ${cfg.stateDir}/logs - chmod 700 ${cfg.stateDir} - chown -R ${cfg.user}:${cfg.group} ${cfg.stateDir} + ${cfg.preStart} ${cfg.package}/bin/nginx -c ${configFile} -p ${cfg.stateDir} -t ''; serviceConfig = { diff --git a/nixos/modules/services/web-servers/nginx/location-options.nix b/nixos/modules/services/web-servers/nginx/location-options.nix index 4c772734a749..9b44433d3845 100644 --- a/nixos/modules/services/web-servers/nginx/location-options.nix +++ b/nixos/modules/services/web-servers/nginx/location-options.nix @@ -71,6 +71,16 @@ with lib; These lines go to the end of the location verbatim. ''; }; + + priority = mkOption { + type = types.int; + default = 1000; + description = '' + Order of this location block in relation to the others in the vhost. + The semantics are the same as with `lib.mkOrder`. Smaller values have + a greater priority. + ''; + }; }; } diff --git a/nixos/modules/services/web-servers/tomcat.nix b/nixos/modules/services/web-servers/tomcat.nix index d92ba72a8336..be54e9255c78 100644 --- a/nixos/modules/services/web-servers/tomcat.nix +++ b/nixos/modules/services/web-servers/tomcat.nix @@ -121,6 +121,11 @@ in type = types.str; description = "name of the virtualhost"; }; + aliases = mkOption { + type = types.listOf types.str; + description = "aliases of the virtualhost"; + default = []; + }; webapps = mkOption { type = types.listOf types.path; description = '' @@ -220,10 +225,28 @@ in ${if cfg.serverXml != "" then '' cp -f ${pkgs.writeTextDir "server.xml" cfg.serverXml}/* ${cfg.baseDir}/conf/ - '' else '' - # Create a modified server.xml which also includes all virtual hosts - sed -e "/<Engine name=\"Catalina\" defaultHost=\"localhost\">/a\ ${toString (map (virtualHost: ''<Host name=\"${virtualHost.name}\" appBase=\"virtualhosts/${virtualHost.name}/webapps\" unpackWARs=\"true\" autoDeploy=\"true\" xmlValidation=\"false\" xmlNamespaceAware=\"false\" >${if cfg.logPerVirtualHost then ''<Valve className=\"org.apache.catalina.valves.AccessLogValve\" directory=\"logs/${virtualHost.name}\" prefix=\"${virtualHost.name}_access_log.\" pattern=\"combined\" resolveHosts=\"false\"/>'' else ""}</Host>'') cfg.virtualHosts)}" \ - ${tomcat}/conf/server.xml > ${cfg.baseDir}/conf/server.xml + '' else + let + hostElementForVirtualHost = virtualHost: '' + <Host name="${virtualHost.name}" appBase="virtualhosts/${virtualHost.name}/webapps" + unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"> + '' + concatStrings (innerElementsForVirtualHost virtualHost) + '' + </Host> + ''; + innerElementsForVirtualHost = virtualHost: + (map (alias: '' + <Alias>${alias}</Alias> + '') virtualHost.aliases) + ++ (optional cfg.logPerVirtualHost '' + <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs/${virtualHost.name}" + prefix="${virtualHost.name}_access_log." pattern="combined" resolveHosts="false"/> + ''); + hostElementsString = concatMapStringsSep "\n" hostElementForVirtualHost cfg.virtualHosts; + hostElementsSedString = replaceStrings ["\n"] ["\\\n"] hostElementsString; + in '' + # Create a modified server.xml which also includes all virtual hosts + sed -e "/<Engine name=\"Catalina\" defaultHost=\"localhost\">/a\\"${escapeShellArg hostElementsSedString} \ + ${tomcat}/conf/server.xml > ${cfg.baseDir}/conf/server.xml '' } ${optionalString (cfg.logDirs != []) '' diff --git a/nixos/modules/services/x11/compton.nix b/nixos/modules/services/x11/compton.nix index 8641c05de52e..cafd8d88ec4d 100644 --- a/nixos/modules/services/x11/compton.nix +++ b/nixos/modules/services/x11/compton.nix @@ -238,6 +238,12 @@ in { description = "Compton composite manager"; wantedBy = [ "graphical-session.target" ]; partOf = [ "graphical-session.target" ]; + + # Temporarily fixes corrupt colours with Mesa 18 + environment = mkIf (cfg.backend == "glx") { + allow_rgb10_configs = "false"; + }; + serviceConfig = { ExecStart = "${cfg.package}/bin/compton --config ${configFile}"; RestartSec = 3; diff --git a/nixos/modules/services/x11/desktop-managers/enlightenment.nix b/nixos/modules/services/x11/desktop-managers/enlightenment.nix index 6fa3ec3b9255..04e380b61530 100644 --- a/nixos/modules/services/x11/desktop-managers/enlightenment.nix +++ b/nixos/modules/services/x11/desktop-managers/enlightenment.nix @@ -66,7 +66,7 @@ in ''; }]; - security.wrappers = (import (builtins.toPath "${e.enlightenment}/e-wrappers.nix")).security.wrappers; + security.wrappers = (import "${e.enlightenment}/e-wrappers.nix").security.wrappers; environment.etc = singleton { source = xcfg.xkbDir; diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix index faf5214130db..0d5b860d4617 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -110,6 +110,7 @@ in { services.gnome3.gnome-terminal-server.enable = mkDefault true; services.gnome3.gnome-user-share.enable = mkDefault true; services.gnome3.gvfs.enable = true; + services.gnome3.rygel.enable = mkDefault true; services.gnome3.seahorse.enable = mkDefault true; services.gnome3.sushi.enable = mkDefault true; services.gnome3.tracker.enable = mkDefault true; @@ -132,7 +133,6 @@ in { fonts.fonts = [ pkgs.dejavu_fonts pkgs.cantarell-fonts ]; - services.xserver.displayManager.gdm.enable = mkDefault true; services.xserver.displayManager.extraSessionFilePackages = [ pkgs.gnome3.gnome-session ]; services.xserver.displayManager.sessionCommands = '' diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix index d1cb962f6ff8..704cc78c1528 100644 --- a/nixos/modules/services/x11/desktop-managers/plasma5.nix +++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix @@ -64,7 +64,7 @@ in }; security.wrappers = { - kcheckpass.source = "${lib.getBin plasma5.plasma-workspace}/lib/libexec/kcheckpass"; + kcheckpass.source = "${lib.getBin plasma5.kscreenlocker}/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"; @@ -81,6 +81,7 @@ in kconfig kconfigwidgets kcoreaddons + kdoctools kdbusaddons kdeclarative kded @@ -184,10 +185,8 @@ in target = "X11/xkb"; }; - environment.variables = { - # Enable GTK applications to load SVG icons - GDK_PIXBUF_MODULE_FILE = "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"; - }; + # Enable GTK applications to load SVG icons + services.xserver.gdk-pixbuf.modulePackages = [ pkgs.librsvg ]; fonts.fonts = with pkgs; [ noto-fonts hack-font ]; fonts.fontconfig.defaultFonts = { @@ -224,11 +223,8 @@ in security.pam.services.sddm.enableKwallet = true; security.pam.services.slim.enableKwallet = true; - # Update the start menu for each user that has `isNormalUser` set. - system.activationScripts.plasmaSetup = stringAfter [ "users" "groups" ] - (concatStringsSep "\n" - (mapAttrsToList (name: value: "${pkgs.su}/bin/su ${name} -c ${pkgs.libsForQt5.kservice}/bin/kbuildsycoca5") - (filterAttrs (n: v: v.isNormalUser) config.users.users))); + # Update the start menu for each user that is currently logged in + system.userActivationScripts.plasmaSetup = "${pkgs.libsForQt5.kservice}/bin/kbuildsycoca5"; }) ]; diff --git a/nixos/modules/services/x11/desktop-managers/xfce.nix b/nixos/modules/services/x11/desktop-managers/xfce.nix index 75b9a76e1924..dabf09418da7 100644 --- a/nixos/modules/services/x11/desktop-managers/xfce.nix +++ b/nixos/modules/services/x11/desktop-managers/xfce.nix @@ -101,10 +101,11 @@ in ]; environment.variables = { - GDK_PIXBUF_MODULE_FILE = "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache"; GIO_EXTRA_MODULES = [ "${pkgs.xfce.gvfs}/lib/gio/modules" ]; }; + services.xserver.gdk-pixbuf.modulePackages = [ pkgs.librsvg ]; + services.xserver.desktopManager.session = [{ name = "xfce"; bgSupport = true; diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix index f561c5f8b7a9..26b79730dd38 100644 --- a/nixos/modules/services/x11/display-managers/default.nix +++ b/nixos/modules/services/x11/display-managers/default.nix @@ -222,6 +222,17 @@ in description = "List of arguments for the X server."; }; + setupCommands = mkOption { + type = types.lines; + default = ""; + description = '' + Shell commands executed just after the X server has started. + + This option is only effective for display managers for which this feature + is supported; currently these are LightDM, GDM and SDDM. + ''; + }; + sessionCommands = mkOption { type = types.lines; default = ""; @@ -266,7 +277,7 @@ in session. Each session script can set the <varname>waitPID</varname> shell variable to make this script wait until the end of the user session. Each script is used - to define either a windows manager or a desktop manager. These + to define either a window manager or a desktop manager. These can be differentiated by setting the attribute <varname>manage</varname> either to <literal>"window"</literal> or <literal>"desktop"</literal>. diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix index a775dd0f0e04..6cc30b218f4a 100644 --- a/nixos/modules/services/x11/display-managers/gdm.nix +++ b/nixos/modules/services/x11/display-managers/gdm.nix @@ -7,6 +7,13 @@ let cfg = config.services.xserver.displayManager; gdm = pkgs.gnome3.gdm; + xSessionWrapper = if (cfg.setupCommands == "") then null else + pkgs.writeScript "gdm-x-session-wrapper" '' + #!${pkgs.bash}/bin/bash + ${cfg.setupCommands} + exec "$@" + ''; + in { @@ -112,6 +119,11 @@ in GDM_SESSIONS_DIR = "${cfg.session.desktops}/share/xsessions"; # Find the mouse XCURSOR_PATH = "~/.icons:${pkgs.gnome3.adwaita-icon-theme}/share/icons"; + } // optionalAttrs (xSessionWrapper != null) { + # Make GDM use this wrapper before running the session, which runs the + # configured setupCommands. This relies on a patched GDM which supports + # this environment variable. + GDM_X_SESSION_WRAPPER = "${xSessionWrapper}"; }; execCmd = "exec ${gdm}/bin/gdm"; }; @@ -142,7 +154,10 @@ in systemd.user.services.dbus.wantedBy = [ "default.target" ]; - programs.dconf.profiles.gdm = "${gdm}/share/dconf/profile/gdm"; + programs.dconf.profiles.gdm = pkgs.writeText "dconf-gdm-profile" '' + system-db:local + ${gdm}/share/dconf/profile/gdm + ''; # Use AutomaticLogin if delay is zero, because it's immediate. # Otherwise with TimedLogin with zero seconds the prompt is still diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/enso-os.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/enso-os.nix new file mode 100644 index 000000000000..7c794b1ba175 --- /dev/null +++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/enso-os.nix @@ -0,0 +1,159 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + dmcfg = config.services.xserver.displayManager; + ldmcfg = dmcfg.lightdm; + cfg = ldmcfg.greeters.enso; + + theme = cfg.theme.package; + icons = cfg.iconTheme.package; + cursors = cfg.cursorTheme.package; + + # We need a few things in the environment for the greeter to run with + # fonts/icons. + wrappedEnsoGreeter = pkgs.runCommand "lightdm-enso-os-greeter" + { buildInputs = [ pkgs.makeWrapper ]; } + '' + # This wrapper ensures that we actually get themes + makeWrapper ${pkgs.lightdm-enso-os-greeter}/bin/pantheon-greeter \ + $out/greeter \ + --prefix PATH : "${pkgs.glibc.bin}/bin" \ + --set GDK_PIXBUF_MODULE_FILE "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache" \ + --set GTK_PATH "${theme}:${pkgs.gtk3.out}" \ + --set GTK_EXE_PREFIX "${theme}" \ + --set GTK_DATA_PREFIX "${theme}" \ + --set XDG_DATA_DIRS "${theme}/share:${icons}/share:${cursors}/share" \ + --set XDG_CONFIG_HOME "${theme}/share" + + cat - > $out/lightdm-enso-os-greeter.desktop << EOF + [Desktop Entry] + Name=LightDM Greeter + Comment=This runs the LightDM Greeter + Exec=$out/greeter + Type=Application + EOF + ''; + + ensoGreeterConf = pkgs.writeText "lightdm-enso-os-greeter.conf" '' + [greeter] + default-wallpaper=${ldmcfg.background} + gtk-theme=${cfg.theme.name} + icon-theme=${cfg.iconTheme.name} + cursor-theme=${cfg.cursorTheme.name} + blur=${toString cfg.blur} + brightness=${toString cfg.brightness} + ${cfg.extraConfig} + ''; +in { + options = { + services.xserver.displayManager.lightdm.greeters.enso = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable enso-os-greeter as the lightdm greeter + ''; + }; + + theme = { + package = mkOption { + type = types.package; + default = pkgs.gnome3.gnome-themes-extra; + defaultText = "pkgs.gnome3.gnome-themes-extra"; + description = '' + The package path that contains the theme given in the name option. + ''; + }; + + name = mkOption { + type = types.str; + default = "Adwaita"; + description = '' + Name of the theme to use for the lightdm-enso-os-greeter + ''; + }; + }; + + iconTheme = { + package = mkOption { + type = types.package; + default = pkgs.papirus-icon-theme; + defaultText = "pkgs.papirus-icon-theme"; + description = '' + The package path that contains the icon theme given in the name option. + ''; + }; + + name = mkOption { + type = types.str; + default = "ePapirus"; + description = '' + Name of the icon theme to use for the lightdm-enso-os-greeter + ''; + }; + }; + + cursorTheme = { + package = mkOption { + type = types.package; + default = pkgs.capitaine-cursors; + defaultText = "pkgs.capitaine-cursors"; + description = '' + The package path that contains the cursor theme given in the name option. + ''; + }; + + name = mkOption { + type = types.str; + default = "capitane-cursors"; + description = '' + Name of the cursor theme to use for the lightdm-enso-os-greeter + ''; + }; + }; + + blur = mkOption { + type = types.bool; + default = false; + description = '' + Whether or not to enable blur + ''; + }; + + brightness = mkOption { + type = types.int; + default = 7; + description = '' + Brightness + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra configuration that should be put in the greeter.conf + configuration file + ''; + }; + }; + }; + + config = mkIf (ldmcfg.enable && cfg.enable) { + environment.etc."lightdm/greeter.conf".source = ensoGreeterConf; + + services.xserver.displayManager.lightdm = { + greeter = mkDefault { + package = wrappedEnsoGreeter; + name = "lightdm-enso-os-greeter"; + }; + + greeters = { + gtk = { + enable = mkDefault false; + }; + }; + }; + }; +} diff --git a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix index 013956c05466..d1ee076e9185 100644 --- a/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix +++ b/nixos/modules/services/x11/display-managers/lightdm-greeters/gtk.nix @@ -22,7 +22,7 @@ let # This wrapper ensures that we actually get themes makeWrapper ${pkgs.lightdm_gtk_greeter}/sbin/lightdm-gtk-greeter \ $out/greeter \ - --prefix PATH : "${pkgs.glibc.bin}/bin" \ + --prefix PATH : "${lib.getBin pkgs.stdenv.cc.libc}/bin" \ --set GDK_PIXBUF_MODULE_FILE "${pkgs.librsvg.out}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache" \ --set GTK_PATH "${theme}:${pkgs.gtk3.out}" \ --set GTK_EXE_PREFIX "${theme}" \ diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix index cd9c3d81a0fb..a685dbfff2a0 100644 --- a/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixos/modules/services/x11/display-managers/lightdm.nix @@ -46,6 +46,7 @@ let greeters-directory = ${cfg.greeter.package} ''} sessions-directory = ${dmcfg.session.desktops}/share/xsessions + ${cfg.extraConfig} [Seat:*] xserver-command = ${xserverWrapper} @@ -61,6 +62,12 @@ let ${optionalString hasDefaultUserSession '' user-session=${defaultSessionName} ''} + ${optionalString (dmcfg.setupCommands != "") '' + display-setup-script=${pkgs.writeScript "lightdm-display-setup" '' + #!${pkgs.bash}/bin/bash + ${dmcfg.setupCommands} + ''} + ''} ${cfg.extraSeatDefaults} ''; @@ -73,6 +80,7 @@ in imports = [ ./lightdm-greeters/gtk.nix ./lightdm-greeters/mini.nix + ./lightdm-greeters/enso-os.nix ]; options = { @@ -113,6 +121,15 @@ in }; }; + extraConfig = mkOption { + type = types.lines; + default = ""; + example = '' + user-authority-in-system-dir = true + ''; + description = "Extra lines to append to LightDM section."; + }; + background = mkOption { type = types.str; default = "${pkgs.nixos-artwork.wallpapers.simple-dark-gray-bottom}/share/artwork/gnome/nix-wallpaper-simple-dark-gray_bottom.png"; @@ -197,7 +214,7 @@ in # lightdm relaunches itself via just `lightdm`, so needs to be on the PATH execCmd = '' export PATH=${lightdm}/sbin:$PATH - exec ${lightdm}/sbin/lightdm --log-dir=/var/log --run-dir=/run + exec ${lightdm}/sbin/lightdm ''; }; @@ -246,12 +263,19 @@ in ''; users.users.lightdm = { - createHome = true; - home = "/var/lib/lightdm-data"; + home = "/var/lib/lightdm"; group = "lightdm"; uid = config.ids.uids.lightdm; }; + systemd.tmpfiles.rules = [ + "d /run/lightdm 0711 lightdm lightdm 0" + "d /var/cache/lightdm 0711 root lightdm -" + "d /var/lib/lightdm 1770 lightdm lightdm -" + "d /var/lib/lightdm-data 1775 lightdm lightdm -" + "d /var/log/lightdm 0711 root lightdm -" + ]; + users.groups.lightdm.gid = config.ids.gids.lightdm; services.xserver.tty = null; # We might start multiple X servers so let the tty increment themselves.. services.xserver.display = null; # We specify our own display (and logfile) in xserver-wrapper up there diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix index 1635c0f9acc5..522a0dc92d6f 100644 --- a/nixos/modules/services/x11/display-managers/sddm.nix +++ b/nixos/modules/services/x11/display-managers/sddm.nix @@ -20,6 +20,7 @@ let Xsetup = pkgs.writeScript "Xsetup" '' #!/bin/sh ${cfg.setupScript} + ${dmcfg.setupCommands} ''; Xstop = pkgs.writeScript "Xstop" '' @@ -137,7 +138,8 @@ in xrandr --auto ''; description = '' - A script to execute when starting the display server. + A script to execute when starting the display server. DEPRECATED, please + use <option>services.xserver.displayManager.setupCommands</option>. ''; }; @@ -263,7 +265,9 @@ in }; environment.etc."sddm.conf".source = cfgFile; - environment.pathsToLink = [ "/share/sddm/themes" ]; + environment.pathsToLink = [ + "/share/sddm" + ]; users.groups.sddm.gid = config.ids.gids.sddm; diff --git a/nixos/modules/services/x11/display-managers/startx.nix b/nixos/modules/services/x11/display-managers/startx.nix new file mode 100644 index 000000000000..15609540a6e7 --- /dev/null +++ b/nixos/modules/services/x11/display-managers/startx.nix @@ -0,0 +1,44 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.xserver.displayManager.startx; + +in + +{ + + ###### interface + + options = { + services.xserver.displayManager.startx = { + enable = mkOption { + default = false; + description = '' + Whether to enable the dummy "startx" pseudo-display manager, + which allows users to start X manually via the "startx" command + from a vt shell. The X server runs under the user's id, not as root. + The user must provide a ~/.xinintrc file containing session startup + commands, see startx(1). This is not autmatically generated + from the desktopManager and windowManager settings. + ''; + }; + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + services.xserver = { + exportConfiguration = true; + displayManager.job.execCmd = ""; + displayManager.lightdm.enable = lib.mkForce false; + }; + systemd.services.display-manager.enable = false; + environment.systemPackages = with pkgs; [ xorg.xinit ]; + }; + +} diff --git a/nixos/modules/services/x11/gdk-pixbuf.nix b/nixos/modules/services/x11/gdk-pixbuf.nix new file mode 100644 index 000000000000..58faa8e2f9df --- /dev/null +++ b/nixos/modules/services/x11/gdk-pixbuf.nix @@ -0,0 +1,45 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.xserver.gdk-pixbuf; + + # Get packages to generate the cache for. We always include gdk_pixbuf. + effectivePackages = unique ([pkgs.gdk_pixbuf] ++ cfg.modulePackages); + + # Generate the cache file by running gdk-pixbuf-query-loaders for each + # package and concatenating the results. + loadersCache = pkgs.runCommand "gdk-pixbuf-loaders.cache" {} '' + ( + for package in ${concatStringsSep " " effectivePackages}; do + module_dir="$package/${pkgs.gdk_pixbuf.moduleDir}" + if [[ ! -d $module_dir ]]; then + echo "Warning (services.xserver.gdk-pixbuf): missing module directory $module_dir" 1>&2 + continue + fi + GDK_PIXBUF_MODULEDIR="$module_dir" \ + ${pkgs.gdk_pixbuf.dev}/bin/gdk-pixbuf-query-loaders + done + ) > "$out" + ''; +in + +{ + options = { + services.xserver.gdk-pixbuf.modulePackages = mkOption { + type = types.listOf types.package; + default = [ ]; + description = "Packages providing GDK-Pixbuf modules, for cache generation."; + }; + }; + + # If there is any package configured in modulePackages, we generate the + # loaders.cache based on that and set the environment variable + # GDK_PIXBUF_MODULE_FILE to point to it. + config = mkIf (cfg.modulePackages != []) { + environment.variables = { + GDK_PIXBUF_MODULE_FILE = "${loadersCache}"; + }; + }; +} diff --git a/nixos/modules/services/x11/hardware/libinput.nix b/nixos/modules/services/x11/hardware/libinput.nix index 072004d5dd91..58fe702d4969 100644 --- a/nixos/modules/services/x11/hardware/libinput.nix +++ b/nixos/modules/services/x11/hardware/libinput.nix @@ -205,7 +205,7 @@ in { }) ]; - services.udev.packages = [ pkgs.libinput ]; + services.udev.packages = [ pkgs.libinput.out ]; services.xserver.config = '' diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix index 75bfeaac1fa3..070a02473437 100644 --- a/nixos/modules/services/x11/xserver.nix +++ b/nixos/modules/services/x11/xserver.nix @@ -374,6 +374,12 @@ in description = "Contents of the first Monitor section of the X server configuration file."; }; + extraConfig = mkOption { + type = types.lines; + default = ""; + description = "Additional contents (sections) included in the X server configuration file"; + }; + xrandrHeads = mkOption { default = []; example = [ @@ -625,6 +631,8 @@ in ] ++ optional (elem "virtualbox" cfg.videoDrivers) xorg.xrefresh; + environment.pathsToLink = [ "/share/X11" ]; + xdg = { autostart.enable = true; menus.enable = true; @@ -754,6 +762,7 @@ in Driver "${driver.driverName or driver.name}" ${if cfg.useGlamor then ''Option "AccelMethod" "glamor"'' else ""} ${cfg.deviceSection} + ${driver.deviceSection or ""} ${xrandrDeviceSection} EndSection @@ -765,6 +774,7 @@ in ''} ${cfg.screenSection} + ${driver.screenSection or ""} ${optionalString (cfg.defaultDepth != 0) '' DefaultDepth ${toString cfg.defaultDepth} @@ -794,6 +804,8 @@ in '')} ${xrandrMonitorSections} + + ${cfg.extraConfig} ''; fonts.enableDefaultFonts = mkDefault true; diff --git a/nixos/modules/system/activation/activation-script.nix b/nixos/modules/system/activation/activation-script.nix index 93a1b13a81dd..0ed7c0f53eb9 100644 --- a/nixos/modules/system/activation/activation-script.nix +++ b/nixos/modules/system/activation/activation-script.nix @@ -21,7 +21,7 @@ let [ coreutils gnugrep findutils - glibc # needed for getent + getent shadow nettools # needed for hostname utillinux # needed for mount and mountpoint @@ -100,6 +100,52 @@ in exit $_status ''; }; + }; + + system.userActivationScripts = mkOption { + default = {}; + + example = literalExample '' + { plasmaSetup = { + text = ''' + ${pkgs.libsForQt5.kservice}/bin/kbuildsycoca5" + '''; + deps = []; + }; + } + ''; + + description = '' + A set of shell script fragments that are executed by a systemd user + service when a NixOS system configuration is activated. Examples are + rebuilding the .desktop file cache for showing applications in the menu. + Since these are executed every time you run + <command>nixos-rebuild</command>, it's important that they are + idempotent and fast. + ''; + + type = types.attrsOf types.unspecified; + + apply = set: { + script = '' + unset PATH + for i in ${toString path}; do + PATH=$PATH:$i/bin:$i/sbin + done + + _status=0 + trap "_status=1 _localstatus=\$?" ERR + + ${ + let + set' = mapAttrs (n: v: if isString v then noDepEntry v else v) set; + withHeadlines = addAttributeName set'; + in textClosureMap id (withHeadlines) (attrNames withHeadlines) + } + + exit $_status + ''; + }; }; @@ -128,14 +174,6 @@ in '' # Various log/runtime directories. - mkdir -m 0755 -p /run/nix/current-load # for distributed builds - mkdir -m 0700 -p /run/nix/remote-stores - - mkdir -m 0755 -p /var/log - - touch /var/log/wtmp /var/log/lastlog # must exist - chmod 644 /var/log/wtmp /var/log/lastlog - mkdir -m 1777 -p /var/tmp # Empty, immutable home directory of many system accounts. @@ -177,6 +215,14 @@ in source ${config.system.build.earlyMountScript} ''; + systemd.user = { + services.nixos-activation = { + description = "Run user specific NixOS activation"; + script = config.system.userActivationScripts.script; + unitConfig.ConditionUser = "!@system"; + serviceConfig.Type = "oneshot"; + }; + }; }; } diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl index b3fe6caf62dc..397b308b7311 100644 --- a/nixos/modules/system/activation/switch-to-configuration.pl +++ b/nixos/modules/system/activation/switch-to-configuration.pl @@ -419,7 +419,8 @@ while (my $f = <$listActiveUsers>) { my ($uid, $name) = ($+{uid}, $+{user}); print STDERR "reloading user units for $name...\n"; - system("su", "-l", $name, "-c", "XDG_RUNTIME_DIR=/run/user/$uid @systemd@/bin/systemctl --user daemon-reload"); + system("@su@", "-s", "@shell@", "-l", $name, "-c", "XDG_RUNTIME_DIR=/run/user/$uid @systemd@/bin/systemctl --user daemon-reload"); + system("@su@", "-s", "@shell@", "-l", $name, "-c", "XDG_RUNTIME_DIR=/run/user/$uid @systemd@/bin/systemctl --user start nixos-activation.service"); } close $listActiveUsers; diff --git a/nixos/modules/system/activation/top-level.nix b/nixos/modules/system/activation/top-level.nix index fff88e2c2bf3..a560af5ce96d 100644 --- a/nixos/modules/system/activation/top-level.nix +++ b/nixos/modules/system/activation/top-level.nix @@ -93,48 +93,53 @@ let ${config.system.extraSystemBuilderCmds} ''; - # Handle assertions - - failed = map (x: x.message) (filter (x: !x.assertion) config.assertions); - - showWarnings = res: fold (w: x: builtins.trace "[1;31mwarning: ${w}[0m" x) res config.warnings; - # Putting it all together. This builds a store path containing # symlinks to the various parts of the built configuration (the # kernel, systemd units, init scripts, etc.) as well as a script # `switch-to-configuration' that activates the configuration and # makes it bootable. - baseSystem = showWarnings ( - 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.nixos.label}"; - preferLocalBuild = true; - allowSubstitutes = false; - buildCommand = systemBuilder; - - inherit (pkgs) utillinux coreutils; - systemd = config.systemd.package; + baseSystem = pkgs.stdenvNoCC.mkDerivation { + name = let hn = config.networking.hostName; + nn = if (hn != "") then hn else "unnamed"; + in "nixos-system-${nn}-${config.system.nixos.label}"; + preferLocalBuild = true; + allowSubstitutes = false; + buildCommand = systemBuilder; + + inherit (pkgs) utillinux coreutils; + systemd = config.systemd.package; + shell = "${pkgs.bash}/bin/sh"; + su = "${pkgs.shadow.su}/bin/su"; + + inherit children; + kernelParams = config.boot.kernelParams; + installBootLoader = + 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.nixos.label; + + configurationName = config.boot.loader.grub.configurationName; + + # Needed by switch-to-configuration. + + perl = "${pkgs.perl}/bin/perl " + (concatMapStringsSep " " (lib: "-I${lib}/${pkgs.perl.libPrefix}") (with pkgs.perlPackages; [ FileSlurp NetDBus XMLParser XMLTwig ])); + }; - inherit children; - kernelParams = config.boot.kernelParams; - installBootLoader = - 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.nixos.label; + # Handle assertions and warnings - configurationName = config.boot.loader.grub.configurationName; + failedAssertions = map (x: x.message) (filter (x: !x.assertion) config.assertions); - # Needed by switch-to-configuration. + showWarnings = res: fold (w: x: builtins.trace "[1;31mwarning: ${w}[0m" x) res config.warnings; - perl = "${pkgs.perl}/bin/perl " + (concatMapStringsSep " " (lib: "-I${lib}/${pkgs.perl.libPrefix}") (with pkgs.perlPackages; [ FileSlurp NetDBus XMLParser XMLTwig ])); - } else throw "\nFailed assertions:\n${concatStringsSep "\n" (map (x: "- ${x}") failed)}"); + baseSystemAssertWarn = if failedAssertions != [] + then throw "\nFailed assertions:\n${concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}" + else showWarnings baseSystem; # Replace runtime dependencies system = fold ({ oldDependency, newDependency }: drv: pkgs.replaceDependency { inherit oldDependency newDependency drv; } - ) baseSystem config.system.replaceRuntimeDependencies; + ) baseSystemAssertWarn config.system.replaceRuntimeDependencies; in diff --git a/nixos/modules/system/boot/initrd-network.nix b/nixos/modules/system/boot/initrd-network.nix index 384ae909b701..dd0ea69e9685 100644 --- a/nixos/modules/system/boot/initrd-network.nix +++ b/nixos/modules/system/boot/initrd-network.nix @@ -6,11 +6,22 @@ let cfg = config.boot.initrd.network; + dhcpinterfaces = lib.attrNames (lib.filterAttrs (iface: v: v.useDHCP == true) (config.networking.interfaces or {})); + udhcpcScript = pkgs.writeScript "udhcp-script" '' #! /bin/sh if [ "$1" = bound ]; then ip address add "$ip/$mask" dev "$interface" + if [ -n "$mtu" ]; then + ip link set mtu "$mtu" dev "$interface" + fi + if [ -n "$staticroutes" ]; then + echo "$staticroutes" \ + | sed -r "s@(\S+) (\S+)@ ip route add \"\1\" via \"\2\" dev \"$interface\" ; @g" \ + | sed -r "s@ via \"0\.0\.0\.0\"@@g" \ + | /bin/sh + fi if [ -n "$router" ]; then ip route add "$router" dev "$interface" # just in case if "$router" is not within "$ip/$mask" (e.g. Hetzner Cloud) ip route add default via "$router" dev "$interface" @@ -93,18 +104,24 @@ in '' # Otherwise, use DHCP. - + optionalString config.networking.useDHCP '' + + optionalString (config.networking.useDHCP || dhcpinterfaces != []) '' if [ -z "$hasNetwork" ]; then # Bring up all interfaces. - for iface in $(cd /sys/class/net && ls); do + for iface in $(ls /sys/class/net/); do echo "bringing up network interface $iface..." ip link set "$iface" up done - # Acquire a DHCP lease. - echo "acquiring IP address via DHCP..." - udhcpc --quit --now --script ${udhcpcScript} ${udhcpcArgs} && hasNetwork=1 + # Acquire DHCP leases. + for iface in ${ if config.networking.useDHCP then + "$(ls /sys/class/net/ | grep -v ^lo$)" + else + lib.concatMapStringsSep " " lib.escapeShellArg dhcpinterfaces + }; do + echo "acquiring IP address via DHCP on $iface..." + udhcpc --quit --now -i $iface -O staticroutes --script ${udhcpcScript} ${udhcpcArgs} && hasNetwork=1 + done fi '' diff --git a/nixos/modules/system/boot/kexec.nix b/nixos/modules/system/boot/kexec.nix index 3e5d7b40f2c5..61f9c6d0e7eb 100644 --- a/nixos/modules/system/boot/kexec.nix +++ b/nixos/modules/system/boot/kexec.nix @@ -1,7 +1,7 @@ { pkgs, lib, ... }: { - config = lib.mkIf (pkgs.kexectools.meta.available) { + config = lib.mkIf (lib.any (lib.meta.platformMatch pkgs.stdenv.hostPlatform) pkgs.kexectools.meta.platforms) { environment.systemPackages = [ pkgs.kexectools ]; systemd.services."prepare-kexec" = diff --git a/nixos/modules/system/boot/loader/raspberrypi/builder_uboot.sh b/nixos/modules/system/boot/loader/raspberrypi/builder_uboot.sh deleted file mode 100644 index 36bf15066274..000000000000 --- a/nixos/modules/system/boot/loader/raspberrypi/builder_uboot.sh +++ /dev/null @@ -1,29 +0,0 @@ -#! @bash@/bin/sh -e - -copyForced() { - local src="$1" - local dst="$2" - cp $src $dst.tmp - mv $dst.tmp $dst -} - -# Call the extlinux builder -"@extlinuxConfBuilder@" "$@" - -# Add the firmware files -fwdir=@firmware@/share/raspberrypi/boot/ -copyForced $fwdir/bootcode.bin /boot/bootcode.bin -copyForced $fwdir/fixup.dat /boot/fixup.dat -copyForced $fwdir/fixup_cd.dat /boot/fixup_cd.dat -copyForced $fwdir/fixup_db.dat /boot/fixup_db.dat -copyForced $fwdir/fixup_x.dat /boot/fixup_x.dat -copyForced $fwdir/start.elf /boot/start.elf -copyForced $fwdir/start_cd.elf /boot/start_cd.elf -copyForced $fwdir/start_db.elf /boot/start_db.elf -copyForced $fwdir/start_x.elf /boot/start_x.elf - -# Add the uboot file -copyForced @uboot@/u-boot.bin /boot/u-boot-rpi.bin - -# Add the config.txt -copyForced @configTxt@ /boot/config.txt diff --git a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi-builder.nix b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi-builder.nix new file mode 100644 index 000000000000..7eb52e3d021f --- /dev/null +++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi-builder.nix @@ -0,0 +1,10 @@ +{ pkgs, configTxt }: + +pkgs.substituteAll { + src = ./raspberrypi-builder.sh; + isExecutable = true; + inherit (pkgs) bash; + path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep]; + firmware = pkgs.raspberrypifw; + inherit configTxt; +} diff --git a/nixos/modules/system/boot/loader/raspberrypi/builder.sh b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi-builder.sh index 8adc8a6a7e11..0fb07de10c04 100644 --- a/nixos/modules/system/boot/loader/raspberrypi/builder.sh +++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi-builder.sh @@ -5,15 +5,25 @@ shopt -s nullglob export PATH=/empty for i in @path@; do PATH=$PATH:$i/bin; done -default=$1 -if test -z "$1"; then - echo "Syntax: builder.sh <DEFAULT-CONFIG>" +usage() { + echo "usage: $0 -c <path-to-default-configuration> [-d <boot-dir>]" >&2 exit 1 -fi +} + +default= # Default configuration +target=/boot # Target directory + +while getopts "c:d:" opt; do + case "$opt" in + c) default="$OPTARG" ;; + d) target="$OPTARG" ;; + \?) usage ;; + esac +done echo "updating the boot generations directory..." -mkdir -p /boot/old +mkdir -p $target/old # Convert a path to a file in the Nix store such as # /nix/store/<hash>-<name>/file to <hash>-<name>-<file>. @@ -22,12 +32,12 @@ cleanName() { echo "$path" | sed 's|^/nix/store/||' | sed 's|/|-|g' } -# Copy a file from the Nix store to /boot/kernels. +# Copy a file from the Nix store to $target/kernels. declare -A filesCopied copyToKernelsDir() { local src="$1" - local dst="/boot/old/$(cleanName $src)" + local dst="$target/old/$(cleanName $src)" # Don't copy the file if $dst already exists. This means that we # have to create $dst atomically to prevent partially copied # kernels or initrd if this script is ever interrupted. @@ -47,10 +57,10 @@ copyForced() { mv $dst.tmp $dst } -outdir=/boot/old +outdir=$target/old mkdir -p $outdir || true -# Copy its kernel and initrd to /boot/kernels. +# Copy its kernel and initrd to $target/old. addEntry() { local path="$1" local generation="$2" @@ -74,25 +84,21 @@ addEntry() { echo $initrd > $outdir/$generation-initrd echo $kernel > $outdir/$generation-kernel - if test $(readlink -f "$path") = "$default"; then - if [ @version@ -eq 1 ]; then - copyForced $kernel /boot/kernel.img - else - copyForced $kernel /boot/kernel7.img - fi - copyForced $initrd /boot/initrd - for dtb in $dtb_path/bcm*.dtb; do - dst="/boot/$(basename $dtb)" + if test "$generation" = "default"; then + copyForced $kernel $target/kernel.img + copyForced $initrd $target/initrd + for dtb in $dtb_path/{broadcom,}/bcm*.dtb; do + dst="$target/$(basename $dtb)" copyForced $dtb "$dst" filesCopied[$dst]=1 done - cp "$(readlink -f "$path/init")" /boot/nixos-init - echo "`cat $path/kernel-params` init=$path/init" >/boot/cmdline.txt - - echo "$2" > /boot/defaultgeneration + cp "$(readlink -f "$path/init")" $target/nixos-init + echo "`cat $path/kernel-params` init=$path/init" >$target/cmdline.txt fi } +addEntry $default default + # Add all generations of the system profile to the menu, in reverse # (most recent to least recent) order. for generation in $( @@ -105,21 +111,21 @@ done # Add the firmware files fwdir=@firmware@/share/raspberrypi/boot/ -copyForced $fwdir/bootcode.bin /boot/bootcode.bin -copyForced $fwdir/fixup.dat /boot/fixup.dat -copyForced $fwdir/fixup_cd.dat /boot/fixup_cd.dat -copyForced $fwdir/fixup_db.dat /boot/fixup_db.dat -copyForced $fwdir/fixup_x.dat /boot/fixup_x.dat -copyForced $fwdir/start.elf /boot/start.elf -copyForced $fwdir/start_cd.elf /boot/start_cd.elf -copyForced $fwdir/start_db.elf /boot/start_db.elf -copyForced $fwdir/start_x.elf /boot/start_x.elf +copyForced $fwdir/bootcode.bin $target/bootcode.bin +copyForced $fwdir/fixup.dat $target/fixup.dat +copyForced $fwdir/fixup_cd.dat $target/fixup_cd.dat +copyForced $fwdir/fixup_db.dat $target/fixup_db.dat +copyForced $fwdir/fixup_x.dat $target/fixup_x.dat +copyForced $fwdir/start.elf $target/start.elf +copyForced $fwdir/start_cd.elf $target/start_cd.elf +copyForced $fwdir/start_db.elf $target/start_db.elf +copyForced $fwdir/start_x.elf $target/start_x.elf # Add the config.txt -copyForced @configTxt@ /boot/config.txt +copyForced @configTxt@ $target/config.txt -# Remove obsolete files from /boot and /boot/old. -for fn in /boot/old/*linux* /boot/old/*initrd-initrd* /boot/bcm*.dtb; do +# Remove obsolete files from $target and $target/old. +for fn in $target/old/*linux* $target/old/*initrd-initrd* $target/bcm*.dtb; do if ! test "${filesCopied[$fn]}" = 1; then rm -vf -- "$fn" fi diff --git a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix index 9bec24c53f5b..7e089507ff20 100644 --- a/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix +++ b/nixos/modules/system/boot/loader/raspberrypi/raspberrypi.nix @@ -5,25 +5,16 @@ with lib; let cfg = config.boot.loader.raspberryPi; - builderGeneric = pkgs.substituteAll { - src = ./builder.sh; - isExecutable = true; - inherit (pkgs) bash; - path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep]; - firmware = pkgs.raspberrypifw; - version = cfg.version; - inherit configTxt; - }; - inherit (pkgs.stdenv.hostPlatform) platform; - builderUboot = import ./builder_uboot.nix { inherit config; inherit pkgs; inherit configTxt; }; + builderUboot = import ./uboot-builder.nix { inherit pkgs configTxt; inherit (cfg) version; }; + builderGeneric = import ./raspberrypi-builder.nix { inherit pkgs configTxt; }; builder = if cfg.uboot.enable then "${builderUboot} -g ${toString cfg.uboot.configurationLimit} -t ${timeoutStr} -c" else - builderGeneric; + "${builderGeneric} -c"; blCfg = config.boot.loader; timeoutStr = if blCfg.timeout == null then "-1" else toString blCfg.timeout; @@ -43,9 +34,12 @@ let '' + optional isAarch64 '' # Boot in 64-bit mode. arm_control=0x200 - '' + optional cfg.uboot.enable '' + '' + (if cfg.uboot.enable then '' kernel=u-boot-rpi.bin - '' + optional (cfg.firmwareConfig != null) cfg.firmwareConfig); + '' else '' + kernel=kernel.img + initramfs initrd followkernel + '') + optional (cfg.firmwareConfig != null) cfg.firmwareConfig); in @@ -65,7 +59,7 @@ in version = mkOption { default = 2; - type = types.enum [ 1 2 3 ]; + type = types.enum [ 0 1 2 3 ]; description = '' ''; }; diff --git a/nixos/modules/system/boot/loader/raspberrypi/builder_uboot.nix b/nixos/modules/system/boot/loader/raspberrypi/uboot-builder.nix index 47f25a9c2b1b..e929c33c6ee3 100644 --- a/nixos/modules/system/boot/loader/raspberrypi/builder_uboot.nix +++ b/nixos/modules/system/boot/loader/raspberrypi/uboot-builder.nix @@ -1,13 +1,14 @@ -{ config, pkgs, configTxt }: +{ pkgs, version, configTxt }: let - cfg = config.boot.loader.raspberryPi; isAarch64 = pkgs.stdenv.isAarch64; uboot = - if cfg.version == 1 then + if version == 0 then + pkgs.ubootRaspberryPiZero + else if version == 1 then pkgs.ubootRaspberryPi - else if cfg.version == 2 then + else if version == 2 then pkgs.ubootRaspberryPi2 else if isAarch64 then @@ -21,7 +22,7 @@ let }; in pkgs.substituteAll { - src = ./builder_uboot.sh; + src = ./uboot-builder.sh; isExecutable = true; inherit (pkgs) bash; path = [pkgs.coreutils pkgs.gnused pkgs.gnugrep]; @@ -29,6 +30,6 @@ pkgs.substituteAll { inherit uboot; inherit configTxt; inherit extlinuxConfBuilder; - version = cfg.version; + inherit version; } diff --git a/nixos/modules/system/boot/loader/raspberrypi/uboot-builder.sh b/nixos/modules/system/boot/loader/raspberrypi/uboot-builder.sh new file mode 100644 index 000000000000..ea591427179f --- /dev/null +++ b/nixos/modules/system/boot/loader/raspberrypi/uboot-builder.sh @@ -0,0 +1,38 @@ +#! @bash@/bin/sh -e + +target=/boot # Target directory + +while getopts "t:c:d:g:" opt; do + case "$opt" in + d) target="$OPTARG" ;; + *) ;; + esac +done + +copyForced() { + local src="$1" + local dst="$2" + cp $src $dst.tmp + mv $dst.tmp $dst +} + +# Call the extlinux builder +"@extlinuxConfBuilder@" "$@" + +# Add the firmware files +fwdir=@firmware@/share/raspberrypi/boot/ +copyForced $fwdir/bootcode.bin $target/bootcode.bin +copyForced $fwdir/fixup.dat $target/fixup.dat +copyForced $fwdir/fixup_cd.dat $target/fixup_cd.dat +copyForced $fwdir/fixup_db.dat $target/fixup_db.dat +copyForced $fwdir/fixup_x.dat $target/fixup_x.dat +copyForced $fwdir/start.elf $target/start.elf +copyForced $fwdir/start_cd.elf $target/start_cd.elf +copyForced $fwdir/start_db.elf $target/start_db.elf +copyForced $fwdir/start_x.elf $target/start_x.elf + +# Add the uboot file +copyForced @uboot@/u-boot.bin $target/u-boot-rpi.bin + +# Add the config.txt +copyForced @configTxt@ $target/config.txt diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix index ed8b9f01e275..018e7b2e7f89 100644 --- a/nixos/modules/system/boot/luksroot.nix +++ b/nixos/modules/system/boot/luksroot.nix @@ -7,8 +7,19 @@ let commonFunctions = '' die() { - echo "$@" >&2 - exit 1 + echo "$@" >&2 + exit 1 + } + + dev_exist() { + local target="$1" + if [ -e $target ]; then + return 0 + else + local uuid=$(echo -n $target | sed -e 's,UUID=\(.*\),\1,g') + blkid --uuid $uuid >/dev/null + return $? + fi } wait_target() { @@ -17,13 +28,13 @@ let local secs="''${3:-10}" local desc="''${4:-$name $target to appear}" - if [ ! -e $target ]; then + if ! dev_exist $target; then echo -n "Waiting $secs seconds for $desc..." local success=false; for try in $(seq $secs); do echo -n "." sleep 1 - if [ -e $target ]; then + if dev_exist $target; then success=true break fi @@ -40,30 +51,30 @@ let } wait_yubikey() { - local secs="''${1:-10}" - - ykinfo -v 1>/dev/null 2>&1 - if [ $? != 0 ]; then - echo -n "Waiting $secs seconds for Yubikey to appear..." - local success=false - for try in $(seq $secs); do - echo -n . - sleep 1 - ykinfo -v 1>/dev/null 2>&1 - if [ $? == 0 ]; then - success=true - break - fi - done - if [ $success == true ]; then - echo " - success"; - return 0 - else - echo " - failure"; - return 1 - fi - fi - return 0 + local secs="''${1:-10}" + + ykinfo -v 1>/dev/null 2>&1 + if [ $? != 0 ]; then + echo -n "Waiting $secs seconds for Yubikey to appear..." + local success=false + for try in $(seq $secs); do + echo -n . + sleep 1 + ykinfo -v 1>/dev/null 2>&1 + if [ $? == 0 ]; then + success=true + break + fi + done + if [ $success == true ]; then + echo " - success"; + return 0 + else + echo " - failure"; + return 1 + fi + fi + return 0 } ''; diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index 4bacf0f126a4..63a6f7fbe099 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -208,7 +208,6 @@ let "InitialCongestionWindow" "InitialAdvertisedReceiveWindow" "QuickAck" "MTUBytes" ]) - (assertHasField "Gateway") ]; checkDhcp = checkUnitConfig "DHCP" [ @@ -249,13 +248,14 @@ let # .network files have a [Link] section with different options than in .netlink files checkNetworkLink = checkUnitConfig "Link" [ (assertOnlyFields [ - "MACAddress" "MTUBytes" "ARP" "Unmanaged" "RequiredForOnline" + "MACAddress" "MTUBytes" "ARP" "Multicast" "Unmanaged" "RequiredForOnline" ]) (assertMacAddress "MACAddress") (assertByteFormat "MTUBytes") (assertValueOneOf "ARP" boolValues) + (assertValueOneOf "Multicast" boolValues) (assertValueOneOf "Unmanaged" boolValues) - (assertValueOneOf "RquiredForOnline" boolValues) + (assertValueOneOf "RequiredForOnline" boolValues) ]; diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index f58b68cb3353..e7167999a6f8 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -147,7 +147,7 @@ let ${config.boot.initrd.extraUtilsCommands} # Copy ld manually since it isn't detected correctly - cp -pv ${pkgs.glibc.out}/lib/ld*.so.? $out/lib + cp -pv ${pkgs.stdenv.cc.libc.out}/lib/ld*.so.? $out/lib # Copy all of the needed libraries find $out/bin $out/lib -type f | while read BIN; do @@ -251,9 +251,9 @@ let postInstall = '' echo checking syntax # check both with bash - ${pkgs.bash}/bin/sh -n $target + ${pkgs.buildPackages.bash}/bin/sh -n $target # and with ash shell, just in case - ${extraUtils}/bin/ash -n $target + ${pkgs.buildPackages.busybox}/bin/ash -n $target ''; inherit udevRules extraUtils modulesClosure; diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh index 49764b75a557..03daafa1ce4f 100644 --- a/nixos/modules/system/boot/stage-2-init.sh +++ b/nixos/modules/system/boot/stage-2-init.sh @@ -152,6 +152,14 @@ ln -sfn /run/booted-system /nix/var/nix/gcroots/booted-system @shell@ @postBootCommands@ +# Ensure systemd doesn't try to populate /etc, by forcing its first-boot +# heuristic off. It doesn't matter what's in /etc/machine-id for this purpose, +# and systemd will immediately fill in the file when it starts, so just +# creating it is enough. This `: >>` pattern avoids forking and avoids changing +# the mtime if the file already exists. +: >> /etc/machine-id + + # Reset the logging file descriptors. exec 1>&$logOutFd 2>&$logErrFd exec {logOutFd}>&- {logErrFd}>&- diff --git a/nixos/modules/system/boot/systemd-lib.nix b/nixos/modules/system/boot/systemd-lib.nix index 9c8d4a026b4a..68a40377ee13 100644 --- a/nixos/modules/system/boot/systemd-lib.nix +++ b/nixos/modules/system/boot/systemd-lib.nix @@ -63,7 +63,7 @@ in rec { assertValueOneOf = name: values: group: attr: optional (attr ? ${name} && !elem attr.${name} values) - "Systemd ${group} field `${name}' cannot have value `${attr.${name}}'."; + "Systemd ${group} field `${name}' cannot have value `${toString attr.${name}}'."; assertHasField = name: group: attr: optional (!(attr ? ${name})) diff --git a/nixos/modules/system/boot/systemd-nspawn.nix b/nixos/modules/system/boot/systemd-nspawn.nix index 83fef8354360..4f538ccdbbe1 100644 --- a/nixos/modules/system/boot/systemd-nspawn.nix +++ b/nixos/modules/system/boot/systemd-nspawn.nix @@ -112,9 +112,7 @@ in { environment.etc."systemd/nspawn".source = generateUnits "nspawn" units [] []; - systemd.services."systemd-nspawn@" = { - wantedBy = [ "machine.target" ]; - }; + systemd.targets."multi-user".wants = [ "machines.target "]; }; } diff --git a/nixos/modules/system/boot/systemd-unit-options.nix b/nixos/modules/system/boot/systemd-unit-options.nix index 2cff25a8c854..5f2bec5c34ae 100644 --- a/nixos/modules/system/boot/systemd-unit-options.nix +++ b/nixos/modules/system/boot/systemd-unit-options.nix @@ -394,7 +394,7 @@ in rec { Each attribute in this set specifies an option in the <literal>[Timer]</literal> section of the unit. See <citerefentry><refentrytitle>systemd.timer</refentrytitle> - <manvolnum>7</manvolnum></citerefentry> and + <manvolnum>5</manvolnum></citerefentry> and <citerefentry><refentrytitle>systemd.time</refentrytitle> <manvolnum>7</manvolnum></citerefentry> for details. ''; diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 12e029ae57f8..89f8e8153550 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -387,7 +387,7 @@ let logindHandlerType = types.enum [ "ignore" "poweroff" "reboot" "halt" "kexec" "suspend" - "hibernate" "hybrid-sleep" "lock" + "hibernate" "hybrid-sleep" "suspend-then-hibernate" "lock" ]; in @@ -587,6 +587,15 @@ in ''; }; + services.journald.forwardToSyslog = mkOption { + default = config.services.rsyslogd.enable || config.services.syslog-ng.enable; + defaultText = "config.services.rsyslogd.enable || config.services.syslog-ng.enable"; + type = types.bool; + description = '' + Whether to forward log messages to syslog. + ''; + }; + services.logind.extraConfig = mkOption { default = ""; type = types.lines; @@ -747,12 +756,16 @@ in "systemd/journald.conf".text = '' [Journal] + Storage=persistent RateLimitInterval=${config.services.journald.rateLimitInterval} RateLimitBurst=${toString config.services.journald.rateLimitBurst} ${optionalString (config.services.journald.console != "") '' ForwardToConsole=yes TTYPath=${config.services.journald.console} ''} + ${optionalString (config.services.journald.forwardToSyslog) '' + ForwardToSyslog=yes + ''} ${config.services.journald.extraConfig} ''; @@ -783,19 +796,6 @@ in services.dbus.enable = true; - system.activationScripts.systemd = stringAfter [ "groups" ] - '' - mkdir -m 0755 -p /var/lib/udev - - if ! [ -e /etc/machine-id ]; then - ${systemd}/bin/systemd-machine-id-setup - fi - - # Keep a persistent journal. Note that systemd-tmpfiles will - # set proper ownership/permissions. - mkdir -m 0700 -p /var/log/journal - ''; - users.users.systemd-network.uid = config.ids.uids.systemd-network; users.groups.systemd-network.gid = config.ids.gids.systemd-network; users.users.systemd-resolve.uid = config.ids.uids.systemd-resolve; @@ -886,6 +886,9 @@ in #systemd.services.systemd-logind.restartTriggers = [ config.environment.etc."systemd/logind.conf".source ]; systemd.services.systemd-logind.restartIfChanged = false; systemd.services.systemd-logind.stopIfChanged = false; + # The user-runtime-dir@ service is managed by systemd-logind we should not touch it or else we break the users' sessions. + systemd.services."user-runtime-dir@".stopIfChanged = false; + systemd.services."user-runtime-dir@".restartIfChanged = false; systemd.services.systemd-journald.restartTriggers = [ config.environment.etc."systemd/journald.conf".source ]; systemd.services.systemd-journald.stopIfChanged = false; systemd.targets.local-fs.unitConfig.X-StopOnReconfiguration = true; diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix index 2b3b09d725c7..8f8c9e23e13e 100644 --- a/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixos/modules/tasks/filesystems/zfs.nix @@ -74,7 +74,7 @@ let importLib = {zpoolCmd, awkCmd, cfgZfs}: '' poolReady() { pool="$1" - state="$("${zpoolCmd}" import | "${awkCmd}" "/pool: $pool/ { found = 1 }; /state:/ { if (found == 1) { print \$2; exit } }; END { if (found == 0) { print \"MISSING\" } }")" + state="$("${zpoolCmd}" import 2>/dev/null | "${awkCmd}" "/pool: $pool/ { found = 1 }; /state:/ { if (found == 1) { print \$2; exit } }; END { if (found == 0) { print \"MISSING\" } }")" if [[ "$state" = "ONLINE" ]]; then return 0 else diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index af61c95da0af..93dfefdce902 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -85,7 +85,8 @@ let after = [ "network-pre.target" "systemd-udevd.service" "systemd-sysctl.service" ]; before = [ "network.target" "shutdown.target" ]; wants = [ "network.target" ]; - partOf = map (i: "network-addresses-${i.name}.service") interfaces; + # exclude bridges from the partOf relationship to fix container networking bug #47210 + partOf = map (i: "network-addresses-${i.name}.service") (filter (i: !(hasAttr i.name cfg.bridges)) interfaces); conflicts = [ "shutdown.target" ]; wantedBy = [ "multi-user.target" ] ++ optional hasDefaultGatewaySet "network-online.target"; diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index 20a740ce1f0c..815523093dde 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -341,7 +341,7 @@ in You should try to make this ID unique among your machines. You can generate a random 32-bit ID using the following commands: - <literal>cksum /etc/machine-id | while read c rest; do printf "%x" $c; done</literal> + <literal>head -c 8 /etc/machine-id</literal> (this derives it from the machine-id that systemd generates) or diff --git a/nixos/modules/testing/test-instrumentation.nix b/nixos/modules/testing/test-instrumentation.nix index ed4cfa7805e2..aa0db4afd978 100644 --- a/nixos/modules/testing/test-instrumentation.nix +++ b/nixos/modules/testing/test-instrumentation.nix @@ -55,7 +55,8 @@ with import ../../lib/qemu-flags.nix { inherit pkgs; }; systemd.services."serial-getty@hvc0".enable = false; # Only use a serial console, no TTY. - virtualisation.qemu.consoles = [ qemuSerialDevice ]; + # hvc1: socket backdoor, see "Debugging NixOS tests" section in NixOS manual + virtualisation.qemu.consoles = [ "hvc1" qemuSerialDevice ]; boot.initrd.preDeviceCommands = '' diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix index e9e935e90202..c92570582f20 100644 --- a/nixos/modules/virtualisation/amazon-image.nix +++ b/nixos/modules/virtualisation/amazon-image.nix @@ -145,8 +145,12 @@ let cfg = config.ec2; in environment.systemPackages = [ pkgs.cryptsetup ]; boot.initrd.supportedFilesystems = [ "unionfs-fuse" ]; - + # EC2 has its own NTP server provided by the hypervisor networking.timeServers = [ "169.254.169.123" ]; + + # udisks has become too bloated to have in a headless system + # (e.g. it depends on GTK+). + services.udisks2.enable = false; }; } diff --git a/nixos/modules/virtualisation/container-config.nix b/nixos/modules/virtualisation/container-config.nix index 5e368acd6d8b..561db7cabcfb 100644 --- a/nixos/modules/virtualisation/container-config.nix +++ b/nixos/modules/virtualisation/container-config.nix @@ -22,6 +22,13 @@ with lib; # Not supported in systemd-nspawn containers. security.audit.enable = false; + # Make sure that root user in container will talk to host nix-daemon + environment.etc."profile".text = '' + export NIX_REMOTE=daemon + ''; + + + }; } diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix index b91165ce3b82..2fcc0f254256 100644 --- a/nixos/modules/virtualisation/containers.nix +++ b/nixos/modules/virtualisation/containers.nix @@ -130,6 +130,7 @@ let --bind-ro=/nix/var/nix/daemon-socket \ --bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles" \ --bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots" \ + --link-journal=try-guest \ --setenv PRIVATE_NETWORK="$PRIVATE_NETWORK" \ --setenv HOST_BRIDGE="$HOST_BRIDGE" \ --setenv HOST_ADDRESS="$HOST_ADDRESS" \ @@ -242,6 +243,9 @@ let Restart = "on-failure"; + Slice = "machine.slice"; + Delegate = true; + # Hack: we don't want to kill systemd-nspawn, since we call # "machinectl poweroff" in preStop to shut down the # container cleanly. But systemd requires sending a signal @@ -605,7 +609,7 @@ in { config = { config, pkgs, ... }: { services.postgresql.enable = true; - services.postgresql.package = pkgs.postgresql96; + services.postgresql.package = pkgs.postgresql_9_6; system.stateVersion = "17.03"; }; @@ -656,6 +660,8 @@ in serviceConfig = serviceDirectives dummyConfig; }; in { + systemd.targets."multi-user".wants = [ "machines.target" ]; + systemd.services = listToAttrs (filter (x: x.value != null) ( # The generic container template used by imperative containers [{ name = "container@"; value = unit; }] @@ -679,7 +685,7 @@ in } // ( if config.autoStart then { - wantedBy = [ "multi-user.target" ]; + wantedBy = [ "machines.target" ]; wants = [ "network.target" ]; after = [ "network.target" ]; restartTriggers = [ config.path ]; diff --git a/nixos/modules/virtualisation/ec2-amis.nix b/nixos/modules/virtualisation/ec2-amis.nix index 76facac39fc6..aaea06bb9a63 100644 --- a/nixos/modules/virtualisation/ec2-amis.nix +++ b/nixos/modules/virtualisation/ec2-amis.nix @@ -257,5 +257,22 @@ let self = { "18.03".sa-east-1.hvm-ebs = "ami-163e1f7a"; "18.03".ap-south-1.hvm-ebs = "ami-6a390b05"; - latest = self."18.03"; + # 18.09.910.c15e342304a + "18.09".eu-west-1.hvm-ebs = "ami-0f412186fb8a0ec97"; + "18.09".eu-west-2.hvm-ebs = "ami-0dada3805ce43c55e"; + "18.09".eu-west-3.hvm-ebs = "ami-074df85565f2e02e2"; + "18.09".eu-central-1.hvm-ebs = "ami-07c9b884e679df4f8"; + "18.09".us-east-1.hvm-ebs = "ami-009c9c3f1af480ff3"; + "18.09".us-east-2.hvm-ebs = "ami-08199961085ea8bc6"; + "18.09".us-west-1.hvm-ebs = "ami-07aa7f56d612ddd38"; + "18.09".us-west-2.hvm-ebs = "ami-01c84b7c368ac24d1"; + "18.09".ca-central-1.hvm-ebs = "ami-04f66113f76198f6c"; + "18.09".ap-southeast-1.hvm-ebs = "ami-0892c7e24ebf2194f"; + "18.09".ap-southeast-2.hvm-ebs = "ami-010730f36424b0a2c"; + "18.09".ap-northeast-1.hvm-ebs = "ami-0cdba8e998f076547"; + "18.09".ap-northeast-2.hvm-ebs = "ami-0400a698e6a9f4a15"; + "18.09".sa-east-1.hvm-ebs = "ami-0e4a8a47fd6db6112"; + "18.09".ap-south-1.hvm-ebs = "ami-0880a678d3f555313"; + + latest = self."18.09"; }; in self diff --git a/nixos/modules/virtualisation/google-compute-image.nix b/nixos/modules/virtualisation/google-compute-image.nix index 4c7cffcf4557..caaf6c0aa59d 100644 --- a/nixos/modules/virtualisation/google-compute-image.nix +++ b/nixos/modules/virtualisation/google-compute-image.nix @@ -97,8 +97,8 @@ in "google-instance-setup.service" "google-network-setup.service" ]; - wantedBy = [ "multi-user.target" ]; requires = ["network.target"]; + wantedBy = ["multi-user.target"]; path = with pkgs; [ shadow ]; serviceConfig = { Type = "simple"; @@ -113,8 +113,8 @@ in "google-instance-setup.service" "google-network-setup.service" ]; - requires = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; + requires = ["network.target"]; + wantedBy = ["multi-user.target"]; serviceConfig = { Type = "simple"; ExecStart = "${gce}/bin/google_clock_skew_daemon --debug"; @@ -123,7 +123,7 @@ in systemd.services.google-instance-setup = { description = "Google Compute Engine Instance Setup"; - after = ["fs.target" "network-online.target" "network.target" "rsyslog.service"]; + after = ["local-fs.target" "network-online.target" "network.target" "rsyslog.service"]; before = ["sshd.service"]; wants = ["local-fs.target" "network-online.target" "network.target"]; wantedBy = [ "sshd.service" "multi-user.target" ]; @@ -134,15 +134,17 @@ in }; }; - systemd.services.google-ip-forwarding-daemon = { - description = "Google Compute Engine IP Forwarding Daemon"; - after = ["network.target" "google-instance-setup.service" "google-network-setup.service"]; + systemd.services.google-network-daemon = { + description = "Google Compute Engine Network Daemon"; + after = ["local-fs.target" "network-online.target" "network.target" "rsyslog.service" "google-instance-setup.service"]; + wants = ["local-fs.target" "network-online.target" "network.target"]; requires = ["network.target"]; + partOf = ["network.target"]; wantedBy = [ "multi-user.target" ]; path = with pkgs; [ iproute ]; serviceConfig = { - Type = "simple"; - ExecStart = "${gce}/bin/google_ip_forwarding_daemon --debug"; + ExecStart = "${gce}/bin/google_network_daemon --debug"; + Type = "oneshot"; }; }; @@ -153,8 +155,9 @@ in "network-online.target" "network.target" "rsyslog.service" + "systemd-resolved.service" "google-instance-setup.service" - "google-network-setup.service" + "google-network-daemon.service" ]; wants = [ "local-fs.target" "network-online.target" "network.target"]; wantedBy = [ "multi-user.target" ]; @@ -167,23 +170,6 @@ in }; }; - systemd.services.google-network-setup = { - description = "Google Compute Engine Network Setup"; - after = [ - "local-fs.target" - "network-online.target" - "network.target" - "rsyslog.service" - ]; - wants = [ "local-fs.target" "network-online.target" "network.target"]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - ExecStart = "${gce}/bin/google_network_setup --debug"; - KillMode = "process"; - Type = "oneshot"; - }; - }; - systemd.services.google-startup-scripts = { description = "Google Compute Engine Startup Scripts"; after = [ @@ -192,9 +178,9 @@ in "network.target" "rsyslog.service" "google-instance-setup.service" - "google-network-setup.service" + "google-network-daemon.service" ]; - wants = [ "local-fs.target" "network-online.target" "network.target"]; + wants = ["local-fs.target" "network-online.target" "network.target"]; wantedBy = [ "multi-user.target" ]; serviceConfig = { ExecStart = "${gce}/bin/google_metadata_script_runner --debug --script-type startup"; diff --git a/nixos/modules/virtualisation/hyperv-guest.nix b/nixos/modules/virtualisation/hyperv-guest.nix index ecd2a8117710..0f1f052880c5 100644 --- a/nixos/modules/virtualisation/hyperv-guest.nix +++ b/nixos/modules/virtualisation/hyperv-guest.nix @@ -9,20 +9,47 @@ in { options = { virtualisation.hypervGuest = { enable = mkEnableOption "Hyper-V Guest Support"; + + videoMode = mkOption { + type = types.str; + default = "1152x864"; + example = "1024x768"; + description = '' + Resolution at which to initialize the video adapter. + + Supports screen resolution up to Full HD 1920x1080 with 32 bit color + on Windows Server 2012, and 1600x1200 with 16 bit color on Windows + Server 2008 R2 or earlier. + ''; + }; }; }; config = mkIf cfg.enable { + boot = { + initrd.kernelModules = [ + "hv_balloon" "hv_netvsc" "hv_storvsc" "hv_utils" "hv_vmbus" + ]; + + kernelParams = [ + "video=hyperv_fb:${cfg.videoMode}" + ]; + }; + environment.systemPackages = [ config.boot.kernelPackages.hyperv-daemons.bin ]; security.rngd.enable = false; - # enable hotadding memory + # enable hotadding cpu/memory services.udev.packages = lib.singleton (pkgs.writeTextFile { - name = "hyperv-memory-hotadd-udev-rules"; - destination = "/etc/udev/rules.d/99-hyperv-memory-hotadd.rules"; + name = "hyperv-cpu-and-memory-hotadd-udev-rules"; + destination = "/etc/udev/rules.d/99-hyperv-cpu-and-memory-hotadd.rules"; text = '' - ACTION="add", SUBSYSTEM=="memory", ATTR{state}="online" + # Memory hotadd + SUBSYSTEM=="memory", ACTION=="add", DEVPATH=="/devices/system/memory/memory[0-9]*", TEST=="state", ATTR{state}="online" + + # CPU hotadd + SUBSYSTEM=="cpu", ACTION=="add", DEVPATH=="/devices/system/cpu/cpu[0-9]*", TEST=="online", ATTR{online}="1" ''; }); diff --git a/nixos/modules/virtualisation/kvmgt.nix b/nixos/modules/virtualisation/kvmgt.nix index fc0bedb68bd0..132815a0ad63 100644 --- a/nixos/modules/virtualisation/kvmgt.nix +++ b/nixos/modules/virtualisation/kvmgt.nix @@ -50,11 +50,17 @@ in { nameValuePair "kvmgt-${name}" { description = "KVMGT VGPU ${name}"; serviceConfig = { - Type = "oneshot"; + Type = "forking"; RemainAfterExit = true; + Restart = "on-failure"; + RestartSec = 5; ExecStart = "${pkgs.runtimeShell} -c 'echo ${value.uuid} > /sys/bus/pci/devices/${cfg.device}/mdev_supported_types/${name}/create'"; ExecStop = "${pkgs.runtimeShell} -c 'echo 1 > /sys/bus/pci/devices/${cfg.device}/${value.uuid}/remove'"; }; + unitConfig = { + StartLimitBurst = 5; + StartLimitIntervalSec = 30; + }; wantedBy = [ "multi-user.target" ]; } ) cfg.vgpus; diff --git a/nixos/modules/virtualisation/libvirtd.nix b/nixos/modules/virtualisation/libvirtd.nix index 3e38662f5b0f..f4d7af1664af 100644 --- a/nixos/modules/virtualisation/libvirtd.nix +++ b/nixos/modules/virtualisation/libvirtd.nix @@ -196,6 +196,8 @@ in { wantedBy = [ "multi-user.target" ]; path = with pkgs; [ coreutils libvirt gawk ]; restartIfChanged = false; + + environment.ON_SHUTDOWN = "${cfg.onShutdown}"; }; systemd.sockets.virtlogd = { diff --git a/nixos/modules/virtualisation/qemu-guest-agent.nix b/nixos/modules/virtualisation/qemu-guest-agent.nix index e0d2b3dc509d..665224e35d8c 100644 --- a/nixos/modules/virtualisation/qemu-guest-agent.nix +++ b/nixos/modules/virtualisation/qemu-guest-agent.nix @@ -25,7 +25,7 @@ in { systemd.services.qemu-guest-agent = { description = "Run the QEMU Guest Agent"; serviceConfig = { - ExecStart = "${pkgs.kvm.ga}/bin/qemu-ga"; + ExecStart = "${pkgs.qemu.ga}/bin/qemu-ga"; Restart = "always"; RestartSec = 0; }; diff --git a/nixos/modules/virtualisation/virtualbox-image.nix b/nixos/modules/virtualisation/virtualbox-image.nix index 60048911658c..037c0d2f0d82 100644 --- a/nixos/modules/virtualisation/virtualbox-image.nix +++ b/nixos/modules/virtualisation/virtualbox-image.nix @@ -12,7 +12,7 @@ in { virtualbox = { baseImageSize = mkOption { type = types.int; - default = 10 * 1024; + default = 50 * 1024; description = '' The size of the VirtualBox base image in MiB. ''; @@ -61,7 +61,7 @@ in { export HOME=$PWD export PATH=${pkgs.virtualbox}/bin:$PATH - echo "creating VirtualBox pass-through disk wrapper (no copying invovled)..." + echo "creating VirtualBox pass-through disk wrapper (no copying involved)..." VBoxManage internalcommands createrawvmdk -filename disk.vmdk -rawdisk $diskImage echo "creating VirtualBox VM..." @@ -72,9 +72,9 @@ in { --memory ${toString cfg.memorySize} --acpi on --vram 32 \ ${optionalString (pkgs.stdenv.hostPlatform.system == "i686-linux") "--pae on"} \ --nictype1 virtio --nic1 nat \ - --audiocontroller ac97 --audio alsa \ + --audiocontroller ac97 --audio alsa --audioout on \ --rtcuseutc on \ - --usb on --mouse usbtablet + --usb on --usbehci on --mouse usbtablet VBoxManage storagectl "$vmName" --name SATA --add sata --portcount 4 --bootable on --hostiocache on VBoxManage storageattach "$vmName" --storagectl SATA --port 0 --device 0 --type hdd \ --medium disk.vmdk @@ -82,7 +82,7 @@ in { echo "exporting VirtualBox VM..." mkdir -p $out fn="$out/${cfg.vmFileName}" - VBoxManage export "$vmName" --output "$fn" + VBoxManage export "$vmName" --output "$fn" --options manifest rm -v $diskImage diff --git a/nixos/modules/virtualisation/xe-guest-utilities.nix b/nixos/modules/virtualisation/xe-guest-utilities.nix index d703353858c0..675cf9297371 100644 --- a/nixos/modules/virtualisation/xe-guest-utilities.nix +++ b/nixos/modules/virtualisation/xe-guest-utilities.nix @@ -5,7 +5,7 @@ let in { options = { services.xe-guest-utilities = { - enable = mkEnableOption "Whether to enable the Xen guest utilities daemon."; + enable = mkEnableOption "the Xen guest utilities daemon"; }; }; config = mkIf cfg.enable { diff --git a/nixos/release.nix b/nixos/release.nix index 1013053b5b3b..51505d6aab9d 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -1,10 +1,12 @@ -{ nixpkgs ? { outPath = (import ../lib).cleanSource ./..; revCount = 130979; shortRev = "gfedcba"; } +with import ../lib; + +{ nixpkgs ? { outPath = cleanSource ./..; revCount = 130979; shortRev = "gfedcba"; } , stableBranch ? false , supportedSystems ? [ "x86_64-linux" "aarch64-linux" ] +, configuration ? {} }: with import ../pkgs/top-level/release-lib.nix { inherit supportedSystems; }; -with import ../lib; let @@ -51,7 +53,7 @@ let hydraJob ((import lib/eval-config.nix { inherit system; - modules = [ module versionModule { isoImage.isoBaseName = "nixos-${type}"; } ]; + modules = [ configuration module versionModule { isoImage.isoBaseName = "nixos-${type}"; } ]; }).config.system.build.isoImage); @@ -62,7 +64,7 @@ let hydraJob ((import lib/eval-config.nix { inherit system; - modules = [ module versionModule ]; + modules = [ configuration module versionModule ]; }).config.system.build.sdImage); @@ -75,7 +77,7 @@ let config = (import lib/eval-config.nix { inherit system; - modules = [ module versionModule ]; + modules = [ configuration module versionModule ]; }).config; tarball = config.system.build.tarball; @@ -95,16 +97,19 @@ let buildFromConfig = module: sel: forAllSystems (system: hydraJob (sel (import ./lib/eval-config.nix { inherit system; - modules = [ module versionModule ] ++ singleton + modules = [ configuration module versionModule ] ++ singleton ({ ... }: { fileSystems."/".device = mkDefault "/dev/sda1"; boot.loader.grub.device = mkDefault "/dev/sda"; }); }).config)); - makeNetboot = config: + makeNetboot = { module, system, ... }: let - configEvaled = import lib/eval-config.nix config; + configEvaled = import lib/eval-config.nix { + inherit system; + modules = [ module versionModule ]; + }; build = configEvaled.config.system.build; kernelTarget = configEvaled.pkgs.stdenv.hostPlatform.platform.kernelTarget; in @@ -128,7 +133,8 @@ in rec { channel = import lib/make-channel.nix { inherit pkgs nixpkgs version versionSuffix; }; - manual = buildFromConfig ({ ... }: { }) (config: config.system.build.manual.manual); + manualHTML = buildFromConfig ({ ... }: { }) (config: config.system.build.manual.manualHTML); + manual = manualHTML; # TODO(@oxij): remove eventually manualEpub = (buildFromConfig ({ ... }: { }) (config: config.system.build.manual.manualEpub)); manpages = buildFromConfig ({ ... }: { }) (config: config.system.build.manual.manpages); manualGeneratedSources = buildFromConfig ({ ... }: { }) (config: config.system.build.manual.generatedSources); @@ -139,11 +145,8 @@ in rec { initialRamdisk = buildFromConfig ({ ... }: { }) (config: config.system.build.initialRamdisk); netboot = forMatchingSystems [ "x86_64-linux" "aarch64-linux" ] (system: makeNetboot { + module = ./modules/installer/netboot/netboot-minimal.nix; inherit system; - modules = [ - ./modules/installer/netboot/netboot-minimal.nix - versionModule - ]; }); iso_minimal = forAllSystems (system: makeIso { @@ -247,13 +250,14 @@ in rec { tests.acme = callTest tests/acme.nix {}; tests.avahi = callTest tests/avahi.nix {}; tests.beegfs = callTest tests/beegfs.nix {}; + tests.upnp = callTest tests/upnp.nix {}; tests.bittorrent = callTest tests/bittorrent.nix {}; tests.bind = callTest tests/bind.nix {}; #tests.blivet = callTest tests/blivet.nix {}; # broken since 2017-07024 tests.boot = callSubTests tests/boot.nix {}; tests.boot-stage1 = callTest tests/boot-stage1.nix {}; tests.borgbackup = callTest tests/borgbackup.nix {}; - tests.buildbot = callTest tests/buildbot.nix {}; + tests.buildbot = callSubTests tests/buildbot.nix {}; tests.cadvisor = callTestOnMatchingSystems ["x86_64-linux"] tests/cadvisor.nix {}; tests.ceph = callTestOnMatchingSystems ["x86_64-linux"] tests/ceph.nix {}; tests.certmgr = callSubTests tests/certmgr.nix {}; @@ -261,6 +265,7 @@ in rec { tests.chromium = (callSubTestsOnMatchingSystems ["x86_64-linux"] tests/chromium.nix {}).stable or {}; tests.cjdns = callTest tests/cjdns.nix {}; tests.cloud-init = callTest tests/cloud-init.nix {}; + tests.codimd = callTest tests/codimd.nix {}; tests.containers-ipv4 = callTest tests/containers-ipv4.nix {}; tests.containers-ipv6 = callTest tests/containers-ipv6.nix {}; tests.containers-bridge = callTest tests/containers-bridge.nix {}; @@ -284,7 +289,8 @@ in rec { tests.ecryptfs = callTest tests/ecryptfs.nix {}; tests.etcd = callTestOnMatchingSystems ["x86_64-linux"] tests/etcd.nix {}; tests.ec2-nixops = (callSubTestsOnMatchingSystems ["x86_64-linux"] tests/ec2.nix {}).boot-ec2-nixops or {}; - tests.ec2-config = (callSubTestsOnMatchingSystems ["x86_64-linux"] tests/ec2.nix {}).boot-ec2-config or {}; + # ec2-config doesn't work in a sandbox as the simulated ec2 instance needs network access + #tests.ec2-config = (callSubTestsOnMatchingSystems ["x86_64-linux"] tests/ec2.nix {}).boot-ec2-config or {}; tests.elk = callSubTestsOnMatchingSystems ["x86_64-linux"] tests/elk.nix {}; tests.env = callTest tests/env.nix {}; tests.ferm = callTest tests/ferm.nix {}; @@ -327,7 +333,6 @@ in rec { tests.keymap = callSubTests tests/keymap.nix {}; tests.initrdNetwork = callTest tests/initrd-network.nix {}; tests.kafka = callSubTests tests/kafka.nix {}; - tests.kernel-copperhead = callTest tests/kernel-copperhead.nix {}; tests.kernel-latest = callTest tests/kernel-latest.nix {}; tests.kernel-lts = callTest tests/kernel-lts.nix {}; tests.kubernetes.dns = callSubTestsOnMatchingSystems ["x86_64-linux"] tests/kubernetes/dns.nix {}; @@ -358,6 +363,7 @@ in rec { tests.netdata = callTest tests/netdata.nix { }; tests.networking.networkd = callSubTests tests/networking.nix { networkd = true; }; tests.networking.scripted = callSubTests tests/networking.nix { networkd = false; }; + tests.nextcloud = callSubTests tests/nextcloud { }; # TODO: put in networking.nix after the test becomes more complete tests.networkingProxy = callTest tests/networking-proxy.nix {}; tests.nexus = callTest tests/nexus.nix { }; @@ -380,17 +386,20 @@ in rec { 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.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.prometheus-exporters = callTest tests/prometheus-exporters.nix {}; tests.prosody = callTest tests/prosody.nix {}; tests.proxy = callTest tests/proxy.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.redmine = callTest tests/redmine.nix {}; tests.rspamd = callSubTests tests/rspamd.nix {}; + tests.rsyslogd = callSubTests tests/rsyslogd.nix {}; tests.runInMachine = callTest tests/run-in-machine.nix {}; tests.rxe = callTest tests/rxe.nix {}; tests.samba = callTest tests/samba.nix {}; @@ -400,7 +409,7 @@ in rec { tests.slurm = callTest tests/slurm.nix {}; tests.smokeping = callTest tests/smokeping.nix {}; tests.snapper = callTest tests/snapper.nix {}; - tests.statsd = callTest tests/statsd.nix {}; + #tests.statsd = callTest tests/statsd.nix {}; # statsd is broken: #45946 tests.strongswan-swanctl = callTest tests/strongswan-swanctl.nix {}; tests.sudo = callTest tests/sudo.nix {}; tests.systemd = callTest tests/systemd.nix {}; @@ -459,7 +468,7 @@ in rec { { services.httpd.enable = true; services.httpd.adminAddr = "foo@example.org"; services.postgresql.enable = true; - services.postgresql.package = pkgs.postgresql93; + services.postgresql.package = pkgs.postgresql_9_3; environment.systemPackages = [ pkgs.php ]; }); }; diff --git a/nixos/tests/acme.nix b/nixos/tests/acme.nix index c7fd4910e072..4669a092433e 100644 --- a/nixos/tests/acme.nix +++ b/nixos/tests/acme.nix @@ -1,32 +1,5 @@ let - commonConfig = { lib, nodes, ... }: { - networking.nameservers = [ - nodes.letsencrypt.config.networking.primaryIPAddress - ]; - - nixpkgs.overlays = lib.singleton (self: super: { - cacert = super.cacert.overrideDerivation (drv: { - installPhase = (drv.installPhase or "") + '' - cat "${nodes.letsencrypt.config.test-support.letsencrypt.caCert}" \ - >> "$out/etc/ssl/certs/ca-bundle.crt" - ''; - }); - - # Override certifi so that it accepts fake certificate for Let's Encrypt - # Need to override the attribute used by simp_le, which is python3Packages - python3Packages = (super.python3.override { - packageOverrides = lib.const (pysuper: { - certifi = pysuper.certifi.overridePythonAttrs (attrs: { - postPatch = (attrs.postPatch or "") + '' - cat "${self.cacert}/etc/ssl/certs/ca-bundle.crt" \ - > certifi/cacert.pem - ''; - }); - }); - }).pkgs; - }); - }; - + commonConfig = ./common/letsencrypt/common.nix; in import ./make-test.nix { name = "acme"; diff --git a/nixos/tests/atd.nix b/nixos/tests/atd.nix index 9f367d4c1d2a..25db72799241 100644 --- a/nixos/tests/atd.nix +++ b/nixos/tests/atd.nix @@ -16,6 +16,7 @@ import ./make-test.nix ({ pkgs, ... }: testScript = '' startAll; + $machine->waitForUnit('atd.service'); # wait for atd to start $machine->fail("test -f ~root/at-1"); $machine->fail("test -f ~alice/at-1"); diff --git a/nixos/tests/bittorrent.nix b/nixos/tests/bittorrent.nix index 609b1ff7a83a..8977be9b859f 100644 --- a/nixos/tests/bittorrent.nix +++ b/nixos/tests/bittorrent.nix @@ -13,57 +13,95 @@ let # Some random file to serve. file = pkgs.hello.src; - miniupnpdConf = nodes: pkgs.writeText "miniupnpd.conf" - '' - ext_ifname=eth1 - 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 - ''; - + internalRouterAddress = "192.168.3.1"; + internalClient1Address = "192.168.3.2"; + externalRouterAddress = "80.100.100.1"; + externalClient2Address = "80.100.100.2"; + externalTrackerAddress = "80.100.100.3"; in { name = "bittorrent"; meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ domenkozar eelco chaoflow rob wkennington ]; + maintainers = [ domenkozar eelco chaoflow rob wkennington bobvanderlinden ]; }; nodes = { tracker = { pkgs, ... }: - { environment.systemPackages = [ pkgs.transmission pkgs.opentracker ]; + { environment.systemPackages = [ pkgs.transmission ]; + + virtualisation.vlans = [ 1 ]; + networking.interfaces.eth1.ipv4.addresses = [ + { address = externalTrackerAddress; prefixLength = 24; } + ]; # We need Apache on the tracker to serve the torrents. services.httpd.enable = true; services.httpd.adminAddr = "foo@example.org"; services.httpd.documentRoot = "/tmp"; - networking.firewall.enable = false; # FIXME: figure out what ports we actually need + networking.firewall.enable = false; + + services.opentracker.enable = true; + + services.transmission.enable = true; + services.transmission.settings.dht-enabled = false; + services.transmission.settings.port-forwaring-enabled = false; }; router = - { pkgs, ... }: - { environment.systemPackages = [ pkgs.miniupnpd ]; - virtualisation.vlans = [ 1 2 ]; + { pkgs, nodes, ... }: + { virtualisation.vlans = [ 1 2 ]; networking.nat.enable = true; networking.nat.internalInterfaces = [ "eth2" ]; networking.nat.externalInterface = "eth1"; - networking.firewall.enable = false; + networking.firewall.enable = true; + networking.firewall.trustedInterfaces = [ "eth2" ]; + networking.interfaces.eth0.ipv4.addresses = []; + networking.interfaces.eth1.ipv4.addresses = [ + { address = externalRouterAddress; prefixLength = 24; } + ]; + networking.interfaces.eth2.ipv4.addresses = [ + { address = internalRouterAddress; prefixLength = 24; } + ]; + services.miniupnpd = { + enable = true; + externalInterface = "eth1"; + internalIPs = [ "eth2" ]; + appendConfig = '' + ext_ip=${externalRouterAddress} + ''; + }; }; client1 = { pkgs, nodes, ... }: - { environment.systemPackages = [ pkgs.transmission ]; + { environment.systemPackages = [ pkgs.transmission pkgs.miniupnpc ]; virtualisation.vlans = [ 2 ]; - networking.defaultGateway = - (pkgs.lib.head nodes.router.config.networking.interfaces.eth2.ipv4.addresses).address; + networking.interfaces.eth0.ipv4.addresses = []; + networking.interfaces.eth1.ipv4.addresses = [ + { address = internalClient1Address; prefixLength = 24; } + ]; + networking.defaultGateway = internalRouterAddress; networking.firewall.enable = false; + services.transmission.enable = true; + services.transmission.settings.dht-enabled = false; + services.transmission.settings.message-level = 3; }; client2 = { pkgs, ... }: { environment.systemPackages = [ pkgs.transmission ]; + virtualisation.vlans = [ 1 ]; + networking.interfaces.eth0.ipv4.addresses = []; + networking.interfaces.eth1.ipv4.addresses = [ + { address = externalClient2Address; prefixLength = 24; } + ]; networking.firewall.enable = false; + services.transmission.enable = true; + services.transmission.settings.dht-enabled = false; + services.transmission.settings.port-forwaring-enabled = false; }; }; @@ -72,43 +110,38 @@ in '' startAll; - # Enable NAT on the router and start miniupnpd. - $router->waitForUnit("nat"); - $router->succeed( - "iptables -w -t nat -N MINIUPNPD", - "iptables -w -t nat -A PREROUTING -i eth1 -j MINIUPNPD", - "echo 1 > /proc/sys/net/ipv4/ip_forward", - "miniupnpd -f ${miniupnpdConf nodes}" - ); + # Wait for network and miniupnpd. + $router->waitForUnit("network-online.target"); + $router->waitForUnit("miniupnpd"); # 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.ipv4.addresses).address}:6969/announce -o /tmp/test.torrent"); + $tracker->succeed("transmission-create /tmp/data/test.tar.bz2 --private --tracker http://${externalTrackerAddress}:6969/announce --outfile /tmp/test.torrent"); $tracker->succeed("chmod 644 /tmp/test.torrent"); # Start the tracker. !!! use a less crappy tracker - $tracker->waitForUnit("network.target"); - $tracker->succeed("opentracker -p 6969 >&2 &"); + $tracker->waitForUnit("network-online.target"); + $tracker->waitForUnit("opentracker.service"); $tracker->waitForOpenPort(6969); # Start the initial seeder. - my $pid = $tracker->succeed("transmission-cli /tmp/test.torrent -M -w /tmp/data >&2 & echo \$!"); + $tracker->succeed("transmission-remote --add /tmp/test.torrent --no-portmap --no-dht --download-dir /tmp/data"); # Now we should be able to download from the client behind the NAT. $tracker->waitForUnit("httpd"); - $client1->waitForUnit("network.target"); - $client1->succeed("transmission-cli http://tracker/test.torrent -w /tmp >&2 &"); + $client1->waitForUnit("network-online.target"); + $client1->succeed("transmission-remote --add http://${externalTrackerAddress}/test.torrent --download-dir /tmp >&2 &"); $client1->waitForFile("/tmp/test.tar.bz2"); $client1->succeed("cmp /tmp/test.tar.bz2 ${file}"); # Bring down the initial seeder. - $tracker->succeed("kill -9 $pid"); + # $tracker->stopJob("transmission"); # Now download from the second client. This can only succeed if # the first client created a NAT hole in the router. - $client2->waitForUnit("network.target"); - $client2->succeed("transmission-cli http://tracker/test.torrent -M -w /tmp >&2 &"); + $client2->waitForUnit("network-online.target"); + $client2->succeed("transmission-remote --add http://${externalTrackerAddress}/test.torrent --no-portmap --no-dht --download-dir /tmp >&2 &"); $client2->waitForFile("/tmp/test.tar.bz2"); $client2->succeed("cmp /tmp/test.tar.bz2 ${file}"); ''; diff --git a/nixos/tests/buildbot.nix b/nixos/tests/buildbot.nix index cf408dc7fec9..399fd39005e2 100644 --- a/nixos/tests/buildbot.nix +++ b/nixos/tests/buildbot.nix @@ -1,111 +1,117 @@ -# Test ensures buildbot master comes up correctly and workers can connect - -import ./make-test.nix ({ pkgs, ... } : { - name = "buildbot"; - - nodes = { - bbmaster = { pkgs, ... }: { - services.buildbot-master = { - enable = true; - package = pkgs.buildbot-full; - - # NOTE: use fake repo due to no internet in hydra ci - factorySteps = [ - "steps.Git(repourl='git://gitrepo/fakerepo.git', mode='incremental')" - "steps.ShellCommand(command=['bash', 'fakerepo.sh'])" - ]; - changeSource = [ - "changes.GitPoller('git://gitrepo/fakerepo.git', workdir='gitpoller-workdir', branch='master', pollinterval=300)" - ]; +{ system ? builtins.currentSystem }: + +with import ../lib/testing.nix { inherit system; }; + +let + # Test ensures buildbot master comes up correctly and workers can connect + mkBuildbotTest = python: makeTest { + name = "buildbot"; + + nodes = { + bbmaster = { pkgs, ... }: { + services.buildbot-master = { + enable = true; + package = python.pkgs.buildbot-full; + + # NOTE: use fake repo due to no internet in hydra ci + factorySteps = [ + "steps.Git(repourl='git://gitrepo/fakerepo.git', mode='incremental')" + "steps.ShellCommand(command=['bash', 'fakerepo.sh'])" + ]; + changeSource = [ + "changes.GitPoller('git://gitrepo/fakerepo.git', workdir='gitpoller-workdir', branch='master', pollinterval=300)" + ]; + }; + networking.firewall.allowedTCPPorts = [ 8010 8011 9989 ]; + environment.systemPackages = with pkgs; [ git python.pkgs.buildbot-full ]; }; - networking.firewall.allowedTCPPorts = [ 8010 8011 9989 ]; - environment.systemPackages = with pkgs; [ git buildbot-full ]; - }; - bbworker = { pkgs, ... }: { - services.buildbot-worker = { - enable = true; - masterUrl = "bbmaster:9989"; + bbworker = { pkgs, ... }: { + services.buildbot-worker = { + enable = true; + masterUrl = "bbmaster:9989"; + }; + environment.systemPackages = with pkgs; [ git python.pkgs.buildbot-worker ]; }; - environment.systemPackages = with pkgs; [ git buildbot-worker ]; - }; - gitrepo = { pkgs, ... }: { - services.openssh.enable = true; - networking.firewall.allowedTCPPorts = [ 22 9418 ]; - environment.systemPackages = with pkgs; [ git ]; + gitrepo = { pkgs, ... }: { + services.openssh.enable = true; + networking.firewall.allowedTCPPorts = [ 22 9418 ]; + environment.systemPackages = with pkgs; [ git ]; + }; }; - }; - testScript = '' - #Start up and populate fake repo - $gitrepo->waitForUnit("multi-user.target"); - print($gitrepo->execute(" \ - git config --global user.name 'Nobody Fakeuser' && \ - git config --global user.email 'nobody\@fakerepo.com' && \ - rm -rvf /srv/repos/fakerepo.git /tmp/fakerepo && \ - mkdir -pv /srv/repos/fakerepo ~/.ssh && \ - ssh-keyscan -H gitrepo > ~/.ssh/known_hosts && \ - cat ~/.ssh/known_hosts && \ - cd /srv/repos/fakerepo && \ - git init && \ - echo -e '#!/bin/sh\necho fakerepo' > fakerepo.sh && \ - cat fakerepo.sh && \ - touch .git/git-daemon-export-ok && \ - git add fakerepo.sh .git/git-daemon-export-ok && \ - git commit -m fakerepo && \ - git daemon --verbose --export-all --base-path=/srv/repos --reuseaddr & \ - ")); - - # Test gitrepo - $bbmaster->waitForUnit("network-online.target"); - #$bbmaster->execute("nc -z gitrepo 9418"); - print($bbmaster->execute(" \ - rm -rfv /tmp/fakerepo && \ - git clone git://gitrepo/fakerepo /tmp/fakerepo && \ - pwd && \ - ls -la && \ - ls -la /tmp/fakerepo \ - ")); - - # Test start master and connect worker - $bbmaster->waitForUnit("buildbot-master.service"); - $bbmaster->waitUntilSucceeds("curl -s --head http://bbmaster:8010") =~ /200 OK/; - $bbworker->waitForUnit("network-online.target"); - $bbworker->execute("nc -z bbmaster 8010"); - $bbworker->execute("nc -z bbmaster 9989"); - $bbworker->waitForUnit("buildbot-worker.service"); - print($bbworker->execute("ls -la /home/bbworker/worker")); - - - # Test stop buildbot master and worker - print($bbmaster->execute(" \ - systemctl -l --no-pager status buildbot-master && \ - systemctl stop buildbot-master \ - ")); - $bbworker->fail("nc -z bbmaster 8010"); - $bbworker->fail("nc -z bbmaster 9989"); - print($bbworker->execute(" \ - systemctl -l --no-pager status buildbot-worker && \ - systemctl stop buildbot-worker && \ - ls -la /home/bbworker/worker \ - ")); - - - # Test buildbot daemon mode - # NOTE: daemon mode tests disabled due to broken PYTHONPATH child inheritence - # - #$bbmaster->execute("buildbot create-master /tmp"); - #$bbmaster->execute("mv -fv /tmp/master.cfg.sample /tmp/master.cfg"); - #$bbmaster->execute("sed -i 's/8010/8011/' /tmp/master.cfg"); - #$bbmaster->execute("buildbot start /tmp"); - #$bbworker->execute("nc -z bbmaster 8011"); - #$bbworker->waitUntilSucceeds("curl -s --head http://bbmaster:8011") =~ /200 OK/; - #$bbmaster->execute("buildbot stop /tmp"); - #$bbworker->fail("nc -z bbmaster 8011"); - - ''; - - meta.maintainers = with pkgs.stdenv.lib.maintainers; [ nand0p ]; - -}) + testScript = '' + #Start up and populate fake repo + $gitrepo->waitForUnit("multi-user.target"); + print($gitrepo->execute(" \ + git config --global user.name 'Nobody Fakeuser' && \ + git config --global user.email 'nobody\@fakerepo.com' && \ + rm -rvf /srv/repos/fakerepo.git /tmp/fakerepo && \ + mkdir -pv /srv/repos/fakerepo ~/.ssh && \ + ssh-keyscan -H gitrepo > ~/.ssh/known_hosts && \ + cat ~/.ssh/known_hosts && \ + cd /srv/repos/fakerepo && \ + git init && \ + echo -e '#!/bin/sh\necho fakerepo' > fakerepo.sh && \ + cat fakerepo.sh && \ + touch .git/git-daemon-export-ok && \ + git add fakerepo.sh .git/git-daemon-export-ok && \ + git commit -m fakerepo && \ + git daemon --verbose --export-all --base-path=/srv/repos --reuseaddr & \ + ")); + + # Test gitrepo + $bbmaster->waitForUnit("network-online.target"); + #$bbmaster->execute("nc -z gitrepo 9418"); + print($bbmaster->execute(" \ + rm -rfv /tmp/fakerepo && \ + git clone git://gitrepo/fakerepo /tmp/fakerepo && \ + pwd && \ + ls -la && \ + ls -la /tmp/fakerepo \ + ")); + + # Test start master and connect worker + $bbmaster->waitForUnit("buildbot-master.service"); + $bbmaster->waitUntilSucceeds("curl -s --head http://bbmaster:8010") =~ /200 OK/; + $bbworker->waitForUnit("network-online.target"); + $bbworker->execute("nc -z bbmaster 8010"); + $bbworker->execute("nc -z bbmaster 9989"); + $bbworker->waitForUnit("buildbot-worker.service"); + print($bbworker->execute("ls -la /home/bbworker/worker")); + + + # Test stop buildbot master and worker + print($bbmaster->execute(" \ + systemctl -l --no-pager status buildbot-master && \ + systemctl stop buildbot-master \ + ")); + $bbworker->fail("nc -z bbmaster 8010"); + $bbworker->fail("nc -z bbmaster 9989"); + print($bbworker->execute(" \ + systemctl -l --no-pager status buildbot-worker && \ + systemctl stop buildbot-worker && \ + ls -la /home/bbworker/worker \ + ")); + + + # Test buildbot daemon mode + $bbmaster->execute("buildbot create-master /tmp"); + $bbmaster->execute("mv -fv /tmp/master.cfg.sample /tmp/master.cfg"); + $bbmaster->execute("sed -i 's/8010/8011/' /tmp/master.cfg"); + $bbmaster->execute("buildbot start /tmp"); + $bbworker->execute("nc -z bbmaster 8011"); + $bbworker->waitUntilSucceeds("curl -s --head http://bbmaster:8011") =~ /200 OK/; + $bbmaster->execute("buildbot stop /tmp"); + $bbworker->fail("nc -z bbmaster 8011"); + + ''; + + meta.maintainers = with pkgs.stdenv.lib.maintainers; [ nand0p ]; + + }; +in { + python2 = mkBuildbotTest pkgs.python2; + python3 = mkBuildbotTest pkgs.python3; +} diff --git a/nixos/tests/ceph.nix b/nixos/tests/ceph.nix index dd45f0157b01..7408029c460e 100644 --- a/nixos/tests/ceph.nix +++ b/nixos/tests/ceph.nix @@ -10,9 +10,8 @@ import ./make-test.nix ({pkgs, ...}: rec { emptyDiskImages = [ 20480 20480 ]; vlans = [ 1 ]; }; - + networking = { - firewall.allowPing = true; useDHCP = false; interfaces.eth1.ipv4.addresses = pkgs.lib.mkOverride 0 [ { address = "192.168.1.1"; prefixLength = 24; } @@ -54,7 +53,7 @@ import ./make-test.nix ({pkgs, ...}: rec { }; }; }; - + testScript = { ... }: '' startAll; @@ -83,7 +82,7 @@ import ./make-test.nix ({pkgs, ...}: rec { # Can't check ceph status until a mon is up $aio->succeed("ceph -s | grep 'mon: 1 daemons'"); - + # Start the ceph-mgr daemon, it has no deps and hardly any setup $aio->mustSucceed( "ceph auth get-or-create mgr.aio mon 'allow profile mgr' osd 'allow *' mds 'allow *' > /var/lib/ceph/mgr/ceph-aio/keyring", diff --git a/nixos/tests/chromium.nix b/nixos/tests/chromium.nix index c341e83961a8..fcc55a59a216 100644 --- a/nixos/tests/chromium.nix +++ b/nixos/tests/chromium.nix @@ -12,8 +12,10 @@ with pkgs.lib; mapAttrs (channel: chromiumPkg: makeTest rec { name = "chromium-${channel}"; - meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ aszlig ]; + meta = { + maintainers = with maintainers; [ aszlig ]; + # https://github.com/NixOS/hydra/issues/591#issuecomment-435125621 + inherit (chromiumPkg.meta) timeout; }; enableOCR = true; diff --git a/nixos/tests/cjdns.nix b/nixos/tests/cjdns.nix index ab5f8e0bcf3e..e03bb9882540 100644 --- a/nixos/tests/cjdns.nix +++ b/nixos/tests/cjdns.nix @@ -13,9 +13,6 @@ let # CJDNS output is incompatible with the XML log. systemd.services.cjdns.serviceConfig.StandardOutput = "null"; - #networking.firewall.enable = true; - networking.firewall.allowPing = true; - #networking.firewall.rejectPackets = true; }; in diff --git a/nixos/tests/codimd.nix b/nixos/tests/codimd.nix new file mode 100644 index 000000000000..562f6f24f999 --- /dev/null +++ b/nixos/tests/codimd.nix @@ -0,0 +1,54 @@ +import ./make-test.nix ({ pkgs, lib, ... }: +{ + name = "codimd"; + + meta = with lib.maintainers; { + maintainers = [ willibutz ]; + }; + + nodes = { + codimdSqlite = { ... }: { + services = { + codimd = { + enable = true; + configuration.dbURL = "sqlite:///var/lib/codimd/codimd.db"; + }; + }; + }; + + codimdPostgres = { ... }: { + systemd.services.codimd.after = [ "postgresql.service" ]; + services = { + codimd = { + enable = true; + configuration.dbURL = "postgres://codimd:snakeoilpassword@localhost:5432/codimddb"; + }; + postgresql = { + enable = true; + initialScript = pkgs.writeText "pg-init-script.sql" '' + CREATE ROLE codimd LOGIN PASSWORD 'snakeoilpassword'; + CREATE DATABASE codimddb OWNER codimd; + ''; + }; + }; + }; + }; + + testScript = '' + startAll(); + + subtest "CodiMD sqlite", sub { + $codimdSqlite->waitForUnit("codimd.service"); + $codimdSqlite->waitForOpenPort(3000); + $codimdSqlite->waitUntilSucceeds("curl -sSf http://localhost:3000/new"); + }; + + subtest "CodiMD postgres", sub { + $codimdPostgres->waitForUnit("postgresql.service"); + $codimdPostgres->waitForUnit("codimd.service"); + $codimdPostgres->waitForOpenPort(5432); + $codimdPostgres->waitForOpenPort(3000); + $codimdPostgres->waitUntilSucceeds("curl -sSf http://localhost:3000/new"); + }; + ''; +}) diff --git a/nixos/tests/common/letsencrypt/common.nix b/nixos/tests/common/letsencrypt/common.nix new file mode 100644 index 000000000000..798a749f7f9b --- /dev/null +++ b/nixos/tests/common/letsencrypt/common.nix @@ -0,0 +1,27 @@ +{ lib, nodes, ... }: { + networking.nameservers = [ + nodes.letsencrypt.config.networking.primaryIPAddress + ]; + + nixpkgs.overlays = lib.singleton (self: super: { + cacert = super.cacert.overrideDerivation (drv: { + installPhase = (drv.installPhase or "") + '' + cat "${nodes.letsencrypt.config.test-support.letsencrypt.caCert}" \ + >> "$out/etc/ssl/certs/ca-bundle.crt" + ''; + }); + + # Override certifi so that it accepts fake certificate for Let's Encrypt + # Need to override the attribute used by simp_le, which is python3Packages + python3Packages = (super.python3.override { + packageOverrides = lib.const (pysuper: { + certifi = pysuper.certifi.overridePythonAttrs (attrs: { + postPatch = (attrs.postPatch or "") + '' + cat "${self.cacert}/etc/ssl/certs/ca-bundle.crt" \ + > certifi/cacert.pem + ''; + }); + }); + }).pkgs; + }); +} diff --git a/nixos/tests/containers-bridge.nix b/nixos/tests/containers-bridge.nix index bd8bd5dee9c8..777cf9a7e7f9 100644 --- a/nixos/tests/containers-bridge.nix +++ b/nixos/tests/containers-bridge.nix @@ -42,7 +42,6 @@ import ./make-test.nix ({ pkgs, ...} : { { services.httpd.enable = true; services.httpd.adminAddr = "foo@example.org"; networking.firewall.allowedTCPPorts = [ 80 ]; - networking.firewall.allowPing = true; }; }; diff --git a/nixos/tests/containers-extra_veth.nix b/nixos/tests/containers-extra_veth.nix index 8f874b3585dc..b4c48afe48ba 100644 --- a/nixos/tests/containers-extra_veth.nix +++ b/nixos/tests/containers-extra_veth.nix @@ -43,7 +43,6 @@ import ./make-test.nix ({ pkgs, ...} : { config = { networking.firewall.allowedTCPPorts = [ 80 ]; - networking.firewall.allowPing = true; }; }; diff --git a/nixos/tests/containers-imperative.nix b/nixos/tests/containers-imperative.nix index 913d8bed19d0..782095a09dad 100644 --- a/nixos/tests/containers-imperative.nix +++ b/nixos/tests/containers-imperative.nix @@ -13,6 +13,7 @@ import ./make-test.nix ({ pkgs, ...} : { # XXX: Sandbox setup fails while trying to hardlink files from the host's # store file system into the prepared chroot directory. nix.useSandbox = false; + nix.binaryCaches = []; # don't try to access cache.nixos.org virtualisation.writableStore = true; virtualisation.memorySize = 1024; @@ -27,9 +28,10 @@ import ./make-test.nix ({ pkgs, ...} : { }; }; }; - in [ - pkgs.stdenv pkgs.stdenvNoCC emptyContainer.config.containers.foo.path - pkgs.libxslt + in with pkgs; [ + stdenv stdenvNoCC emptyContainer.config.containers.foo.path + libxslt desktop-file-utils texinfo docbook5 libxml2 + docbook_xsl_ns xorg.lndir documentation-highlighter ]; }; @@ -84,6 +86,9 @@ import ./make-test.nix ({ pkgs, ...} : { # Execute commands via the root shell. $machine->succeed("nixos-container run $id1 -- uname") =~ /Linux/ or die; + # Execute a nix command via the root shell. (regression test for #40355) + $machine->succeed("nixos-container run $id1 -- nix-instantiate -E 'derivation { name = \"empty\"; builder = \"false\"; system = \"false\"; }'"); + # Stop and start (regression test for #4989) $machine->succeed("nixos-container stop $id1"); $machine->succeed("nixos-container start $id1"); diff --git a/nixos/tests/containers-ipv4.nix b/nixos/tests/containers-ipv4.nix index 4affe3d9d56d..5f83a33b1079 100644 --- a/nixos/tests/containers-ipv4.nix +++ b/nixos/tests/containers-ipv4.nix @@ -20,7 +20,6 @@ import ./make-test.nix ({ pkgs, ...} : { { services.httpd.enable = true; services.httpd.adminAddr = "foo@example.org"; networking.firewall.allowedTCPPorts = [ 80 ]; - networking.firewall.allowPing = true; system.stateVersion = "18.03"; }; }; diff --git a/nixos/tests/containers-ipv6.nix b/nixos/tests/containers-ipv6.nix index 7db389a18e72..5866e51b731d 100644 --- a/nixos/tests/containers-ipv6.nix +++ b/nixos/tests/containers-ipv6.nix @@ -25,7 +25,6 @@ import ./make-test.nix ({ pkgs, ...} : { { services.httpd.enable = true; services.httpd.adminAddr = "foo@example.org"; networking.firewall.allowedTCPPorts = [ 80 ]; - networking.firewall.allowPing = true; }; }; diff --git a/nixos/tests/containers-portforward.nix b/nixos/tests/containers-portforward.nix index be83f82445ed..d2dda926fc0e 100644 --- a/nixos/tests/containers-portforward.nix +++ b/nixos/tests/containers-portforward.nix @@ -28,7 +28,6 @@ import ./make-test.nix ({ pkgs, ...} : { { services.httpd.enable = true; services.httpd.adminAddr = "foo@example.org"; networking.firewall.allowedTCPPorts = [ 80 ]; - networking.firewall.allowPing = true; }; }; diff --git a/nixos/tests/containers-restart_networking.nix b/nixos/tests/containers-restart_networking.nix index aeb0a6e68e21..0fb3b591e9f9 100644 --- a/nixos/tests/containers-restart_networking.nix +++ b/nixos/tests/containers-restart_networking.nix @@ -10,7 +10,6 @@ let hostBridge = "br0"; config = { networking.firewall.enable = false; - networking.firewall.allowPing = true; networking.interfaces.eth0.ipv4.addresses = [ { address = "192.168.1.122"; prefixLength = 24; } ]; diff --git a/nixos/tests/docker-tools.nix b/nixos/tests/docker-tools.nix index db4eacc37287..360b32faae72 100644 --- a/nixos/tests/docker-tools.nix +++ b/nixos/tests/docker-tools.nix @@ -20,7 +20,10 @@ import ./make-test.nix ({ pkgs, ... }: { '' $docker->waitForUnit("sockets.target"); + # Ensure Docker images use a stable date by default $docker->succeed("docker load --input='${pkgs.dockerTools.examples.bash}'"); + $docker->succeed("[ '1970-01-01T00:00:01Z' = \"\$(docker inspect ${pkgs.dockerTools.examples.bash.imageName} | ${pkgs.jq}/bin/jq -r .[].Created)\" ]"); + $docker->succeed("docker run --rm ${pkgs.dockerTools.examples.bash.imageName} bash --version"); $docker->succeed("docker rmi ${pkgs.dockerTools.examples.bash.imageName}"); @@ -51,5 +54,13 @@ import ./make-test.nix ({ pkgs, ... }: { $docker->succeed("docker run --rm runasrootextracommands cat extraCommands"); $docker->succeed("docker run --rm runasrootextracommands cat runAsRoot"); $docker->succeed("docker rmi '${pkgs.dockerTools.examples.runAsRootExtraCommands.imageName}'"); + + # Ensure Docker images can use an unstable date + $docker->succeed("docker load --input='${pkgs.dockerTools.examples.bash}'"); + $docker->succeed("[ '1970-01-01T00:00:01Z' != \"\$(docker inspect ${pkgs.dockerTools.examples.unstableDate.imageName} | ${pkgs.jq}/bin/jq -r .[].Created)\" ]"); + + # Ensure Layered Docker images work + $docker->succeed("docker load --input='${pkgs.dockerTools.examples.layered-image}'"); + $docker->succeed("docker run --rm ${pkgs.dockerTools.examples.layered-image.imageName}"); ''; }) diff --git a/nixos/tests/ferm.nix b/nixos/tests/ferm.nix index 24b74df85ad1..b8e8663e3ad2 100644 --- a/nixos/tests/ferm.nix +++ b/nixos/tests/ferm.nix @@ -11,6 +11,7 @@ import ./make-test.nix ({ pkgs, ...} : { with pkgs.lib; { networking = { + dhcpcd.enable = false; interfaces.eth1.ipv6.addresses = mkOverride 0 [ { address = "fd00::2"; prefixLength = 64; } ]; interfaces.eth1.ipv4.addresses = mkOverride 0 [ { address = "192.168.1.2"; prefixLength = 24; } ]; }; @@ -20,6 +21,7 @@ import ./make-test.nix ({ pkgs, ...} : { with pkgs.lib; { networking = { + dhcpcd.enable = false; interfaces.eth1.ipv6.addresses = mkOverride 0 [ { address = "fd00::1"; prefixLength = 64; } ]; interfaces.eth1.ipv4.addresses = mkOverride 0 [ { address = "192.168.1.1"; prefixLength = 24; } ]; }; @@ -51,7 +53,7 @@ import ./make-test.nix ({ pkgs, ...} : { '' startAll; - $client->waitForUnit("network.target"); + $client->waitForUnit("network-online.target"); $server->waitForUnit("ferm.service"); $server->waitForUnit("nginx.service"); $server->waitUntilSucceeds("ss -ntl | grep -q 80"); diff --git a/nixos/tests/gdk-pixbuf.nix b/nixos/tests/gdk-pixbuf.nix index b20f61b5ffe2..005c5111da2b 100644 --- a/nixos/tests/gdk-pixbuf.nix +++ b/nixos/tests/gdk-pixbuf.nix @@ -10,10 +10,12 @@ import ./make-test.nix ({ pkgs, ... }: { environment.systemPackages = with pkgs; [ gnome-desktop-testing ]; environment.variables.XDG_DATA_DIRS = [ "${pkgs.gdk_pixbuf.installedTests}/share" ]; - virtualisation.memorySize = 4096; # Tests allocate a lot of memory trying to exploit a CVE + # Tests allocate a lot of memory trying to exploit a CVE + # but qemu-system-i386 has a 2047M memory limit + virtualisation.memorySize = if pkgs.stdenv.isi686 then 2047 else 4096; }; testScript = '' - $machine->succeed("gnome-desktop-testing-runner"); + $machine->succeed("gnome-desktop-testing-runner -t 1800"); # increase timeout to 1800s ''; }) diff --git a/nixos/tests/hibernate.nix b/nixos/tests/hibernate.nix index 1f98bb739f21..274aa7becc82 100644 --- a/nixos/tests/hibernate.nix +++ b/nixos/tests/hibernate.nix @@ -35,8 +35,8 @@ import ./make-test.nix (pkgs: { $machine->waitForOpenPort(4444); $machine->succeed("systemctl hibernate &"); $machine->waitForShutdown; + $probe->waitForUnit("multi-user.target"); $machine->start; - $probe->waitForUnit("network.target"); $probe->waitUntilSucceeds("echo test | nc machine 4444 -N"); ''; diff --git a/nixos/tests/home-assistant.nix b/nixos/tests/home-assistant.nix index 2d74b59bca46..0b3da0d59c68 100644 --- a/nixos/tests/home-assistant.nix +++ b/nixos/tests/home-assistant.nix @@ -74,7 +74,6 @@ in { print "$log\n"; # Check that no errors were logged - # The timer can get out of sync due to Hydra's load, so this error is ignored - $hass->fail("cat ${configDir}/home-assistant.log | grep -vF 'Timer got out of sync' | grep -qF ERROR"); + $hass->fail("cat ${configDir}/home-assistant.log | grep -qF ERROR"); ''; }) diff --git a/nixos/tests/hound.nix b/nixos/tests/hound.nix index f21c0ad58a85..cb8e25332c07 100644 --- a/nixos/tests/hound.nix +++ b/nixos/tests/hound.nix @@ -52,7 +52,7 @@ import ./make-test.nix ({ pkgs, ... } : { $machine->waitForUnit("network.target"); $machine->waitForUnit("hound.service"); $machine->waitForOpenPort(6080); - $machine->succeed('curl http://127.0.0.1:6080/api/v1/search\?stats\=fosho\&repos\=\*\&rng=%3A20\&q\=hi\&files\=\&i=nope | grep "Filename" | grep "hello"'); + $machine->waitUntilSucceeds('curl http://127.0.0.1:6080/api/v1/search\?stats\=fosho\&repos\=\*\&rng=%3A20\&q\=hi\&files\=\&i=nope | grep "Filename" | grep "hello"'); ''; }) diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix index 3d31c8dc4457..3f9fa0e6016c 100644 --- a/nixos/tests/installer.nix +++ b/nixos/tests/installer.nix @@ -282,9 +282,9 @@ in { { createPartitions = '' $machine->succeed( - "parted --script /dev/vda mklabel msdos", - "parted --script /dev/vda -- mkpart primary linux-swap 1M 1024M", - "parted --script /dev/vda -- mkpart primary ext2 1024M -1s", + "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + . " mkpart primary linux-swap 1M 1024M" + . " mkpart primary ext2 1024M -1s", "udevadm settle", "mkswap /dev/vda1 -L swap", "swapon -L swap", @@ -299,11 +299,11 @@ in { { createPartitions = '' $machine->succeed( - "parted --script /dev/vda mklabel gpt", - "parted --script /dev/vda -- mkpart ESP fat32 1M 50MiB", # /boot - "parted --script /dev/vda -- set 1 boot on", - "parted --script /dev/vda -- mkpart primary linux-swap 50MiB 1024MiB", - "parted --script /dev/vda -- mkpart primary ext2 1024MiB -1MiB", # / + "flock /dev/vda parted --script /dev/vda -- mklabel gpt" + . " mkpart ESP fat32 1M 50MiB" # /boot + . " set 1 boot on" + . " mkpart primary linux-swap 50MiB 1024MiB" + . " mkpart primary ext2 1024MiB -1MiB", # / "udevadm settle", "mkswap /dev/vda2 -L swap", "swapon -L swap", @@ -321,11 +321,11 @@ in { { createPartitions = '' $machine->succeed( - "parted --script /dev/vda mklabel gpt", - "parted --script /dev/vda -- mkpart ESP fat32 1M 50MiB", # /boot - "parted --script /dev/vda -- set 1 boot on", - "parted --script /dev/vda -- mkpart primary linux-swap 50MiB 1024MiB", - "parted --script /dev/vda -- mkpart primary ext2 1024MiB -1MiB", # / + "flock /dev/vda parted --script /dev/vda -- mklabel gpt" + . " mkpart ESP fat32 1M 50MiB" # /boot + . " set 1 boot on" + . " mkpart primary linux-swap 50MiB 1024MiB" + . " mkpart primary ext2 1024MiB -1MiB", # / "udevadm settle", "mkswap /dev/vda2 -L swap", "swapon -L swap", @@ -345,10 +345,10 @@ in { { createPartitions = '' $machine->succeed( - "parted --script /dev/vda mklabel msdos", - "parted --script /dev/vda -- mkpart primary ext2 1M 50MB", # /boot - "parted --script /dev/vda -- mkpart primary linux-swap 50MB 1024M", - "parted --script /dev/vda -- mkpart primary ext2 1024M -1s", # / + "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + . " mkpart primary ext2 1M 50MB" # /boot + . " mkpart primary linux-swap 50MB 1024M" + . " mkpart primary ext2 1024M -1s", # / "udevadm settle", "mkswap /dev/vda2 -L swap", "swapon -L swap", @@ -366,10 +366,10 @@ in { { createPartitions = '' $machine->succeed( - "parted --script /dev/vda mklabel msdos", - "parted --script /dev/vda -- mkpart primary ext2 1M 50MB", # /boot - "parted --script /dev/vda -- mkpart primary linux-swap 50MB 1024M", - "parted --script /dev/vda -- mkpart primary ext2 1024M -1s", # / + "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + . " mkpart primary ext2 1M 50MB" # /boot + . " mkpart primary linux-swap 50MB 1024M" + . " mkpart primary ext2 1024M -1s", # / "udevadm settle", "mkswap /dev/vda2 -L swap", "swapon -L swap", @@ -402,9 +402,9 @@ in { createPartitions = '' $machine->succeed( - "parted --script /dev/vda mklabel msdos", - "parted --script /dev/vda -- mkpart primary linux-swap 1M 1024M", - "parted --script /dev/vda -- mkpart primary 1024M -1s", + "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + . " mkpart primary linux-swap 1M 1024M" + . " mkpart primary 1024M -1s", "udevadm settle", "mkswap /dev/vda1 -L swap", @@ -425,11 +425,11 @@ in { { createPartitions = '' $machine->succeed( - "parted --script /dev/vda mklabel msdos", - "parted --script /dev/vda -- mkpart primary 1M 2048M", # PV1 - "parted --script /dev/vda -- set 1 lvm on", - "parted --script /dev/vda -- mkpart primary 2048M -1s", # PV2 - "parted --script /dev/vda -- set 2 lvm on", + "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + . " mkpart primary 1M 2048M" # PV1 + . " set 1 lvm on" + . " mkpart primary 2048M -1s" # PV2 + . " set 2 lvm on", "udevadm settle", "pvcreate /dev/vda1 /dev/vda2", "vgcreate MyVolGroup /dev/vda1 /dev/vda2", @@ -447,10 +447,10 @@ in { luksroot = makeInstallerTest "luksroot" { createPartitions = '' $machine->succeed( - "parted --script /dev/vda mklabel msdos", - "parted --script /dev/vda -- mkpart primary ext2 1M 50MB", # /boot - "parted --script /dev/vda -- mkpart primary linux-swap 50M 1024M", - "parted --script /dev/vda -- mkpart primary 1024M -1s", # LUKS + "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + . " mkpart primary ext2 1M 50MB" # /boot + . " mkpart primary linux-swap 50M 1024M" + . " mkpart primary 1024M -1s", # LUKS "udevadm settle", "mkswap /dev/vda2 -L swap", "swapon -L swap", @@ -481,11 +481,11 @@ in { filesystemEncryptedWithKeyfile = makeInstallerTest "filesystemEncryptedWithKeyfile" { createPartitions = '' $machine->succeed( - "parted --script /dev/vda mklabel msdos", - "parted --script /dev/vda -- mkpart primary ext2 1M 50MB", # /boot - "parted --script /dev/vda -- mkpart primary linux-swap 50M 1024M", - "parted --script /dev/vda -- mkpart primary 1024M 1280M", # LUKS with keyfile - "parted --script /dev/vda -- mkpart primary 1280M -1s", + "flock /dev/vda parted --script /dev/vda -- mklabel msdos" + . " mkpart primary ext2 1M 50MB" # /boot + . " mkpart primary linux-swap 50M 1024M" + . " mkpart primary 1024M 1280M" # LUKS with keyfile + . " mkpart primary 1280M -1s", "udevadm settle", "mkswap /dev/vda2 -L swap", "swapon -L swap", @@ -520,7 +520,7 @@ in { { createPartitions = '' $machine->succeed( - "parted --script /dev/vda --" + "flock /dev/vda parted --script /dev/vda --" . " mklabel msdos" . " mkpart primary ext2 1M 100MB" # /boot . " mkpart extended 100M -1s" @@ -531,8 +531,10 @@ in { "udevadm settle", "ls -l /dev/vda* >&2", "cat /proc/partitions >&2", + "udevadm control --stop-exec-queue", "mdadm --create --force /dev/md0 --metadata 1.2 --level=raid1 --raid-devices=2 /dev/vda5 /dev/vda6", "mdadm --create --force /dev/md1 --metadata 1.2 --level=raid1 --raid-devices=2 /dev/vda7 /dev/vda8", + "udevadm control --start-exec-queue", "udevadm settle", "mkswap -f /dev/md1 -L swap", "swapon -L swap", @@ -555,14 +557,15 @@ in { { createPartitions = '' $machine->succeed( - "parted --script /dev/sda mklabel msdos", - "parted --script /dev/sda -- mkpart primary linux-swap 1M 1024M", - "parted --script /dev/sda -- mkpart primary ext2 1024M -1s", + "flock /dev/sda parted --script /dev/sda -- mklabel msdos" + . " mkpart primary linux-swap 1M 1024M" + . " mkpart primary ext2 1024M -1s", "udevadm settle", "mkswap /dev/sda1 -L swap", "swapon -L swap", "mkfs.ext3 -L nixos /dev/sda2", "mount LABEL=nixos /mnt", + "mkdir -p /mnt/tmp", ); ''; grubVersion = 1; diff --git a/nixos/tests/kernel-copperhead.nix b/nixos/tests/kernel-copperhead.nix deleted file mode 100644 index 652fbf055373..000000000000 --- a/nixos/tests/kernel-copperhead.nix +++ /dev/null @@ -1,19 +0,0 @@ -import ./make-test.nix ({ pkgs, ...} : { - name = "kernel-copperhead"; - meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ nequissimus ]; - }; - - machine = { pkgs, ... }: - { - boot.kernelPackages = pkgs.linuxPackages_copperhead_lts; - }; - - testScript = - '' - $machine->succeed("uname -a"); - $machine->succeed("uname -s | grep 'Linux'"); - $machine->succeed("uname -a | grep '${pkgs.linuxPackages_copperhead_lts.kernel.modDirVersion}'"); - $machine->succeed("uname -a | grep 'hardened'"); - ''; -}) diff --git a/nixos/tests/misc.nix b/nixos/tests/misc.nix index b0bc1d083b16..3ad55651b112 100644 --- a/nixos/tests/misc.nix +++ b/nixos/tests/misc.nix @@ -14,7 +14,7 @@ import ./make-test.nix ({ pkgs, ...} : rec { { swapDevices = mkOverride 0 [ { device = "/root/swapfile"; size = 128; } ]; environment.variables.EDITOR = mkOverride 0 "emacs"; - services.nixosManual.enable = mkOverride 0 true; + documentation.nixos.enable = mkOverride 0 true; systemd.tmpfiles.rules = [ "d /tmp 1777 root root 10d" ]; fileSystems = mkVMOverride { "/tmp2" = { fsType = "tmpfs"; @@ -78,6 +78,8 @@ import ./make-test.nix ({ pkgs, ...} : rec { # Test whether we have a reboot record in wtmp. subtest "reboot-wtmp", sub { + $machine->shutdown; + $machine->waitForUnit('multi-user.target'); $machine->succeed("last | grep reboot >&2"); }; diff --git a/nixos/tests/nat.nix b/nixos/tests/nat.nix index 9c280fe8b5b6..04b4f0f045f0 100644 --- a/nixos/tests/nat.nix +++ b/nixos/tests/nat.nix @@ -11,7 +11,6 @@ import ./make-test.nix ({ pkgs, lib, withFirewall, withConntrackHelpers ? false, lib.mkMerge [ { virtualisation.vlans = [ 2 1 ]; networking.firewall.enable = withFirewall; - networking.firewall.allowPing = true; networking.nat.internalIPs = [ "192.168.1.0/24" ]; networking.nat.externalInterface = "eth1"; } @@ -33,7 +32,6 @@ import ./make-test.nix ({ pkgs, lib, withFirewall, withConntrackHelpers ? false, { pkgs, nodes, ... }: lib.mkMerge [ { virtualisation.vlans = [ 1 ]; - networking.firewall.allowPing = true; networking.defaultGateway = (pkgs.lib.head nodes.router.config.networking.interfaces.eth2.ipv4.addresses).address; } diff --git a/nixos/tests/networking.nix b/nixos/tests/networking.nix index 02bd4bd98079..d1d4fd41dda6 100644 --- a/nixos/tests/networking.nix +++ b/nixos/tests/networking.nix @@ -17,7 +17,6 @@ let networking = { useDHCP = false; useNetworkd = networkd; - firewall.allowPing = true; firewall.checkReversePath = true; firewall.allowedUDPPorts = [ 547 ]; interfaces = mkOverride 0 (listToAttrs (flip map vlanIfs (n: @@ -86,7 +85,6 @@ let virtualisation.vlans = [ 1 2 ]; networking = { useNetworkd = networkd; - firewall.allowPing = true; useDHCP = false; defaultGateway = "192.168.1.1"; interfaces.eth1.ipv4.addresses = mkOverride 0 [ @@ -139,7 +137,6 @@ let virtualisation.vlans = [ 1 2 ]; networking = { useNetworkd = networkd; - firewall.allowPing = true; useDHCP = true; interfaces.eth1 = { ipv4.addresses = mkOverride 0 [ ]; @@ -194,7 +191,6 @@ let virtualisation.vlans = [ 1 2 ]; networking = { useNetworkd = networkd; - firewall.allowPing = true; useDHCP = false; interfaces.eth1 = { ipv4.addresses = mkOverride 0 [ ]; @@ -234,7 +230,6 @@ let virtualisation.vlans = [ 1 2 ]; networking = { useNetworkd = networkd; - firewall.allowPing = true; useDHCP = false; bonds.bond = { interfaces = [ "eth1" "eth2" ]; @@ -271,7 +266,6 @@ let virtualisation.vlans = [ vlan ]; networking = { useNetworkd = networkd; - firewall.allowPing = true; useDHCP = false; interfaces.eth1.ipv4.addresses = mkOverride 0 [ { inherit address; prefixLength = 24; } ]; @@ -285,7 +279,6 @@ let virtualisation.vlans = [ 1 2 ]; networking = { useNetworkd = networkd; - firewall.allowPing = true; useDHCP = false; bridges.bridge.interfaces = [ "eth1" "eth2" ]; interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; @@ -329,7 +322,6 @@ let # reverse path filtering rules for the macvlan interface seem # to be incorrect, causing the test to fail. Disable temporarily. firewall.checkReversePath = false; - firewall.allowPing = true; useDHCP = true; macvlans.macvlan.interface = "eth1"; interfaces.eth1.ipv4.addresses = mkOverride 0 [ ]; @@ -415,7 +407,6 @@ let #virtualisation.vlans = [ 1 ]; networking = { useNetworkd = networkd; - firewall.allowPing = true; useDHCP = false; vlans.vlan = { id = 1; @@ -467,7 +458,7 @@ let # Wait for networking to come up $machine->start; - $machine->waitForUnit("network.target"); + $machine->waitForUnit("network-online.target"); # Test interfaces set up my $list = $machine->succeed("ip tuntap list | sort"); @@ -479,7 +470,9 @@ let # Test interfaces clean up $machine->succeed("systemctl stop network-addresses-tap0"); + $machine->sleep(10); $machine->succeed("systemctl stop network-addresses-tun0"); + $machine->sleep(10); my $residue = $machine->succeed("ip tuntap list"); $residue eq "" or die( "Some virtual interface has not been properly cleaned:\n", diff --git a/nixos/tests/nextcloud/basic.nix b/nixos/tests/nextcloud/basic.nix new file mode 100644 index 000000000000..c3b710f0f904 --- /dev/null +++ b/nixos/tests/nextcloud/basic.nix @@ -0,0 +1,56 @@ +import ../make-test.nix ({ pkgs, ...}: let + adminpass = "notproduction"; + adminuser = "root"; +in { + name = "nextcloud-basic"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ globin eqyiel ]; + }; + + nodes = { + # The only thing the client needs to do is download a file. + client = { ... }: {}; + + nextcloud = { config, pkgs, ... }: { + networking.firewall.allowedTCPPorts = [ 80 ]; + + services.nextcloud = { + enable = true; + nginx.enable = true; + hostName = "nextcloud"; + config = { + # Don't inherit adminuser since "root" is supposed to be the default + inherit adminpass; + }; + }; + }; + }; + + testScript = let + withRcloneEnv = pkgs.writeScript "with-rclone-env" '' + #!${pkgs.stdenv.shell} + export RCLONE_CONFIG_NEXTCLOUD_TYPE=webdav + export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/webdav/" + export RCLONE_CONFIG_NEXTCLOUD_VENDOR="nextcloud" + export RCLONE_CONFIG_NEXTCLOUD_USER="${adminuser}" + export RCLONE_CONFIG_NEXTCLOUD_PASS="$(${pkgs.rclone}/bin/rclone obscure ${adminpass})" + "''${@}" + ''; + copySharedFile = pkgs.writeScript "copy-shared-file" '' + #!${pkgs.stdenv.shell} + echo 'hi' | ${withRcloneEnv} ${pkgs.rclone}/bin/rclone rcat nextcloud:test-shared-file + ''; + + diffSharedFile = pkgs.writeScript "diff-shared-file" '' + #!${pkgs.stdenv.shell} + diff <(echo 'hi') <(${pkgs.rclone}/bin/rclone cat nextcloud:test-shared-file) + ''; + in '' + startAll(); + $nextcloud->waitForUnit("multi-user.target"); + $nextcloud->succeed("curl -sSf http://nextcloud/login"); + $nextcloud->succeed("${withRcloneEnv} ${copySharedFile}"); + $client->waitForUnit("multi-user.target"); + $client->succeed("${withRcloneEnv} ${diffSharedFile}"); + ''; +}) diff --git a/nixos/tests/nextcloud/default.nix b/nixos/tests/nextcloud/default.nix new file mode 100644 index 000000000000..66da6794b961 --- /dev/null +++ b/nixos/tests/nextcloud/default.nix @@ -0,0 +1,6 @@ +{ system ? builtins.currentSystem }: +{ + basic = import ./basic.nix { inherit system; }; + with-postgresql-and-redis = import ./with-postgresql-and-redis.nix { inherit system; }; + with-mysql-and-memcached = import ./with-mysql-and-memcached.nix { inherit system; }; +} diff --git a/nixos/tests/nextcloud/with-mysql-and-memcached.nix b/nixos/tests/nextcloud/with-mysql-and-memcached.nix new file mode 100644 index 000000000000..c0d347238b47 --- /dev/null +++ b/nixos/tests/nextcloud/with-mysql-and-memcached.nix @@ -0,0 +1,97 @@ +import ../make-test.nix ({ pkgs, ...}: let + adminpass = "hunter2"; + adminuser = "root"; +in { + name = "nextcloud-with-mysql-and-memcached"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ eqyiel ]; + }; + + nodes = { + # The only thing the client needs to do is download a file. + client = { ... }: {}; + + nextcloud = { config, pkgs, ... }: { + networking.firewall.allowedTCPPorts = [ 80 ]; + + services.nextcloud = { + enable = true; + hostName = "nextcloud"; + nginx.enable = true; + https = true; + caching = { + apcu = true; + redis = false; + memcached = true; + }; + config = { + dbtype = "mysql"; + dbname = "nextcloud"; + dbuser = "nextcloud"; + dbhost = "127.0.0.1"; + dbport = 3306; + dbpass = "hunter2"; + # Don't inherit adminuser since "root" is supposed to be the default + inherit adminpass; + }; + }; + + services.mysql = { + enable = true; + bind = "127.0.0.1"; + package = pkgs.mariadb; + initialScript = pkgs.writeText "mysql-init" '' + CREATE USER 'nextcloud'@'localhost' IDENTIFIED BY 'hunter2'; + CREATE DATABASE IF NOT EXISTS nextcloud; + GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, + CREATE TEMPORARY TABLES ON nextcloud.* TO 'nextcloud'@'localhost' + IDENTIFIED BY 'hunter2'; + FLUSH privileges; + ''; + }; + + systemd.services."nextcloud-setup"= { + requires = ["mysql.service"]; + after = ["mysql.service"]; + }; + + services.memcached.enable = true; + }; + }; + + testScript = let + configureMemcached = pkgs.writeScript "configure-memcached" '' + #!${pkgs.stdenv.shell} + nextcloud-occ config:system:set memcached_servers 0 0 --value 127.0.0.1 --type string + nextcloud-occ config:system:set memcached_servers 0 1 --value 11211 --type integer + nextcloud-occ config:system:set memcache.local --value '\OC\Memcache\APCu' --type string + nextcloud-occ config:system:set memcache.distributed --value '\OC\Memcache\Memcached' --type string + ''; + withRcloneEnv = pkgs.writeScript "with-rclone-env" '' + #!${pkgs.stdenv.shell} + export RCLONE_CONFIG_NEXTCLOUD_TYPE=webdav + export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/webdav/" + export RCLONE_CONFIG_NEXTCLOUD_VENDOR="nextcloud" + export RCLONE_CONFIG_NEXTCLOUD_USER="${adminuser}" + export RCLONE_CONFIG_NEXTCLOUD_PASS="$(${pkgs.rclone}/bin/rclone obscure ${adminpass})" + ''; + copySharedFile = pkgs.writeScript "copy-shared-file" '' + #!${pkgs.stdenv.shell} + echo 'hi' | ${pkgs.rclone}/bin/rclone rcat nextcloud:test-shared-file + ''; + + diffSharedFile = pkgs.writeScript "diff-shared-file" '' + #!${pkgs.stdenv.shell} + diff <(echo 'hi') <(${pkgs.rclone}/bin/rclone cat nextcloud:test-shared-file) + ''; + in '' + startAll(); + $nextcloud->waitForUnit("multi-user.target"); + $nextcloud->succeed("${configureMemcached}"); + $nextcloud->succeed("curl -sSf http://nextcloud/login"); + $nextcloud->succeed("${withRcloneEnv} ${copySharedFile}"); + $client->waitForUnit("multi-user.target"); + $client->succeed("${withRcloneEnv} ${diffSharedFile}"); + + ''; +}) diff --git a/nixos/tests/nextcloud/with-postgresql-and-redis.nix b/nixos/tests/nextcloud/with-postgresql-and-redis.nix new file mode 100644 index 000000000000..0351d4db69ac --- /dev/null +++ b/nixos/tests/nextcloud/with-postgresql-and-redis.nix @@ -0,0 +1,130 @@ +import ../make-test.nix ({ pkgs, ...}: let + adminpass = "hunter2"; + adminuser = "custom-admin-username"; +in { + name = "nextcloud-with-postgresql-and-redis"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ eqyiel ]; + }; + + nodes = { + # The only thing the client needs to do is download a file. + client = { ... }: {}; + + nextcloud = { config, pkgs, ... }: { + networking.firewall.allowedTCPPorts = [ 80 ]; + + services.nextcloud = { + enable = true; + hostName = "nextcloud"; + nginx.enable = true; + caching = { + apcu = false; + redis = true; + memcached = false; + }; + config = { + dbtype = "pgsql"; + dbname = "nextcloud"; + dbuser = "nextcloud"; + dbhost = "localhost"; + dbpassFile = toString (pkgs.writeText "db-pass-file" '' + hunter2 + ''); + inherit adminuser; + adminpassFile = toString (pkgs.writeText "admin-pass-file" '' + ${adminpass} + ''); + }; + }; + + services.redis = { + unixSocket = "/var/run/redis/redis.sock"; + enable = true; + extraConfig = '' + unixsocketperm 770 + ''; + }; + + systemd.services.redis = { + preStart = '' + mkdir -p /var/run/redis + chown ${config.services.redis.user}:${config.services.nginx.group} /var/run/redis + ''; + serviceConfig.PermissionsStartOnly = true; + }; + + systemd.services."nextcloud-setup"= { + requires = ["postgresql.service"]; + after = [ + "postgresql.service" + "chown-redis-socket.service" + ]; + }; + + # At the time of writing, redis creates its socket with the "nobody" + # group. I figure this is slightly less bad than making the socket world + # readable. + systemd.services."chown-redis-socket" = { + enable = true; + script = '' + until ${pkgs.redis}/bin/redis-cli ping; do + echo "waiting for redis..." + sleep 1 + done + chown ${config.services.redis.user}:${config.services.nginx.group} /var/run/redis/redis.sock + ''; + after = [ "redis.service" ]; + requires = [ "redis.service" ]; + wantedBy = [ "redis.service" ]; + serviceConfig = { + Type = "oneshot"; + }; + }; + + services.postgresql = { + enable = true; + initialScript = pkgs.writeText "psql-init" '' + create role nextcloud with login password 'hunter2'; + create database nextcloud with owner nextcloud; + ''; + }; + }; + }; + + testScript = let + configureRedis = pkgs.writeScript "configure-redis" '' + #!${pkgs.stdenv.shell} + nextcloud-occ config:system:set redis 'host' --value '/var/run/redis/redis.sock' --type string + nextcloud-occ config:system:set redis 'port' --value 0 --type integer + nextcloud-occ config:system:set memcache.local --value '\OC\Memcache\Redis' --type string + nextcloud-occ config:system:set memcache.locking --value '\OC\Memcache\Redis' --type string + ''; + withRcloneEnv = pkgs.writeScript "with-rclone-env" '' + #!${pkgs.stdenv.shell} + export RCLONE_CONFIG_NEXTCLOUD_TYPE=webdav + export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/webdav/" + export RCLONE_CONFIG_NEXTCLOUD_VENDOR="nextcloud" + export RCLONE_CONFIG_NEXTCLOUD_USER="${adminuser}" + export RCLONE_CONFIG_NEXTCLOUD_PASS="$(${pkgs.rclone}/bin/rclone obscure ${adminpass})" + "''${@}" + ''; + copySharedFile = pkgs.writeScript "copy-shared-file" '' + #!${pkgs.stdenv.shell} + echo 'hi' | ${pkgs.rclone}/bin/rclone rcat nextcloud:test-shared-file + ''; + + diffSharedFile = pkgs.writeScript "diff-shared-file" '' + #!${pkgs.stdenv.shell} + diff <(echo 'hi') <(${pkgs.rclone}/bin/rclone cat nextcloud:test-shared-file) + ''; + in '' + startAll(); + $nextcloud->waitForUnit("multi-user.target"); + $nextcloud->succeed("${configureRedis}"); + $nextcloud->succeed("curl -sSf http://nextcloud/login"); + $nextcloud->succeed("${withRcloneEnv} ${copySharedFile}"); + $client->waitForUnit("multi-user.target"); + $client->succeed("${withRcloneEnv} ${diffSharedFile}"); + ''; +}) diff --git a/nixos/tests/nix-ssh-serve.nix b/nixos/tests/nix-ssh-serve.nix index aa366d8612d7..494d55121eb1 100644 --- a/nixos/tests/nix-ssh-serve.nix +++ b/nixos/tests/nix-ssh-serve.nix @@ -14,8 +14,8 @@ in keys = [ snakeOilPublicKey ]; protocol = "ssh-ng"; }; - server.nix.package = pkgs.nixUnstable; - client.nix.package = pkgs.nixUnstable; + server.nix.package = pkgs.nix; + client.nix.package = pkgs.nix; }; testScript = '' startAll; diff --git a/nixos/tests/novacomd.nix b/nixos/tests/novacomd.nix index 2b56aee0a2e7..4eb60c0feb5c 100644 --- a/nixos/tests/novacomd.nix +++ b/nixos/tests/novacomd.nix @@ -9,12 +9,16 @@ import ./make-test.nix ({ pkgs, ...} : { }; testScript = '' - startAll; + $machine->waitForUnit("multi-user.target"); + # multi-user.target wants novacomd.service, but let's make sure $machine->waitForUnit("novacomd.service"); # Check status and try connecting with novacom $machine->succeed("systemctl status novacomd.service >&2"); + # to prevent non-deterministic failure, + # make sure the daemon is really listening + $machine->waitForOpenPort(6968); $machine->succeed("novacom -l"); # Stop the daemon, double-check novacom fails if daemon isn't working @@ -23,6 +27,8 @@ import ./make-test.nix ({ pkgs, ...} : { # And back again for good measure $machine->startJob("novacomd"); + # make sure the daemon is really listening + $machine->waitForOpenPort(6968); $machine->succeed("novacom -l"); ''; }) diff --git a/nixos/tests/opensmtpd.nix b/nixos/tests/opensmtpd.nix index 5079779f35b4..4d3479168f70 100644 --- a/nixos/tests/opensmtpd.nix +++ b/nixos/tests/opensmtpd.nix @@ -17,11 +17,12 @@ import ./make-test.nix { extraServerArgs = [ "-v" ]; serverConfiguration = '' listen on 0.0.0.0 + action do_relay relay # DO NOT DO THIS IN PRODUCTION! # Setting up authentication requires a certificate which is painful in # a test environment, but THIS WOULD BE DANGEROUS OUTSIDE OF A # WELL-CONTROLLED ENVIRONMENT! - accept from any for any relay + match from any for any action do_relay ''; }; }; @@ -41,8 +42,9 @@ import ./make-test.nix { extraServerArgs = [ "-v" ]; serverConfiguration = '' listen on 0.0.0.0 - accept from any for local deliver to mda \ + action dovecot_deliver mda \ "${pkgs.dovecot}/libexec/dovecot/deliver -d %{user.username}" + match from any for local action dovecot_deliver ''; }; services.dovecot2 = { @@ -102,11 +104,17 @@ import ./make-test.nix { testScript = '' startAll; - $client->waitForUnit("network.target"); + $client->waitForUnit("network-online.target"); $smtp1->waitForUnit('opensmtpd'); $smtp2->waitForUnit('opensmtpd'); $smtp2->waitForUnit('dovecot2'); + # To prevent sporadic failures during daemon startup, make sure + # services are listening on their ports before sending requests + $smtp1->waitForOpenPort(25); + $smtp2->waitForOpenPort(25); + $smtp2->waitForOpenPort(143); + $client->succeed('send-a-test-mail'); $smtp1->waitUntilFails('smtpctl show queue | egrep .'); $smtp2->waitUntilFails('smtpctl show queue | egrep .'); diff --git a/nixos/tests/plasma5.nix b/nixos/tests/plasma5.nix index eb705536827e..788c8719c8d2 100644 --- a/nixos/tests/plasma5.nix +++ b/nixos/tests/plasma5.nix @@ -26,31 +26,20 @@ import ./make-test.nix ({ pkgs, ...} : services.xserver.displayManager.sddm.theme = "breeze-ocr-theme"; services.xserver.desktopManager.plasma5.enable = true; services.xserver.desktopManager.default = "plasma5"; + services.xserver.displayManager.sddm.autoLogin = { + enable = true; + user = "alice"; + }; virtualisation.memorySize = 1024; environment.systemPackages = [ sddm_theme ]; - - # fontconfig-penultimate-0.3.3 -> 0.3.4 broke OCR apparently, but no idea why. - nixpkgs.config.packageOverrides = superPkgs: { - fontconfig-penultimate = superPkgs.fontconfig-penultimate.override { - version = "0.3.3"; - sha256 = "1z76jbkb0nhf4w7fy647yyayqr4q02fgk6w58k0yi700p0m3h4c9"; - }; - }; }; - enableOCR = true; - testScript = { nodes, ... }: let user = nodes.machine.config.users.users.alice; xdo = "${pkgs.xdotool}/bin/xdotool"; in '' startAll; - # Wait for display manager to start - $machine->waitForText(qr/${user.description}/); - $machine->screenshot("sddm"); - - # Log in - $machine->sendChars("${user.password}\n"); + # wait for log in $machine->waitForFile("/home/alice/.Xauthority"); $machine->succeed("xauth merge ~alice/.Xauthority"); diff --git a/nixos/tests/postgis.nix b/nixos/tests/postgis.nix index f8b63c5b6a27..49be0672a8e5 100644 --- a/nixos/tests/postgis.nix +++ b/nixos/tests/postgis.nix @@ -9,7 +9,7 @@ import ./make-test.nix ({ pkgs, ...} : { { pkgs, ... }: { - services.postgresql = let mypg = pkgs.postgresql100; in { + services.postgresql = let mypg = pkgs.postgresql_11; in { enable = true; package = mypg; extraPlugins = [ (pkgs.postgis.override { postgresql = mypg; }) ]; diff --git a/nixos/tests/prometheus-exporters.nix b/nixos/tests/prometheus-exporters.nix new file mode 100644 index 000000000000..5d1e004c5dd1 --- /dev/null +++ b/nixos/tests/prometheus-exporters.nix @@ -0,0 +1,316 @@ +import ./make-test.nix ({ lib, pkgs, ... }: +let + escape' = str: lib.replaceChars [''"'' "$" "\n"] [''\\\"'' "\\$" ""] str; + +/* + * The attrset `exporterTests` contains one attribute + * for each exporter test. Each of these attributes + * is expected to be an attrset containing: + * + * `exporterConfig`: + * this attribute set contains config for the exporter itself + * + * `exporterTest` + * this attribute set contains test instructions + * + * `metricProvider` (optional) + * this attribute contains additional machine config + * + * Example: + * exporterTests.<exporterName> = { + * exporterConfig = { + * enable = true; + * }; + * metricProvider = { + * services.<metricProvider>.enable = true; + * }; + * exporterTest = '' + * waitForUnit("prometheus-<exporterName>-exporter.service"); + * waitForOpenPort("1234"); + * succeed("curl -sSf 'localhost:1234/metrics'"); + * ''; + * }; + * + * # this would generate the following test config: + * + * nodes.<exporterName> = { + * services.prometheus.<exporterName> = { + * enable = true; + * }; + * services.<metricProvider>.enable = true; + * }; + * + * testScript = '' + * $<exporterName>->start(); + * $<exporterName>->waitForUnit("prometheus-<exporterName>-exporter.service"); + * $<exporterName>->waitForOpenPort("1234"); + * $<exporterName>->succeed("curl -sSf 'localhost:1234/metrics'"); + * $<exporterName>->shutdown(); + * ''; + */ + + exporterTests = { + + blackbox = { + exporterConfig = { + enable = true; + configFile = pkgs.writeText "config.yml" (builtins.toJSON { + modules.icmp_v6 = { + prober = "icmp"; + icmp.preferred_ip_protocol = "ip6"; + }; + }); + }; + exporterTest = '' + waitForUnit("prometheus-blackbox-exporter.service"); + waitForOpenPort(9115); + succeed("curl -sSf 'http://localhost:9115/probe?target=localhost&module=icmp_v6' | grep -q 'probe_success 1'"); + ''; + }; + + collectd = { + exporterConfig = { + enable = true; + extraFlags = [ "--web.collectd-push-path /collectd" ]; + }; + exporterTest =let postData = escape' '' + [{ + "values":[23], + "dstypes":["gauge"], + "type":"gauge", + "interval":1000, + "host":"testhost", + "plugin":"testplugin", + "time":$(date +%s) + }] + ''; in '' + waitForUnit("prometheus-collectd-exporter.service"); + waitForOpenPort(9103); + succeed("curl -sSfH 'Content-Type: application/json' -X POST --data \"${postData}\" localhost:9103/collectd"); + succeed("curl -sSf localhost:9103/metrics | grep -q 'collectd_testplugin_gauge{instance=\"testhost\"} 23'"); + ''; + }; + + dnsmasq = { + exporterConfig = { + enable = true; + leasesPath = "/var/lib/dnsmasq/dnsmasq.leases"; + }; + metricProvider = { + services.dnsmasq.enable = true; + }; + exporterTest = '' + waitForUnit("prometheus-dnsmasq-exporter.service"); + waitForOpenPort(9153); + succeed("curl -sSf http://localhost:9153/metrics | grep -q 'dnsmasq_leases 0'"); + ''; + }; + + dovecot = { + exporterConfig = { + enable = true; + scopes = [ "global" ]; + socketPath = "/var/run/dovecot2/old-stats"; + user = "root"; # <- don't use user root in production + }; + metricProvider = { + services.dovecot2.enable = true; + }; + exporterTest = '' + waitForUnit("prometheus-dovecot-exporter.service"); + waitForOpenPort(9166); + succeed("curl -sSf http://localhost:9166/metrics | grep -q 'dovecot_up{scope=\"global\"} 1'"); + ''; + }; + + fritzbox = { # TODO add proper test case + exporterConfig = { + enable = true; + }; + exporterTest = '' + waitForUnit("prometheus-fritzbox-exporter.service"); + waitForOpenPort(9133); + succeed("curl -sSf http://localhost:9133/metrics | grep -q 'fritzbox_exporter_collect_errors 0'"); + ''; + }; + + json = { + exporterConfig = { + enable = true; + url = "http://localhost"; + configFile = pkgs.writeText "json-exporter-conf.json" (builtins.toJSON [{ + name = "json_test_metric"; + path = "$.test"; + }]); + }; + metricProvider = { + systemd.services.prometheus-json-exporter.after = [ "nginx.service" ]; + services.nginx = { + enable = true; + virtualHosts.localhost.locations."/".extraConfig = '' + return 200 "{\"test\":1}"; + ''; + }; + }; + exporterTest = '' + waitForUnit("nginx.service"); + waitForOpenPort(80); + waitForUnit("prometheus-json-exporter.service"); + waitForOpenPort(7979); + succeed("curl -sSf localhost:7979/metrics | grep -q 'json_test_metric 1'"); + ''; + }; + + nginx = { + exporterConfig = { + enable = true; + }; + metricProvider = { + services.nginx = { + enable = true; + statusPage = true; + virtualHosts."/".extraConfig = "return 204;"; + }; + }; + exporterTest = '' + waitForUnit("nginx.service") + waitForUnit("prometheus-nginx-exporter.service") + waitForOpenPort(9113) + succeed("curl -sSf http://localhost:9113/metrics | grep -q 'nginx_up 1'") + ''; + }; + + node = { + exporterConfig = { + enable = true; + }; + exporterTest = '' + waitForUnit("prometheus-node-exporter.service"); + waitForOpenPort(9100); + succeed("curl -sSf http://localhost:9100/metrics | grep -q 'node_exporter_build_info{.\\+} 1'"); + ''; + }; + + postfix = { + exporterConfig = { + enable = true; + }; + metricProvider = { + services.postfix.enable = true; + }; + exporterTest = '' + waitForUnit("prometheus-postfix-exporter.service"); + waitForOpenPort(9154); + succeed("curl -sSf http://localhost:9154/metrics | grep -q 'postfix_smtpd_connects_total 0'"); + ''; + }; + + snmp = { + exporterConfig = { + enable = true; + configuration.default = { + version = 2; + auth.community = "public"; + }; + }; + exporterTest = '' + waitForUnit("prometheus-snmp-exporter.service"); + waitForOpenPort(9116); + succeed("curl -sSf localhost:9116/metrics | grep -q 'snmp_request_errors_total 0'"); + ''; + }; + + surfboard = { + exporterConfig = { + enable = true; + modemAddress = "localhost"; + }; + metricProvider = { + systemd.services.prometheus-surfboard-exporter.after = [ "nginx.service" ]; + services.nginx = { + enable = true; + virtualHosts.localhost.locations."/cgi-bin/status".extraConfig = '' + return 204; + ''; + }; + }; + exporterTest = '' + waitForUnit("nginx.service"); + waitForOpenPort(80); + waitForUnit("prometheus-surfboard-exporter.service"); + waitForOpenPort(9239); + succeed("curl -sSf localhost:9239/metrics | grep -q 'surfboard_up 1'"); + ''; + }; + + tor = { + exporterConfig = { + enable = true; + }; + metricProvider = { + # Note: this does not connect the test environment to the Tor network. + # Client, relay, bridge or exit connectivity are disabled by default. + services.tor.enable = true; + services.tor.controlPort = 9051; + }; + exporterTest = '' + waitForUnit("tor.service"); + waitForOpenPort(9051); + waitForUnit("prometheus-tor-exporter.service"); + waitForOpenPort(9130); + succeed("curl -sSf localhost:9130/metrics | grep -q 'tor_version{.\\+} 1'"); + ''; + }; + + varnish = { + exporterConfig = { + enable = true; + instance = "/var/spool/varnish/varnish"; + group = "varnish"; + }; + metricProvider = { + systemd.services.prometheus-varnish-exporter.after = [ + "varnish.service" + ]; + services.varnish = { + enable = true; + config = '' + vcl 4.0; + backend default { + .host = "127.0.0.1"; + .port = "80"; + } + ''; + }; + }; + exporterTest = '' + waitForUnit("prometheus-varnish-exporter.service"); + waitForOpenPort(9131); + succeed("curl -sSf http://localhost:9131/metrics | grep -q 'varnish_up 1'"); + ''; + }; + }; + + nodes = lib.mapAttrs (exporter: testConfig: lib.mkMerge [{ + services.prometheus.exporters.${exporter} = testConfig.exporterConfig; + } testConfig.metricProvider or {}]) exporterTests; + + testScript = lib.concatStrings (lib.mapAttrsToList (exporter: testConfig: ('' + subtest "${exporter}", sub { + ${"$"+exporter}->start(); + ${lib.concatStringsSep " " (map (line: '' + ${"$"+exporter}->${line}; + '') (lib.splitString "\n" (lib.removeSuffix "\n" testConfig.exporterTest)))} + ${"$"+exporter}->shutdown(); + }; + '')) exporterTests); +in +{ + name = "prometheus-exporters"; + + inherit nodes testScript; + + meta = with lib.maintainers; { + maintainers = [ willibutz ]; + }; +}) diff --git a/nixos/tests/prosody.nix b/nixos/tests/prosody.nix index 5d33aaf8d65d..61ae5bb38ed9 100644 --- a/nixos/tests/prosody.nix +++ b/nixos/tests/prosody.nix @@ -6,6 +6,9 @@ import ./make-test.nix { enable = true; # TODO: use a self-signed certificate c2sRequireEncryption = false; + extraConfig = '' + storage = "sql" + ''; }; environment.systemPackages = let sendMessage = pkgs.writeScriptBin "send-message" '' diff --git a/nixos/tests/quagga.nix b/nixos/tests/quagga.nix index 0ff14a21584a..6aee7ea57f03 100644 --- a/nixos/tests/quagga.nix +++ b/nixos/tests/quagga.nix @@ -66,7 +66,6 @@ import ./make-test.nix ({ pkgs, ... }: virtualisation.vlans = [ 3 ]; networking.defaultGateway = ifAddr nodes.router2 "eth1"; networking.firewall.allowedTCPPorts = [ 80 ]; - networking.firewall.allowPing = true; services.httpd.enable = true; services.httpd.adminAddr = "foo@example.com"; }; diff --git a/nixos/tests/redmine.nix b/nixos/tests/redmine.nix new file mode 100644 index 000000000000..330f72854cac --- /dev/null +++ b/nixos/tests/redmine.nix @@ -0,0 +1,40 @@ +import ./make-test.nix ({ pkgs, lib, ... }: +{ + name = "redmine"; + meta.maintainers = [ lib.maintainers.aanderse ]; + + machine = + { config, pkgs, ... }: + { services.mysql.enable = true; + services.mysql.package = pkgs.mariadb; + services.mysql.ensureDatabases = [ "redmine" ]; + services.mysql.ensureUsers = [ + { name = "redmine"; + ensurePermissions = { "redmine.*" = "ALL PRIVILEGES"; }; + } + ]; + + services.redmine.enable = true; + services.redmine.database.socket = "/run/mysqld/mysqld.sock"; + services.redmine.plugins = { + redmine_env_auth = pkgs.fetchurl { + url = https://github.com/Intera/redmine_env_auth/archive/0.6.zip; + sha256 = "0yyr1yjd8gvvh832wdc8m3xfnhhxzk2pk3gm2psg5w9jdvd6skak"; + }; + }; + services.redmine.themes = { + dkuk-redmine_alex_skin = pkgs.fetchurl { + url = https://bitbucket.org/dkuk/redmine_alex_skin/get/1842ef675ef3.zip; + sha256 = "0hrin9lzyi50k4w2bd2b30vrf1i4fi1c0gyas5801wn8i7kpm9yl"; + }; + }; + }; + + testScript = '' + startAll; + + $machine->waitForUnit('redmine.service'); + $machine->waitForOpenPort('3000'); + $machine->succeed("curl --fail http://localhost:3000/"); + ''; +}) diff --git a/nixos/tests/rspamd.nix b/nixos/tests/rspamd.nix index 6b2e2dd3a531..a12622b6aa0b 100644 --- a/nixos/tests/rspamd.nix +++ b/nixos/tests/rspamd.nix @@ -13,13 +13,10 @@ let $machine->succeed("[[ \"\$(stat -c %G ${socket})\" == \"${group}\" ]]"); $machine->succeed("[[ \"\$(stat -c %a ${socket})\" == \"${mode}\" ]]"); ''; - simple = name: socketActivation: enableIPv6: makeTest { + simple = name: enableIPv6: makeTest { name = "rspamd-${name}"; machine = { - services.rspamd = { - enable = true; - socketActivation = socketActivation; - }; + services.rspamd.enable = true; networking.enableIPv6 = enableIPv6; }; testScript = '' @@ -32,13 +29,6 @@ let 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 '' @@ -48,10 +38,8 @@ let }; 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; + simple = simple "simple" true; + ipv4only = simple "ipv4only" false; deprecated = makeTest { name = "rspamd-deprecated"; machine = { @@ -68,7 +56,6 @@ in ${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")); ''; @@ -79,7 +66,6 @@ in machine = { services.rspamd = { enable = true; - socketActivation = false; workers.normal.bindSockets = [{ socket = "/run/rspamd.sock"; mode = "0600"; @@ -101,38 +87,6 @@ in ${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/rsyslogd.nix b/nixos/tests/rsyslogd.nix new file mode 100644 index 000000000000..969d59e0f2c2 --- /dev/null +++ b/nixos/tests/rsyslogd.nix @@ -0,0 +1,38 @@ +{ system ? builtins.currentSystem }: + +with import ../lib/testing.nix { inherit system; }; +with pkgs.lib; +{ + test1 = makeTest { + name = "rsyslogd-test1"; + meta.maintainers = [ maintainers.aanderse ]; + + machine = + { config, pkgs, ... }: + { services.rsyslogd.enable = true; + services.journald.forwardToSyslog = false; + }; + + # ensure rsyslogd isn't receiving messages from journald if explicitly disabled + testScript = '' + $machine->waitForUnit("default.target"); + $machine->fail("test -f /var/log/messages"); + ''; + }; + + test2 = makeTest { + name = "rsyslogd-test2"; + meta.maintainers = [ maintainers.aanderse ]; + + machine = + { config, pkgs, ... }: + { services.rsyslogd.enable = true; + }; + + # ensure rsyslogd is receiving messages from journald + testScript = '' + $machine->waitForUnit("default.target"); + $machine->succeed("test -f /var/log/messages"); + ''; + }; +} diff --git a/nixos/tests/slurm.nix b/nixos/tests/slurm.nix index 60f44c3c8459..7f9c266cbff6 100644 --- a/nixos/tests/slurm.nix +++ b/nixos/tests/slurm.nix @@ -1,22 +1,27 @@ -import ./make-test.nix ({ ... }: -let mungekey = "mungeverryweakkeybuteasytointegratoinatest"; +import ./make-test.nix ({ lib, ... }: +let + mungekey = "mungeverryweakkeybuteasytointegratoinatest"; + slurmconfig = { controlMachine = "control"; - nodeName = '' - control - NodeName=node[1-3] CPUs=1 State=UNKNOWN + nodeName = [ "node[1-3] CPUs=1 State=UNKNOWN" ]; + partitionName = [ "debug Nodes=node[1-3] Default=YES MaxTime=INFINITE State=UP" ]; + extraConfig = '' + AccountingStorageHost=dbd + AccountingStorageType=accounting_storage/slurmdbd ''; - partitionName = "debug Nodes=node[1-3] Default=YES MaxTime=INFINITE State=UP"; }; in { name = "slurm"; + meta.maintainers = [ lib.maintainers.markuskowa ]; + nodes = let computeNode = { ...}: { - # TODO slrumd port and slurmctld port should be configurations and + # TODO slurmd port and slurmctld port should be configurations and # automatically allowed by the firewall. networking.firewall.enable = false; services.slurm = { @@ -43,6 +48,24 @@ in { } // slurmconfig; }; + dbd = + { pkgs, ... } : + { + networking.firewall.enable = false; + services.slurm.dbdserver = { + enable = true; + }; + services.mysql = { + enable = true; + package = pkgs.mysql; + ensureDatabases = [ "slurm_acct_db" ]; + ensureUsers = [{ + ensurePermissions = { "slurm_acct_db.*" = "ALL PRIVILEGES"; }; + name = "slurm"; + }]; + }; + }; + node1 = computeNode; node2 = computeNode; node3 = computeNode; @@ -54,7 +77,7 @@ in { startAll; # Set up authentification across the cluster - foreach my $node (($submit,$control,$node1,$node2,$node3)) + foreach my $node (($submit,$control,$dbd,$node1,$node2,$node3)) { $node->waitForUnit("default.target"); @@ -63,10 +86,22 @@ in { $node->succeed("chmod 0400 /etc/munge/munge.key"); $node->succeed("chown munge:munge /etc/munge/munge.key"); $node->succeed("systemctl restart munged"); - } + + $node->waitForUnit("munged"); + }; # Restart the services since they have probably failed due to the munge init # failure + subtest "can_start_slurmdbd", sub { + $dbd->succeed("systemctl restart slurmdbd"); + $dbd->waitForUnit("slurmdbd.service"); + }; + + # there needs to be an entry for the current + # cluster in the database before slurmctld is restarted + subtest "add_account", sub { + $control->succeed("sacctmgr -i add cluster default"); + }; subtest "can_start_slurmctld", sub { $control->succeed("systemctl restart slurmctld"); @@ -81,12 +116,17 @@ in { } }; - # Test that the cluster work and can distribute jobs; + # Test that the cluster works and can distribute jobs; subtest "run_distributed_command", sub { # Run `hostname` on 3 nodes of the partition (so on all the 3 nodes). # The output must contain the 3 different names $submit->succeed("srun -N 3 hostname | sort | uniq | wc -l | xargs test 3 -eq"); }; + + subtest "check_slurm_dbd", sub { + # find the srun job from above in the database + $submit->succeed("sacct | grep hostname"); + }; ''; }) diff --git a/nixos/tests/upnp.nix b/nixos/tests/upnp.nix new file mode 100644 index 000000000000..3f2dd13fb560 --- /dev/null +++ b/nixos/tests/upnp.nix @@ -0,0 +1,94 @@ +# This tests whether UPnP port mappings can be created using Miniupnpd +# and Miniupnpc. +# It runs a Miniupnpd service on one machine, and verifies +# a client can indeed create a port mapping using Miniupnpc. If +# this succeeds an external client will try to connect to the port +# mapping. + +import ./make-test.nix ({ pkgs, ... }: + +let + internalRouterAddress = "192.168.3.1"; + internalClient1Address = "192.168.3.2"; + externalRouterAddress = "80.100.100.1"; + externalClient2Address = "80.100.100.2"; +in +{ + name = "upnp"; + meta = with pkgs.stdenv.lib.maintainers; { + maintainers = [ bobvanderlinden ]; + }; + + nodes = + { + router = + { pkgs, nodes, ... }: + { virtualisation.vlans = [ 1 2 ]; + networking.nat.enable = true; + networking.nat.internalInterfaces = [ "eth2" ]; + networking.nat.externalInterface = "eth1"; + networking.firewall.enable = true; + networking.firewall.trustedInterfaces = [ "eth2" ]; + networking.interfaces.eth1.ipv4.addresses = [ + { address = externalRouterAddress; prefixLength = 24; } + ]; + networking.interfaces.eth2.ipv4.addresses = [ + { address = internalRouterAddress; prefixLength = 24; } + ]; + services.miniupnpd = { + enable = true; + externalInterface = "eth1"; + internalIPs = [ "eth2" ]; + appendConfig = '' + ext_ip=${externalRouterAddress} + ''; + }; + }; + + client1 = + { pkgs, nodes, ... }: + { environment.systemPackages = [ pkgs.miniupnpc pkgs.netcat ]; + virtualisation.vlans = [ 2 ]; + networking.defaultGateway = internalRouterAddress; + networking.interfaces.eth1.ipv4.addresses = [ + { address = internalClient1Address; prefixLength = 24; } + ]; + networking.firewall.enable = false; + + services.httpd.enable = true; + services.httpd.listen = [{ ip = "*"; port = 9000; }]; + services.httpd.adminAddr = "foo@example.org"; + services.httpd.documentRoot = "/tmp"; + }; + + client2 = + { pkgs, ... }: + { environment.systemPackages = [ pkgs.miniupnpc ]; + virtualisation.vlans = [ 1 ]; + networking.interfaces.eth1.ipv4.addresses = [ + { address = externalClient2Address; prefixLength = 24; } + ]; + networking.firewall.enable = false; + }; + }; + + testScript = + { nodes, ... }: + '' + startAll; + + # Wait for network and miniupnpd. + $router->waitForUnit("network-online.target"); + # $router->waitForUnit("nat"); + $router->waitForUnit("firewall.service"); + $router->waitForUnit("miniupnpd"); + + $client1->waitForUnit("network-online.target"); + + $client1->succeed("upnpc -a ${internalClient1Address} 9000 9000 TCP"); + + $client1->waitForUnit("httpd"); + $client2->waitUntilSucceeds("curl http://${externalRouterAddress}:9000/"); + ''; + +}) diff --git a/nixos/tests/yabar.nix b/nixos/tests/yabar.nix index 06fe5bc2b278..bbc0cf4c7dd7 100644 --- a/nixos/tests/yabar.nix +++ b/nixos/tests/yabar.nix @@ -8,18 +8,26 @@ with lib; maintainers = [ ma27 ]; }; - nodes.yabar = { + machine = { imports = [ ./common/x11.nix ./common/user-account.nix ]; services.xserver.displayManager.auto.user = "bob"; programs.yabar.enable = true; + programs.yabar.bars = { + top.indicators.date.exec = "YABAR_DATE"; + }; }; testScript = '' - $yabar->start; - $yabar->waitForX; + $machine->start; + $machine->waitForX; - $yabar->waitForUnit("yabar.service", "bob"); + # confirm proper startup + $machine->waitForUnit("yabar.service", "bob"); + $machine->sleep(10); + $machine->waitForUnit("yabar.service", "bob"); + + $machine->screenshot("top_bar"); ''; }) |