diff options
Diffstat (limited to 'nixos')
187 files changed, 8363 insertions, 5239 deletions
diff --git a/nixos/doc/config-examples/basic.nix b/nixos/doc/config-examples/basic.nix deleted file mode 100644 index da37cfb8c28..00000000000 --- a/nixos/doc/config-examples/basic.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - boot = { - loader.grub.device = "/dev/sda"; - }; - - fileSystems = [ - { mountPoint = "/"; - device = "/dev/sda1"; - } - ]; - - swapDevices = [ - { device = "/dev/sdb1"; } - ]; - - services = { - openssh = { - enable = true; - }; - }; -} diff --git a/nixos/doc/config-examples/closed-install-configuration.nix b/nixos/doc/config-examples/closed-install-configuration.nix deleted file mode 100644 index 0cebacdb0cc..00000000000 --- a/nixos/doc/config-examples/closed-install-configuration.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ - boot = { - loader.grub.device = "/dev/sda"; - copyKernels = true; - bootMount = "(hd0,0)"; - }; - - fileSystems = [ - { mountPoint = "/"; - device = "/dev/sda3"; - } - { mountPoint = "/boot"; - device = "/dev/sda1"; - neededForBoot = true; - } - ]; - - swapDevices = [ - { device = "/dev/sda2"; } - ]; - - services = { - sshd = { - enable = true; - }; - }; - - fonts = { - enableFontConfig = false; - }; - -} diff --git a/nixos/doc/config-examples/root-on-lvm.nix b/nixos/doc/config-examples/root-on-lvm.nix deleted file mode 100644 index 2ea1e547921..00000000000 --- a/nixos/doc/config-examples/root-on-lvm.nix +++ /dev/null @@ -1,27 +0,0 @@ -# This configuration has / on a LVM volume. Since Grub -# doesn't know about LVM, a separate /boot is therefore -# needed. -# -# In this example, labels are used for file systems and -# swap devices: "boot" might be /dev/sda1, "root" might be -# /dev/my-volume-group/root, and "swap" might be /dev/sda2. -# In particular there is no specific reference to the fact -# that / is on LVM; that's figured out automatically. - -{ - boot.loader.grub.device = "/dev/sda"; - boot.initrd.kernelModules = ["ata_piix"]; - - fileSystems = [ - { mountPoint = "/"; - label = "root"; - } - { mountPoint = "/boot"; - label = "boot"; - } - ]; - - swapDevices = [ - { label = "swap"; } - ]; -} diff --git a/nixos/doc/config-examples/svn-server.nix b/nixos/doc/config-examples/svn-server.nix deleted file mode 100644 index e727007117b..00000000000 --- a/nixos/doc/config-examples/svn-server.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ - boot = { - loader.grub.device = "/dev/sda"; - }; - - fileSystems = [ - { mountPoint = "/"; - device = "/dev/sda1"; - } - ]; - - services = { - - sshd = { - enable = true; - }; - - httpd = { - enable = true; - adminAddr = "admin@example.org"; - - subservices = { - - subversion = { - enable = true; - dataDir = "/data/subversion"; - notificationSender = "svn@example.org"; - }; - - }; - - }; - - }; - -} diff --git a/nixos/doc/config-examples/x86_64-usbstick.nix b/nixos/doc/config-examples/x86_64-usbstick.nix deleted file mode 100644 index 374d3ba3bc7..00000000000 --- a/nixos/doc/config-examples/x86_64-usbstick.nix +++ /dev/null @@ -1,20 +0,0 @@ -# Configuration file used to install NixOS-x86_64 on a USB stick. - -{ - boot = { - loader.grub.device = "/dev/sda"; - initrd = { - kernelModules = ["usb_storage" "ehci_hcd" "ohci_hcd"]; - }; - }; - - fileSystems = [ - { mountPoint = "/"; - label = "nixos-usb"; - } - ]; - - fonts = { - enableFontConfig = false; - }; -} diff --git a/nixos/doc/manual/administration/boot-problems.xml b/nixos/doc/manual/administration/boot-problems.xml new file mode 100644 index 00000000000..be6ff3aac0f --- /dev/null +++ b/nixos/doc/manual/administration/boot-problems.xml @@ -0,0 +1,65 @@ +<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-boot-problems"> + +<title>Boot Problems</title> + +<para>If NixOS fails to boot, there are a number of kernel command +line parameters that may help you to identify or fix the issue. You +can add these parameters in the GRUB boot menu by pressing “e” to +modify the selected boot entry and editing the line starting with +<literal>linux</literal>. The following are some useful kernel command +line parameters that are recognised by the NixOS boot scripts or by +systemd: + +<variablelist> + + <varlistentry><term><literal>boot.shell_on_fail</literal></term> + <listitem><para>Start a root shell if something goes wrong in + stage 1 of the boot process (the initial ramdisk). This is + disabled by default because there is no authentication for the + root shell.</para></listitem> + </varlistentry> + + <varlistentry><term><literal>boot.debug1</literal></term> + <listitem><para>Start an interactive shell in stage 1 before + anything useful has been done. That is, no modules have been + loaded and no file systems have been mounted, except for + <filename>/proc</filename> and + <filename>/sys</filename>.</para></listitem> + </varlistentry> + + <varlistentry><term><literal>boot.trace</literal></term> + <listitem><para>Print every shell command executed by the stage 1 + and 2 boot scripts.</para></listitem> + </varlistentry> + + <varlistentry><term><literal>single</literal></term> + <listitem><para>Boot into rescue mode (a.k.a. single user mode). + This will cause systemd to start nothing but the unit + <literal>rescue.target</literal>, which runs + <command>sulogin</command> to prompt for the root password and + start a root login shell. Exiting the shell causes the system to + continue with the normal boot process.</para></listitem> + </varlistentry> + + <varlistentry><term><literal>systemd.log_level=debug systemd.log_target=console</literal></term> + <listitem><para>Make systemd very verbose and send log messages to + the console instead of the journal.</para></listitem> + </varlistentry> + +</variablelist> + +For more parameters recognised by systemd, see +<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para> + +<para>If no login prompts or X11 login screens appear (e.g. due to +hanging dependencies), you can press Alt+ArrowUp. If you’re lucky, +this will start rescue mode (described above). (Also note that since +most units have a 90-second timeout before systemd gives up on them, +the <command>agetty</command> login prompts should appear eventually +unless something is very wrong.)</para> + +</section> \ No newline at end of file diff --git a/nixos/doc/manual/administration/cleaning-store.xml b/nixos/doc/manual/administration/cleaning-store.xml new file mode 100644 index 00000000000..41dc65795b6 --- /dev/null +++ b/nixos/doc/manual/administration/cleaning-store.xml @@ -0,0 +1,62 @@ +<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="sec-nix-gc"> + +<title>Cleaning the Nix Store</title> + +<para>Nix has a purely functional model, meaning that packages are +never upgraded in place. Instead new versions of packages end up in a +different location in the Nix store (<filename>/nix/store</filename>). +You should periodically run Nix’s <emphasis>garbage +collector</emphasis> to remove old, unreferenced packages. This is +easy: + +<screen> +$ nix-collect-garbage +</screen> + +Alternatively, you can use a systemd unit that does the same in the +background: + +<screen> +$ systemctl start nix-gc.service +</screen> + +You can tell NixOS in <filename>configuration.nix</filename> to run +this unit automatically at certain points in time, for instance, every +night at 03:15: + +<programlisting> +nix.gc.automatic = true; +nix.gc.dates = "03:15"; +</programlisting> + +</para> + +<para>The commands above do not remove garbage collector roots, such +as old system configurations. Thus they do not remove the ability to +roll back to previous configurations. The following command deletes +old roots, removing the ability to roll back to them: +<screen> +$ nix-collect-garbage -d +</screen> +You can also do this for specific profiles, e.g. +<screen> +$ nix-env -p /nix/var/nix/profiles/per-user/eelco/profile --delete-generations old +</screen> +Note that NixOS system configurations are stored in the profile +<filename>/nix/var/nix/profiles/system</filename>.</para> + +<para>Another way to reclaim disk space (often as much as 40% of the +size of the Nix store) is to run Nix’s store optimiser, which seeks +out identical files in the store and replaces them with hard links to +a single copy. +<screen> +$ nix-store --optimise +</screen> +Since this command needs to read the entire Nix store, it can take +quite a while to finish.</para> + +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/administration/container-networking.xml b/nixos/doc/manual/administration/container-networking.xml new file mode 100644 index 00000000000..adea3e69840 --- /dev/null +++ b/nixos/doc/manual/administration/container-networking.xml @@ -0,0 +1,50 @@ +<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-container-networking"> + + +<title>Container Networking</title> + +<para>When you create a container using <literal>nixos-container +create</literal>, it gets it own private IPv4 address in the range +<literal>10.233.0.0/16</literal>. You can get the container’s IPv4 +address as follows: + +<screen> +$ nixos-container show-ip foo +10.233.4.2 + +$ ping -c1 10.233.4.2 +64 bytes from 10.233.4.2: icmp_seq=1 ttl=64 time=0.106 ms +</screen> + +</para> + +<para>Networking is implemented using a pair of virtual Ethernet +devices. The network interface in the container is called +<literal>eth0</literal>, while the matching interface in the host is +called <literal>ve-<replaceable>container-name</replaceable></literal> +(e.g., <literal>ve-foo</literal>). The container has its own network +namespace and the <literal>CAP_NET_ADMIN</literal> capability, so it +can perform arbitrary network configuration such as setting up +firewall rules, without affecting or having access to the host’s +network.</para> + +<para>By default, containers cannot talk to the outside network. If +you want that, you should set up Network Address Translation (NAT) +rules on the host to rewrite container traffic to use your external +IP address. This can be accomplished using the following configuration +on the host: + +<programlisting> +networking.nat.enable = true; +networking.nat.internalInterfaces = ["ve-+"]; +networking.nat.externalInterface = "eth0"; +</programlisting> +where <literal>eth0</literal> should be replaced with the desired +external interface. Note that <literal>ve-+</literal> is a wildcard +that matches all container interfaces.</para> + +</section> \ No newline at end of file diff --git a/nixos/doc/manual/administration/containers.xml b/nixos/doc/manual/administration/containers.xml new file mode 100644 index 00000000000..4cd2c8ae556 --- /dev/null +++ b/nixos/doc/manual/administration/containers.xml @@ -0,0 +1,34 @@ +<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="ch-containers"> + +<title>Container Management</title> + +<para>NixOS allows you to easily run other NixOS instances as +<emphasis>containers</emphasis>. Containers are a light-weight +approach to virtualisation that runs software in the container at the +same speed as in the host system. NixOS containers share the Nix store +of the host, making container creation very efficient.</para> + +<warning><para>Currently, NixOS containers are not perfectly isolated +from the host system. This means that a user with root access to the +container can do things that affect the host. So you should not give +container root access to untrusted users.</para></warning> + +<para>NixOS containers can be created in two ways: imperatively, using +the command <command>nixos-container</command>, and declaratively, by +specifying them in your <filename>configuration.nix</filename>. The +declarative approach implies that containers get upgraded along with +your host system when you run <command>nixos-rebuild</command>, which +is often not what you want. By contrast, in the imperative approach, +containers are configured and updated independently from the host +system.</para> + +<xi:include href="imperative-containers.xml" /> +<xi:include href="declarative-containers.xml" /> +<xi:include href="container-networking.xml" /> + +</chapter> + diff --git a/nixos/doc/manual/administration/control-groups.xml b/nixos/doc/manual/administration/control-groups.xml new file mode 100644 index 00000000000..86c684cdfe5 --- /dev/null +++ b/nixos/doc/manual/administration/control-groups.xml @@ -0,0 +1,75 @@ +<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="sec-cgroups"> + +<title>Control Groups</title> + +<para>To keep track of the processes in a running system, systemd uses +<emphasis>control groups</emphasis> (cgroups). A control group is a +set of processes used to allocate resources such as CPU, memory or I/O +bandwidth. There can be multiple control group hierarchies, allowing +each kind of resource to be managed independently.</para> + +<para>The command <command>systemd-cgls</command> lists all control +groups in the <literal>systemd</literal> hierarchy, which is what +systemd uses to keep track of the processes belonging to each service +or user session: + +<screen> +$ systemd-cgls +├─user +│ └─eelco +│ └─c1 +│ ├─ 2567 -:0 +│ ├─ 2682 kdeinit4: kdeinit4 Running... +│ ├─ <replaceable>...</replaceable> +│ └─10851 sh -c less -R +└─system + ├─httpd.service + │ ├─2444 httpd -f /nix/store/3pyacby5cpr55a03qwbnndizpciwq161-httpd.conf -DNO_DETACH + │ └─<replaceable>...</replaceable> + ├─dhcpcd.service + │ └─2376 dhcpcd --config /nix/store/f8dif8dsi2yaa70n03xir8r653776ka6-dhcpcd.conf + └─ <replaceable>...</replaceable> +</screen> + +Similarly, <command>systemd-cgls cpu</command> shows the cgroups in +the CPU hierarchy, which allows per-cgroup CPU scheduling priorities. +By default, every systemd service gets its own CPU cgroup, while all +user sessions are in the top-level CPU cgroup. This ensures, for +instance, that a thousand run-away processes in the +<literal>httpd.service</literal> cgroup cannot starve the CPU for one +process in the <literal>postgresql.service</literal> cgroup. (By +contrast, it they were in the same cgroup, then the PostgreSQL process +would get 1/1001 of the cgroup’s CPU time.) You can limit a service’s +CPU share in <filename>configuration.nix</filename>: + +<programlisting> +systemd.services.httpd.serviceConfig.CPUShares = 512; +</programlisting> + +By default, every cgroup has 1024 CPU shares, so this will halve the +CPU allocation of the <literal>httpd.service</literal> cgroup.</para> + +<para>There also is a <literal>memory</literal> hierarchy that +controls memory allocation limits; by default, all processes are in +the top-level cgroup, so any service or session can exhaust all +available memory. Per-cgroup memory limits can be specified in +<filename>configuration.nix</filename>; for instance, to limit +<literal>httpd.service</literal> to 512 MiB of RAM (excluding swap) +and 640 MiB of RAM (including swap): + +<programlisting> +systemd.services.httpd.serviceConfig.MemoryLimit = "512M"; +systemd.services.httpd.serviceConfig.ControlGroupAttribute = [ "memory.memsw.limit_in_bytes 640M" ]; +</programlisting> + +</para> + +<para>The command <command>systemd-cgtop</command> shows a +continuously updated list of all cgroups with their CPU and memory +usage.</para> + +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/administration/declarative-containers.xml b/nixos/doc/manual/administration/declarative-containers.xml new file mode 100644 index 00000000000..177ebdd8db1 --- /dev/null +++ b/nixos/doc/manual/administration/declarative-containers.xml @@ -0,0 +1,52 @@ +<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-declarative-containers"> + +<title>Declarative Container Specification</title> + +<para>You can also specify containers and their configuration in the +host’s <filename>configuration.nix</filename>. For example, the +following specifies that there shall be a container named +<literal>database</literal> running PostgreSQL: + +<programlisting> +containers.database = + { config = + { config, pkgs, ... }: + { services.postgresql.enable = true; + services.postgresql.package = pkgs.postgresql92; + }; + }; +</programlisting> + +If you run <literal>nixos-rebuild switch</literal>, the container will +be built and started. If the container was already running, it will be +updated in place, without rebooting.</para> + +<para>By default, declarative containers share the network namespace +of the host, meaning that they can listen on (privileged) +ports. However, they cannot change the network configuration. You can +give a container its own network as follows: + +<programlisting> +containers.database = + { privateNetwork = true; + hostAddress = "192.168.100.10"; + localAddress = "192.168.100.11"; + }; +</programlisting> + +This gives the container a private virtual Ethernet interface with IP +address <literal>192.168.100.11</literal>, which is hooked up to a +virtual Ethernet interface on the host with IP address +<literal>192.168.100.10</literal>. (See the next section for details +on container networking.)</para> + +<para>To disable the container, just remove it from +<filename>configuration.nix</filename> and run <literal>nixos-rebuild +switch</literal>. Note that this will not delete the root directory of +the container in <literal>/var/lib/containers</literal>.</para> + +</section> \ No newline at end of file diff --git a/nixos/doc/manual/administration/imperative-containers.xml b/nixos/doc/manual/administration/imperative-containers.xml new file mode 100644 index 00000000000..6131d4e04ea --- /dev/null +++ b/nixos/doc/manual/administration/imperative-containers.xml @@ -0,0 +1,124 @@ +<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-imperative-containers"> + +<title>Imperative Container Management</title> + +<para>We’ll cover imperative container management using +<command>nixos-container</command> first. You create a container with +identifier <literal>foo</literal> as follows: + +<screen> +$ nixos-container create foo +</screen> + +This creates the container’s root directory in +<filename>/var/lib/containers/foo</filename> and a small configuration +file in <filename>/etc/containers/foo.conf</filename>. It also builds +the container’s initial system configuration and stores it in +<filename>/nix/var/nix/profiles/per-container/foo/system</filename>. You +can modify the initial configuration of the container on the command +line. For instance, to create a container that has +<command>sshd</command> running, with the given public key for +<literal>root</literal>: + +<screen> +$ nixos-container create foo --config 'services.openssh.enable = true; \ + users.extraUsers.root.openssh.authorizedKeys.keys = ["ssh-dss AAAAB3N…"];' +</screen> + +</para> + +<para>Creating a container does not start it. To start the container, +run: + +<screen> +$ nixos-container start foo +</screen> + +This command will return as soon as the container has booted and has +reached <literal>multi-user.target</literal>. On the host, the +container runs within a systemd unit called +<literal>container@<replaceable>container-name</replaceable>.service</literal>. +Thus, if something went wrong, you can get status info using +<command>systemctl</command>: + +<screen> +$ systemctl status container@foo +</screen> + +</para> + +<para>If the container has started succesfully, you can log in as +root using the <command>root-login</command> operation: + +<screen> +$ nixos-container root-login foo +[root@foo:~]# +</screen> + +Note that only root on the host can do this (since there is no +authentication). You can also get a regular login prompt using the +<command>login</command> operation, which is available to all users on +the host: + +<screen> +$ nixos-container login foo +foo login: alice +Password: *** +</screen> + +With <command>nixos-container run</command>, you can execute arbitrary +commands in the container: + +<screen> +$ nixos-container run foo -- uname -a +Linux foo 3.4.82 #1-NixOS SMP Thu Mar 20 14:44:05 UTC 2014 x86_64 GNU/Linux +</screen> + +</para> + +<para>There are several ways to change the configuration of the +container. First, on the host, you can edit +<literal>/var/lib/container/<replaceable>name</replaceable>/etc/nixos/configuration.nix</literal>, +and run + +<screen> +$ nixos-container update foo +</screen> + +This will build and activate the new configuration. You can also +specify a new configuration on the command line: + +<screen> +$ nixos-container update foo --config 'services.httpd.enable = true; \ + services.httpd.adminAddr = "foo@example.org";' + +$ curl http://$(nixos-container show-ip foo)/ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">… +</screen> + +However, note that this will overwrite the container’s +<filename>/etc/nixos/configuration.nix</filename>.</para> + +<para>Alternatively, you can change the configuration from within the +container itself by running <command>nixos-rebuild switch</command> +inside the container. Note that the container by default does not have +a copy of the NixOS channel, so you should run <command>nix-channel +--update</command> first.</para> + +<para>Containers can be stopped and started using +<literal>nixos-container stop</literal> and <literal>nixos-container +start</literal>, respectively, or by using +<command>systemctl</command> on the container’s service unit. To +destroy a container, including its file system, do + +<screen> +$ nixos-container destroy foo +</screen> + +</para> + +</section> \ No newline at end of file diff --git a/nixos/doc/manual/administration/logging.xml b/nixos/doc/manual/administration/logging.xml new file mode 100644 index 00000000000..1d5df7770e2 --- /dev/null +++ b/nixos/doc/manual/administration/logging.xml @@ -0,0 +1,52 @@ +<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="sec-logging"> + +<title>Logging</title> + +<para>System-wide logging is provided by systemd’s +<emphasis>journal</emphasis>, which subsumes traditional logging +daemons such as syslogd and klogd. Log entries are kept in binary +files in <filename>/var/log/journal/</filename>. The command +<literal>journalctl</literal> allows you to see the contents of the +journal. For example, + +<screen> +$ journalctl -b +</screen> + +shows all journal entries since the last reboot. (The output of +<command>journalctl</command> is piped into <command>less</command> by +default.) You can use various options and match operators to restrict +output to messages of interest. For instance, to get all messages +from PostgreSQL: + +<screen> +$ journalctl -u postgresql.service +-- Logs begin at Mon, 2013-01-07 13:28:01 CET, end at Tue, 2013-01-08 01:09:57 CET. -- +... +Jan 07 15:44:14 hagbard postgres[2681]: [2-1] LOG: database system is shut down +-- Reboot -- +Jan 07 15:45:10 hagbard postgres[2532]: [1-1] LOG: database system was shut down at 2013-01-07 15:44:14 CET +Jan 07 15:45:13 hagbard postgres[2500]: [1-1] LOG: database system is ready to accept connections +</screen> + +Or to get all messages since the last reboot that have at least a +“critical” severity level: + +<screen> +$ journalctl -b -p crit +Dec 17 21:08:06 mandark sudo[3673]: pam_unix(sudo:auth): auth could not identify password for [alice] +Dec 29 01:30:22 mandark kernel[6131]: [1053513.909444] CPU6: Core temperature above threshold, cpu clock throttled (total events = 1) +</screen> + +</para> + +<para>The system journal is readable by root and by users in the +<literal>wheel</literal> and <literal>systemd-journal</literal> +groups. All users have a private journal that can be read using +<command>journalctl</command>.</para> + +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/administration/maintenance-mode.xml b/nixos/doc/manual/administration/maintenance-mode.xml new file mode 100644 index 00000000000..15c1f902da7 --- /dev/null +++ b/nixos/doc/manual/administration/maintenance-mode.xml @@ -0,0 +1,18 @@ +<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-maintenance-mode"> + +<title>Maintenance Mode</title> + +<para>You can enter rescue mode by running: + +<screen> +$ systemctl rescue</screen> + +This will eventually give you a single-user root shell. Systemd will +stop (almost) all system services. To get out of maintenance mode, +just exit from the rescue shell.</para> + +</section> \ No newline at end of file diff --git a/nixos/doc/manual/administration/network-problems.xml b/nixos/doc/manual/administration/network-problems.xml new file mode 100644 index 00000000000..5ba1bfd5ac9 --- /dev/null +++ b/nixos/doc/manual/administration/network-problems.xml @@ -0,0 +1,33 @@ +<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-nix-network-issues"> + +<title>Network Problems</title> + +<para>Nix uses a so-called <emphasis>binary cache</emphasis> to +optimise building a package from source into downloading it as a +pre-built binary. That is, whenever a command like +<command>nixos-rebuild</command> needs a path in the Nix store, Nix +will try to download that path from the Internet rather than build it +from source. The default binary cache is +<uri>http://cache.nixos.org/</uri>. If this cache is unreachable, Nix +operations may take a long time due to HTTP connection timeouts. You +can disable the use of the binary cache by adding <option>--option +use-binary-caches false</option>, e.g. + +<screen> +$ nixos-rebuild switch --option use-binary-caches false +</screen> + +If you have an alternative binary cache at your disposal, you can use +it instead: + +<screen> +$ nixos-rebuild switch --option binary-caches http://my-cache.example.org/ +</screen> + +</para> + +</section> \ No newline at end of file diff --git a/nixos/doc/manual/administration/rebooting.xml b/nixos/doc/manual/administration/rebooting.xml new file mode 100644 index 00000000000..d1db7b141cf --- /dev/null +++ b/nixos/doc/manual/administration/rebooting.xml @@ -0,0 +1,44 @@ +<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="sec-rebooting"> + +<title>Rebooting and Shutting Down</title> + +<para>The system can be shut down (and automatically powered off) by +doing: + +<screen> +$ shutdown +</screen> + +This is equivalent to running <command>systemctl +poweroff</command>.</para> + +<para>To reboot the system, run + +<screen> +$ reboot +</screen> + +which is equivalent to <command>systemctl reboot</command>. +Alternatively, you can quickly reboot the system using +<literal>kexec</literal>, which bypasses the BIOS by directly loading +the new kernel into memory: + +<screen> +$ systemctl kexec +</screen> + +</para> + +<para>The machine can be suspended to RAM (if supported) using +<command>systemctl suspend</command>, and suspended to disk using +<command>systemctl hibernate</command>.</para> + +<para>These commands can be run by any user who is logged in locally, +i.e. on a virtual console or in X11; otherwise, the user is asked for +authentication.</para> + +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/administration/rollback.xml b/nixos/doc/manual/administration/rollback.xml new file mode 100644 index 00000000000..23a3ece7c07 --- /dev/null +++ b/nixos/doc/manual/administration/rollback.xml @@ -0,0 +1,48 @@ +<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-rollback"> + +<title>Rolling Back Configuration Changes</title> + +<para>After running <command>nixos-rebuild</command> to switch to a +new configuration, you may find that the new configuration doesn’t +work very well. In that case, there are several ways to return to a +previous configuration.</para> + +<para>First, the GRUB boot manager allows you to boot into any +previous configuration that hasn’t been garbage-collected. These +configurations can be found under the GRUB submenu “NixOS - All +configurations”. This is especially useful if the new configuration +fails to boot. After the system has booted, you can make the selected +configuration the default for subsequent boots: + +<screen> +$ /run/current-system/bin/switch-to-configuration boot</screen> + +</para> + +<para>Second, you can switch to the previous configuration in a running +system: + +<screen> +$ nixos-rebuild switch --rollback</screen> + +This is equivalent to running: + +<screen> +$ /nix/var/nix/profiles/system-<replaceable>N</replaceable>-link/bin/switch-to-configuration switch</screen> + +where <replaceable>N</replaceable> is the number of the NixOS system +configuration. To get a list of the available configurations, do: + +<screen> +$ ls -l /nix/var/nix/profiles/system-*-link +<replaceable>...</replaceable> +lrwxrwxrwx 1 root root 78 Aug 12 13:54 /nix/var/nix/profiles/system-268-link -> /nix/store/202b...-nixos-13.07pre4932_5a676e4-4be1055 +</screen> + +</para> + +</section> \ No newline at end of file diff --git a/nixos/doc/manual/administration/running.xml b/nixos/doc/manual/administration/running.xml new file mode 100644 index 00000000000..9091511ed52 --- /dev/null +++ b/nixos/doc/manual/administration/running.xml @@ -0,0 +1,24 @@ +<part 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="ch-running"> + +<title>Administration</title> + +<partintro> +<para>This chapter describes various aspects of managing a running +NixOS system, such as how to use the <command>systemd</command> +service manager.</para> +</partintro> + +<xi:include href="service-mgmt.xml" /> +<xi:include href="rebooting.xml" /> +<xi:include href="user-sessions.xml" /> +<xi:include href="control-groups.xml" /> +<xi:include href="logging.xml" /> +<xi:include href="cleaning-store.xml" /> +<xi:include href="containers.xml" /> +<xi:include href="troubleshooting.xml" /> + +</part> diff --git a/nixos/doc/manual/administration/service-mgmt.xml b/nixos/doc/manual/administration/service-mgmt.xml new file mode 100644 index 00000000000..c0940a42f30 --- /dev/null +++ b/nixos/doc/manual/administration/service-mgmt.xml @@ -0,0 +1,83 @@ +<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="sec-systemctl"> + +<title>Service Management</title> + +<para>In NixOS, all system services are started and monitored using +the systemd program. Systemd is the “init” process of the system +(i.e. PID 1), the parent of all other processes. It manages a set of +so-called “units”, which can be things like system services +(programs), but also mount points, swap files, devices, targets +(groups of units) and more. Units can have complex dependencies; for +instance, one unit can require that another unit must be successfully +started before the first unit can be started. When the system boots, +it starts a unit named <literal>default.target</literal>; the +dependencies of this unit cause all system services to be started, +file systems to be mounted, swap files to be activated, and so +on.</para> + +<para>The command <command>systemctl</command> is the main way to +interact with <command>systemd</command>. Without any arguments, it +shows the status of active units: + +<screen> +$ systemctl +-.mount loaded active mounted / +swapfile.swap loaded active active /swapfile +sshd.service loaded active running SSH Daemon +graphical.target loaded active active Graphical Interface +<replaceable>...</replaceable> +</screen> + +</para> + +<para>You can ask for detailed status information about a unit, for +instance, the PostgreSQL database service: + +<screen> +$ systemctl status postgresql.service +postgresql.service - PostgreSQL Server + Loaded: loaded (/nix/store/pn3q73mvh75gsrl8w7fdlfk3fq5qm5mw-unit/postgresql.service) + Active: active (running) since Mon, 2013-01-07 15:55:57 CET; 9h ago + Main PID: 2390 (postgres) + CGroup: name=systemd:/system/postgresql.service + ├─2390 postgres + ├─2418 postgres: writer process + ├─2419 postgres: wal writer process + ├─2420 postgres: autovacuum launcher process + ├─2421 postgres: stats collector process + └─2498 postgres: zabbix zabbix [local] idle + +Jan 07 15:55:55 hagbard postgres[2394]: [1-1] LOG: database system was shut down at 2013-01-07 15:55:05 CET +Jan 07 15:55:57 hagbard postgres[2390]: [1-1] LOG: database system is ready to accept connections +Jan 07 15:55:57 hagbard postgres[2420]: [1-1] LOG: autovacuum launcher started +Jan 07 15:55:57 hagbard systemd[1]: Started PostgreSQL Server. +</screen> + +Note that this shows the status of the unit (active and running), all +the processes belonging to the service, as well as the most recent log +messages from the service. + +</para> + +<para>Units can be stopped, started or restarted: + +<screen> +$ systemctl stop postgresql.service +$ systemctl start postgresql.service +$ systemctl restart postgresql.service +</screen> + +These operations are synchronous: they wait until the service has +finished starting or stopping (or has failed). Starting a unit will +cause the dependencies of that unit to be started as well (if +necessary).</para> + +<!-- - cgroups: each service and user session is a cgroup + +- cgroup resource management --> + +</chapter> diff --git a/nixos/doc/manual/administration/store-corruption.xml b/nixos/doc/manual/administration/store-corruption.xml new file mode 100644 index 00000000000..0160cb45358 --- /dev/null +++ b/nixos/doc/manual/administration/store-corruption.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-nix-store-corruption"> + +<title>Nix Store Corruption</title> + +<para>After a system crash, it’s possible for files in the Nix store +to become corrupted. (For instance, the Ext4 file system has the +tendency to replace un-synced files with zero bytes.) NixOS tries +hard to prevent this from happening: it performs a +<command>sync</command> before switching to a new configuration, and +Nix’s database is fully transactional. If corruption still occurs, +you may be able to fix it automatically.</para> + +<para>If the corruption is in a path in the closure of the NixOS +system configuration, you can fix it by doing + +<screen> +$ nixos-rebuild switch --repair +</screen> + +This will cause Nix to check every path in the closure, and if its +cryptographic hash differs from the hash recorded in Nix’s database, +the path is rebuilt or redownloaded.</para> + +<para>You can also scan the entire Nix store for corrupt paths: + +<screen> +$ nix-store --verify --check-contents --repair +</screen> + +Any corrupt paths will be redownloaded if they’re available in a +binary cache; otherwise, they cannot be repaired.</para> + +</section> \ No newline at end of file diff --git a/nixos/doc/manual/administration/troubleshooting.xml b/nixos/doc/manual/administration/troubleshooting.xml new file mode 100644 index 00000000000..351fb188331 --- /dev/null +++ b/nixos/doc/manual/administration/troubleshooting.xml @@ -0,0 +1,18 @@ +<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="ch-troubleshooting"> + +<title>Troubleshooting</title> + +<para>This chapter describes solutions to common problems you might +encounter when you manage your NixOS system.</para> + +<xi:include href="boot-problems.xml" /> +<xi:include href="maintenance-mode.xml" /> +<xi:include href="rollback.xml" /> +<xi:include href="store-corruption.xml" /> +<xi:include href="network-problems.xml" /> + +</chapter> diff --git a/nixos/doc/manual/administration/user-sessions.xml b/nixos/doc/manual/administration/user-sessions.xml new file mode 100644 index 00000000000..05e2c1a9b29 --- /dev/null +++ b/nixos/doc/manual/administration/user-sessions.xml @@ -0,0 +1,53 @@ +<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="sec-user-sessions"> + +<title>User Sessions</title> + +<para>Systemd keeps track of all users who are logged into the system +(e.g. on a virtual console or remotely via SSH). The command +<command>loginctl</command> allows querying and manipulating user +sessions. For instance, to list all user sessions: + +<screen> +$ loginctl + SESSION UID USER SEAT + c1 500 eelco seat0 + c3 0 root seat0 + c4 500 alice +</screen> + +This shows that two users are logged in locally, while another is +logged in remotely. (“Seats” are essentially the combinations of +displays and input devices attached to the system; usually, there is +only one seat.) To get information about a session: + +<screen> +$ loginctl session-status c3 +c3 - root (0) + Since: Tue, 2013-01-08 01:17:56 CET; 4min 42s ago + Leader: 2536 (login) + Seat: seat0; vc3 + TTY: /dev/tty3 + Service: login; type tty; class user + State: online + CGroup: name=systemd:/user/root/c3 + ├─ 2536 /nix/store/10mn4xip9n7y9bxqwnsx7xwx2v2g34xn-shadow-4.1.5.1/bin/login -- + ├─10339 -bash + └─10355 w3m nixos.org +</screen> + +This shows that the user is logged in on virtual console 3. It also +lists the processes belonging to this session. Since systemd keeps +track of this, you can terminate a session in a way that ensures that +all the session’s processes are gone: + +<screen> +$ loginctl terminate-session c3 +</screen> + +</para> + +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/configuration.xml b/nixos/doc/manual/configuration.xml deleted file mode 100644 index d35a5fff4aa..00000000000 --- a/nixos/doc/manual/configuration.xml +++ /dev/null @@ -1,1557 +0,0 @@ -<chapter xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="ch-configuration"> - -<title>Configuring NixOS</title> - -<para>This chapter describes how to configure various aspects of a -NixOS machine through the configuration file -<filename>/etc/nixos/configuration.nix</filename>. As described in -<xref linkend="sec-changing-config" />, changes to this file only take -effect after you run <command>nixos-rebuild</command>.</para> - - -<!--===============================================================--> - -<section xml:id="sec-configuration-syntax"><title>Configuration syntax</title> - -<section><title>The basics</title> - -<para>The NixOS configuration file -<filename>/etc/nixos/configuration.nix</filename> is actually a -<emphasis>Nix expression</emphasis>, which is the Nix package -manager’s purely functional language for describing how to build -packages and configurations. This means you have all the expressive -power of that language at your disposal, including the ability to -abstract over common patterns, which is very useful when managing -complex systems. The syntax and semantics of the Nix language are -fully described in the <link -xlink:href="http://nixos.org/nix/manual/#chap-writing-nix-expressions">Nix -manual</link>, but here we give a short overview of the most important -constructs useful in NixOS configuration files.</para> - -<para>The NixOS configuration file generally looks like this: - -<programlisting> -{ config, pkgs, ... }: - -{ <replaceable>option definitions</replaceable> -} -</programlisting> - -The first line (<literal>{ config, pkgs, ... }:</literal>) denotes -that this is actually a function that takes at least the two arguments - <varname>config</varname> and <varname>pkgs</varname>. (These are -explained later.) The function returns a <emphasis>set</emphasis> of -option definitions (<literal>{ <replaceable>...</replaceable> }</literal>). These definitions have the -form <literal><replaceable>name</replaceable> = -<replaceable>value</replaceable></literal>, where -<replaceable>name</replaceable> is the name of an option and -<replaceable>value</replaceable> is its value. For example, - -<programlisting> -{ config, pkgs, ... }: - -{ services.httpd.enable = true; - services.httpd.adminAddr = "alice@example.org"; - services.httpd.documentRoot = "/webroot"; -} -</programlisting> - -defines a configuration with three option definitions that together -enable the Apache HTTP Server with <filename>/webroot</filename> as -the document root.</para> - -<para>Sets can be nested, and in fact dots in option names are -shorthand for defining a set containing another set. For instance, -<option>services.httpd.enable</option> defines a set named -<varname>services</varname> that contains a set named -<varname>httpd</varname>, which in turn contains an option definition -named <varname>enable</varname> with value <literal>true</literal>. -This means that the example above can also be written as: - -<programlisting> -{ config, pkgs, ... }: - -{ services = { - httpd = { - enable = true; - adminAddr = "alice@example.org"; - documentRoot = "/webroot"; - }; - }; -} -</programlisting> - -which may be more convenient if you have lots of option definitions -that share the same prefix (such as -<literal>services.httpd</literal>).</para> - -<para>NixOS checks your option definitions for correctness. For -instance, if you try to define an option that doesn’t exist (that is, -doesn’t have a corresponding <emphasis>option declaration</emphasis>), -<command>nixos-rebuild</command> will give an error like: -<screen> -The option `services.httpd.enabl' defined in `/etc/nixos/configuration.nix' does not exist. -</screen> -Likewise, values in option definitions must have a correct type. For -instance, <option>services.httpd.enable</option> must be a Boolean -(<literal>true</literal> or <literal>false</literal>). Trying to give -it a value of another type, such as a string, will cause an error: -<screen> -The option value `services.httpd.enable' in `/etc/nixos/configuration.nix' is not a boolean. -</screen> - -</para> - -<para>Options have various types of values. The most important are: - -<variablelist> - <varlistentry> - <term>Strings</term> - <listitem> - <para>Strings are enclosed in double quotes, e.g. - -<programlisting> -networking.hostName = "dexter"; -</programlisting> - - Special characters can be escaped by prefixing them with a - backslash (e.g. <literal>\"</literal>).</para> - - <para>Multi-line strings can be enclosed in <emphasis>double - single quotes</emphasis>, e.g. - -<programlisting> -networking.extraHosts = - '' - 127.0.0.2 other-localhost - 10.0.0.1 server - ''; -</programlisting> - - The main difference is that preceding whitespace is - automatically stripped from each line, and that characters like - <literal>"</literal> and <literal>\</literal> are not special - (making it more convenient for including things like shell - code).</para> - </listitem> - </varlistentry> - - <varlistentry> - <term>Booleans</term> - <listitem> - <para>These can be <literal>true</literal> or - <literal>false</literal>, e.g. - -<programlisting> -networking.firewall.enable = true; -networking.firewall.allowPing = false; -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term>Integers</term> - <listitem> - <para>For example, - -<programlisting> -boot.kernel.sysctl."net.ipv4.tcp_keepalive_time" = 60; -</programlisting> - - (Note that here the attribute name - <literal>net.ipv4.tcp_keepalive_time</literal> is enclosed in - quotes to prevent it from being interpreted as a set named - <literal>net</literal> containing a set named - <literal>ipv4</literal>, and so on. This is because it’s not a - NixOS option but the literal name of a Linux kernel - setting.)</para> - </listitem> - </varlistentry> - - <varlistentry> - <term>Sets</term> - <listitem> - <para>Sets were introduced above. They are name/value pairs - enclosed in braces, as in the option definition - -<programlisting> -fileSystems."/boot" = - { device = "/dev/sda1"; - fsType = "ext4"; - options = "rw,data=ordered,relatime"; - }; -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term>Lists</term> - <listitem> - <para>The important thing to note about lists is that list - elements are separated by whitespace, like this: - -<programlisting> -boot.kernelModules = [ "fuse" "kvm-intel" "coretemp" ]; -</programlisting> - - List elements can be any other type, e.g. sets: - -<programlisting> -swapDevices = [ { device = "/dev/disk/by-label/swap"; } ]; -</programlisting> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term>Packages</term> - <listitem> - <para>Usually, the packages you need are already part of the Nix - Packages collection, which is a set that can be accessed through - the function argument <varname>pkgs</varname>. Typical uses: - -<programlisting> -environment.systemPackages = - [ pkgs.thunderbird - pkgs.emacs - ]; - -postgresql.package = pkgs.postgresql90; -</programlisting> - - The latter option definition changes the default PostgreSQL - package used by NixOS’s PostgreSQL service to 9.0. For more - information on packages, including how to add new ones, see - <xref linkend="sec-custom-packages"/>.</para> - </listitem> - </varlistentry> - -</variablelist> - -</para> - -</section> - - -<section xml:id="sec-module-abstractions"><title>Abstractions</title> - -<para>If you find yourself repeating yourself over and over, it’s time -to abstract. Take, for instance, this Apache HTTP Server configuration: - -<programlisting> -{ - services.httpd.virtualHosts = - [ { hostName = "example.org"; - documentRoot = "/webroot"; - adminAddr = "alice@example.org"; - enableUserDir = true; - } - { hostName = "example.org"; - documentRoot = "/webroot"; - adminAddr = "alice@example.org"; - enableUserDir = true; - enableSSL = true; - sslServerCert = "/root/ssl-example-org.crt"; - sslServerKey = "/root/ssl-example-org.key"; - } - ]; -} -</programlisting> - -It defines two virtual hosts with nearly identical configuration; the -only difference is that the second one has SSL enabled. To prevent -this duplication, we can use a <literal>let</literal>: - -<programlisting> -let - exampleOrgCommon = - { hostName = "example.org"; - documentRoot = "/webroot"; - adminAddr = "alice@example.org"; - enableUserDir = true; - }; -in -{ - services.httpd.virtualHosts = - [ exampleOrgCommon - (exampleOrgCommon // { - enableSSL = true; - sslServerCert = "/root/ssl-example-org.crt"; - sslServerKey = "/root/ssl-example-org.key"; - }) - ]; -} -</programlisting> - -The <literal>let exampleOrgCommon = -<replaceable>...</replaceable></literal> defines a variable named -<literal>exampleOrgCommon</literal>. The <literal>//</literal> -operator merges two attribute sets, so the configuration of the second -virtual host is the set <literal>exampleOrgCommon</literal> extended -with the SSL options.</para> - -<para>You can write a <literal>let</literal> wherever an expression is -allowed. Thus, you also could have written: - -<programlisting> -{ - services.httpd.virtualHosts = - let exampleOrgCommon = <replaceable>...</replaceable>; in - [ exampleOrgCommon - (exampleOrgCommon // { <replaceable>...</replaceable> }) - ]; -} -</programlisting> - -but not <literal>{ let exampleOrgCommon = -<replaceable>...</replaceable>; in <replaceable>...</replaceable>; -}</literal> since attributes (as opposed to attribute values) are not -expressions.</para> - -<para><emphasis>Functions</emphasis> provide another method of -abstraction. For instance, suppose that we want to generate lots of -different virtual hosts, all with identical configuration except for -the host name. This can be done as follows: - -<programlisting> -{ - services.httpd.virtualHosts = - let - makeVirtualHost = name: - { hostName = name; - documentRoot = "/webroot"; - adminAddr = "alice@example.org"; - }; - in - [ (makeVirtualHost "example.org") - (makeVirtualHost "example.com") - (makeVirtualHost "example.gov") - (makeVirtualHost "example.nl") - ]; -} -</programlisting> - -Here, <varname>makeVirtualHost</varname> is a function that takes a -single argument <literal>name</literal> and returns the configuration -for a virtual host. That function is then called for several names to -produce the list of virtual host configurations.</para> - -<para>We can further improve on this by using the function -<varname>map</varname>, which applies another function to every -element in a list: - -<programlisting> -{ - services.httpd.virtualHosts = - let - makeVirtualHost = <replaceable>...</replaceable>; - in map makeVirtualHost - [ "example.org" "example.com" "example.gov" "example.nl" ]; -} -</programlisting> - -(The function <literal>map</literal> is called a -<emphasis>higher-order function</emphasis> because it takes another -function as an argument.)</para> - -<para>What if you need more than one argument, for instance, if we -want to use a different <literal>documentRoot</literal> for each -virtual host? Then we can make <varname>makeVirtualHost</varname> a -function that takes a <emphasis>set</emphasis> as its argument, like this: - -<programlisting> -{ - services.httpd.virtualHosts = - let - makeVirtualHost = { name, root }: - { hostName = name; - documentRoot = root; - adminAddr = "alice@example.org"; - }; - in map makeVirtualHost - [ { name = "example.org"; root = "/sites/example.org"; } - { name = "example.com"; root = "/sites/example.com"; } - { name = "example.gov"; root = "/sites/example.gov"; } - { name = "example.nl"; root = "/sites/example.nl"; } - ]; -} -</programlisting> - -But in this case (where every root is a subdirectory of -<filename>/sites</filename> named after the virtual host), it would -have been shorter to define <varname>makeVirtualHost</varname> as -<programlisting> -makeVirtualHost = name: - { hostName = name; - documentRoot = "/sites/${name}"; - adminAddr = "alice@example.org"; - }; -</programlisting> - -Here, the construct -<literal>${<replaceable>...</replaceable>}</literal> allows the result -of an expression to be spliced into a string.</para> - -</section> - - -<section xml:id="sec-modularity"><title>Modularity</title> - -<para>The NixOS configuration mechanism is modular. If your -<filename>configuration.nix</filename> becomes too big, you can split -it into multiple files. Likewise, if you have multiple NixOS -configurations (e.g. for different computers) with some commonality, -you can move the common configuration into a shared file.</para> - -<para>Modules have exactly the same syntax as -<filename>configuration.nix</filename>. In fact, -<filename>configuration.nix</filename> is itself a module. You can -use other modules by including them from -<filename>configuration.nix</filename>, e.g.: - -<programlisting> -{ config, pkgs, ... }: - -{ imports = [ ./vpn.nix ./kde.nix ]; - services.httpd.enable = true; - environment.systemPackages = [ pkgs.emacs ]; - <replaceable>...</replaceable> -} -</programlisting> - -Here, we include two modules from the same directory, -<filename>vpn.nix</filename> and <filename>kde.nix</filename>. The -latter might look like this: - -<programlisting> -{ config, pkgs, ... }: - -{ services.xserver.enable = true; - services.xserver.displayManager.kdm.enable = true; - services.xserver.desktopManager.kde4.enable = true; - environment.systemPackages = [ pkgs.kde4.kscreensaver ]; -} -</programlisting> - -Note that both <filename>configuration.nix</filename> and -<filename>kde.nix</filename> define the option -<option>environment.systemPackages</option>. When multiple modules -define an option, NixOS will try to <emphasis>merge</emphasis> the -definitions. In the case of -<option>environment.systemPackages</option>, that’s easy: the lists of -packages can simply be concatenated. The value in -<filename>configuration.nix</filename> is merged last, so for -list-type options, it will appear at the end of the merged list. If -you want it to appear first, you can use <varname>mkBefore</varname>: - -<programlisting> -boot.kernelModules = mkBefore [ "kvm-intel" ]; -</programlisting> - -This causes the <literal>kvm-intel</literal> kernel module to be -loaded before any other kernel modules.</para> - -<para>For other types of options, a merge may not be possible. For -instance, if two modules define -<option>services.httpd.adminAddr</option>, -<command>nixos-rebuild</command> will give an error: - -<screen> -The unique option `services.httpd.adminAddr' is defined multiple times, in `/etc/nixos/httpd.nix' and `/etc/nixos/configuration.nix'. -</screen> - -When that happens, it’s possible to force one definition take -precedence over the others: - -<programlisting> -services.httpd.adminAddr = pkgs.lib.mkForce "bob@example.org"; -</programlisting> - -</para> - -<para>When using multiple modules, you may need to access -configuration values defined in other modules. This is what the -<varname>config</varname> function argument is for: it contains the -complete, merged system configuration. That is, -<varname>config</varname> is the result of combining the -configurations returned by every module<footnote><para>If you’re -wondering how it’s possible that the (indirect) -<emphasis>result</emphasis> of a function is passed as an -<emphasis>input</emphasis> to that same function: that’s because Nix -is a “lazy” language — it only computes values when they are needed. -This works as long as no individual configuration value depends on -itself.</para></footnote>. For example, here is a module that adds -some packages to <option>environment.systemPackages</option> only if -<option>services.xserver.enable</option> is set to -<literal>true</literal> somewhere else: - -<programlisting> -{ config, pkgs, ... }: - -{ environment.systemPackages = - if config.services.xserver.enable then - [ pkgs.firefox - pkgs.thunderbird - ] - else - [ ]; -} -</programlisting> - -</para> - -<para>With multiple modules, it may not be obvious what the final -value of a configuration option is. The command -<option>nixos-option</option> allows you to find out: - -<screen> -$ nixos-option services.xserver.enable -true - -$ nixos-option boot.kernelModules -[ "tun" "ipv6" "loop" <replaceable>...</replaceable> ] -</screen> - -Interactive exploration of the configuration is possible using -<command -xlink:href="https://github.com/edolstra/nix-repl">nix-repl</command>, -a read-eval-print loop for Nix expressions. It’s not installed by -default; run <literal>nix-env -i nix-repl</literal> to get it. A -typical use: - -<screen> -$ nix-repl '<nixos>' - -nix-repl> config.networking.hostName -"mandark" - -nix-repl> map (x: x.hostName) config.services.httpd.virtualHosts -[ "example.org" "example.gov" ] -</screen> - -</para> - -</section> - - -<section xml:id="sec-nix-syntax-summary"><title>Syntax summary</title> - -<para>Below is a summary of the most important syntactic constructs in -the Nix expression language. It’s not complete. In particular, there -are many other built-in functions. See the <link -xlink:href="http://nixos.org/nix/manual/#chap-writing-nix-expressions">Nix -manual</link> for the rest.</para> - -<informaltable frame='none'> - <tgroup cols='2'> - <colspec colname='c1' rowsep='1' colsep='1' /> - <colspec colname='c2' rowsep='1' /> - <thead> - <row> - <entry>Example</entry> - <entry>Description</entry> - </row> - </thead> - <tbody> - - <row> - <entry namest="c1" nameend="c2"><emphasis>Basic values</emphasis></entry> - </row> - <row> - <entry><literal>"Hello world"</literal></entry> - <entry>A string</entry> - </row> - <row> - <entry><literal>"${pkgs.bash}/bin/sh"</literal></entry> - <entry>A string containing an expression (expands to <literal>"/nix/store/<replaceable>hash</replaceable>-bash-<replaceable>version</replaceable>/bin/sh"</literal>)</entry> - </row> - <row> - <entry><literal>true</literal>, <literal>false</literal></entry> - <entry>Booleans</entry> - </row> - <row> - <entry><literal>123</literal></entry> - <entry>An integer</entry> - </row> - <row> - <entry><literal>./foo.png</literal></entry> - <entry>A path (relative to the containing Nix expression)</entry> - </row> - - <row> - <entry namest="c1" nameend="c2"><emphasis>Compound values</emphasis></entry> - </row> - <row> - <entry><literal>{ x = 1; y = 2; }</literal></entry> - <entry>An set with attributes names <literal>x</literal> and <literal>y</literal></entry> - </row> - <row> - <entry><literal>{ foo.bar = 1; }</literal></entry> - <entry>A nested set, equivalent to <literal>{ foo = { bar = 1; }; }</literal></entry> - </row> - <row> - <entry><literal>rec { x = "bla"; y = x + "bar"; }</literal></entry> - <entry>A recursive set, equivalent to <literal>{ x = "foo"; y = "foobar"; }</literal></entry> - </row> - <row> - <entry><literal>[ "foo" "bar" ]</literal></entry> - <entry>A list with two elements</entry> - </row> - - <row> - <entry namest="c1" nameend="c2"><emphasis>Operators</emphasis></entry> - </row> - <row> - <entry><literal>"foo" + "bar"</literal></entry> - <entry>String concatenation</entry> - </row> - <row> - <entry><literal>1 + 2</literal></entry> - <entry>Integer addition</entry> - </row> - <row> - <entry><literal>"foo" == "f" + "oo"</literal></entry> - <entry>Equality test (evaluates to <literal>true</literal>)</entry> - </row> - <row> - <entry><literal>"foo" != "bar"</literal></entry> - <entry>Inequality test (evaluates to <literal>true</literal>)</entry> - </row> - <row> - <entry><literal>!true</literal></entry> - <entry>Boolean negation</entry> - </row> - <row> - <entry><literal>{ x = 1; y = 2; }.x</literal></entry> - <entry>Attribute selection (evaluates to <literal>1</literal>)</entry> - </row> - <row> - <entry><literal>{ x = 1; y = 2; }.z or 3</literal></entry> - <entry>Attribute selection with default (evaluates to <literal>3</literal>)</entry> - </row> - <row> - <entry><literal>{ x = 1; y = 2; } // { z = 3; }</literal></entry> - <entry>Merge two sets (attributes in the right-hand set taking precedence)</entry> - </row> - - <row> - <entry namest="c1" nameend="c2"><emphasis>Control structures</emphasis></entry> - </row> - <row> - <entry><literal>if 1 + 1 == 2 then "yes!" else "no!"</literal></entry> - <entry>Conditional expression</entry> - </row> - <row> - <entry><literal>assert 1 + 1 == 2; "yes!"</literal></entry> - <entry>Assertion check (evaluates to <literal>"yes!"</literal>)</entry> - </row> - <row> - <entry><literal>let x = "foo"; y = "bar"; in x + y</literal></entry> - <entry>Variable definition</entry> - </row> - <row> - <entry><literal>with pkgs.lib; head [ 1 2 3 ]</literal></entry> - <entry>Add all attributes from the given set to the scope - (evaluates to <literal>1</literal>)</entry> - </row> - - <row> - <entry namest="c1" nameend="c2"><emphasis>Functions (lambdas)</emphasis></entry> - </row> - <row> - <entry><literal>x: x + 1</literal></entry> - <entry>A function that expects an integer and returns it increased by 1</entry> - </row> - <row> - <entry><literal>(x: x + 1) 100</literal></entry> - <entry>A function call (evaluates to 101)</entry> - </row> - <row> - <entry><literal>let inc = x: x + 1; in inc (inc (inc 100))</literal></entry> - <entry>A function bound to a variable and subsequently called by name (evaluates to 103)</entry> - </row> - <row> - <entry><literal>{ x, y }: x + y</literal></entry> - <entry>A function that expects a set with required attributes - <literal>x</literal> and <literal>y</literal> and concatenates - them</entry> - </row> - <row> - <entry><literal>{ x, y ? "bar" }: x + y</literal></entry> - <entry>A function that expects a set with required attribute - <literal>x</literal> and optional <literal>y</literal>, using - <literal>"bar"</literal> as default value for - <literal>y</literal></entry> - </row> - <row> - <entry><literal>{ x, y, ... }: x + y</literal></entry> - <entry>A function that expects a set with required attributes - <literal>x</literal> and <literal>y</literal> and ignores any - other attributes</entry> - </row> - <row> - <entry><literal>{ x, y } @ args: x + y</literal></entry> - <entry>A function that expects a set with required attributes - <literal>x</literal> and <literal>y</literal>, and binds the - whole set to <literal>args</literal></entry> - </row> - - <row> - <entry namest="c1" nameend="c2"><emphasis>Built-in functions</emphasis></entry> - </row> - <row> - <entry><literal>import ./foo.nix</literal></entry> - <entry>Load and return Nix expression in given file</entry> - </row> - <row> - <entry><literal>map (x: x + x) [ 1 2 3 ]</literal></entry> - <entry>Apply a function to every element of a list (evaluates to <literal>[ 2 4 6 ]</literal>)</entry> - </row> - <!-- - <row> - <entry><literal>throw "Urgh"</literal></entry> - <entry>Raise an error condition</entry> - </row> - --> - - </tbody> - </tgroup> -</informaltable> - -</section> - - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-package-management"><title>Package management</title> - -<para>This section describes how to add additional packages to your -system. NixOS has two distinct styles of package management: - -<itemizedlist> - - <listitem><para><emphasis>Declarative</emphasis>, where you declare - what packages you want in your - <filename>configuration.nix</filename>. Every time you run - <command>nixos-rebuild</command>, NixOS will ensure that you get a - consistent set of binaries corresponding to your - specification.</para></listitem> - - <listitem><para><emphasis>Ad hoc</emphasis>, where you install, - upgrade and uninstall packages via the <command>nix-env</command> - command. This style allows mixing packages from different Nixpkgs - versions. It’s the only choice for non-root - users.</para></listitem> - -</itemizedlist> - -</para> - -<para>The next two sections describe these two styles.</para> - - -<section><title>Declarative package management</title> - -<para>With declarative package management, you specify which packages -you want on your system by setting the option -<option>environment.systemPackages</option>. For instance, adding the -following line to <filename>configuration.nix</filename> enables the -Mozilla Thunderbird email application: - -<programlisting> -environment.systemPackages = [ pkgs.thunderbird ]; -</programlisting> - -The effect of this specification is that the Thunderbird package from -Nixpkgs will be built or downloaded as part of the system when you run -<command>nixos-rebuild switch</command>.</para> - -<para>You can get a list of the available packages as follows: -<screen> -$ nix-env -qaP '*' --description -nixos.pkgs.firefox firefox-23.0 Mozilla Firefox - the browser, reloaded -<replaceable>...</replaceable> -</screen> - -The first column in the output is the <emphasis>attribute -name</emphasis>, such as -<literal>nixos.pkgs.thunderbird</literal>. (The -<literal>nixos</literal> prefix allows distinguishing between -different channels that you might have.)</para> - -<para>To “uninstall” a package, simply remove it from -<option>environment.systemPackages</option> and run -<command>nixos-rebuild switch</command>.</para> - - -<section xml:id="sec-customising-packages"><title>Customising packages</title> - -<para>Some packages in Nixpkgs have options to enable or disable -optional functionality or change other aspects of the package. For -instance, the Firefox wrapper package (which provides Firefox with a -set of plugins such as the Adobe Flash player) has an option to enable -the Google Talk plugin. It can be set in -<filename>configuration.nix</filename> as follows: - -<filename> -nixpkgs.config.firefox.enableGoogleTalkPlugin = true; -</filename> -</para> - -<warning><para>Unfortunately, Nixpkgs currently lacks a way to query -available configuration options.</para></warning> - -<para>Apart from high-level options, it’s possible to tweak a package -in almost arbitrary ways, such as changing or disabling dependencies -of a package. For instance, the Emacs package in Nixpkgs by default -has a dependency on GTK+ 2. If you want to build it against GTK+ 3, -you can specify that as follows: - -<programlisting> -environment.systemPackages = [ (pkgs.emacs.override { gtk = pkgs.gtk3; }) ]; -</programlisting> - -The function <varname>override</varname> performs the call to the Nix -function that produces Emacs, with the original arguments amended by -the set of arguments specified by you. So here the function argument -<varname>gtk</varname> gets the value <literal>pkgs.gtk3</literal>, -causing Emacs to depend on GTK+ 3. (The parentheses are necessary -because in Nix, function application binds more weakly than list -construction, so without them, -<literal>environment.systemPackages</literal> would be a list with two -elements.)</para> - -<para>Even greater customisation is possible using the function -<varname>overrideDerivation</varname>. While the -<varname>override</varname> mechanism above overrides the arguments of -a package function, <varname>overrideDerivation</varname> allows -changing the <emphasis>result</emphasis> of the function. This -permits changing any aspect of the package, such as the source code. -For instance, if you want to override the source code of Emacs, you -can say: - -<programlisting> -environment.systemPackages = - [ (pkgs.lib.overrideDerivation pkgs.emacs (attrs: { - name = "emacs-25.0-pre"; - src = /path/to/my/emacs/tree; - })) - ]; -</programlisting> - -Here, <varname>overrideDerivation</varname> takes the Nix derivation -specified by <varname>pkgs.emacs</varname> and produces a new -derivation in which the original’s <literal>name</literal> and -<literal>src</literal> attribute have been replaced by the given -values. The original attributes are accessible via -<varname>attrs</varname>.</para> - -<para>The overrides shown above are not global. They do not affect -the original package; other packages in Nixpkgs continue to depend on -the original rather than the customised package. This means that if -another package in your system depends on the original package, you -end up with two instances of the package. If you want to have -everything depend on your customised instance, you can apply a -<emphasis>global</emphasis> override as follows: - -<screen> -nixpkgs.config.packageOverrides = pkgs: - { emacs = pkgs.emacs.override { gtk = pkgs.gtk3; }; - }; -</screen> - -The effect of this definition is essentially equivalent to modifying -the <literal>emacs</literal> attribute in the Nixpkgs source tree. -Any package in Nixpkgs that depends on <literal>emacs</literal> will -be passed your customised instance. (However, the value -<literal>pkgs.emacs</literal> in -<varname>nixpkgs.config.packageOverrides</varname> refers to the -original rather than overridden instance, to prevent an infinite -recursion.)</para> - -</section> - -<section xml:id="sec-custom-packages"><title>Adding custom packages</title> - -<para>It’s possible that a package you need is not available in NixOS. -In that case, you can do two things. First, you can clone the Nixpkgs -repository, add the package to your clone, and (optionally) submit a -patch or pull request to have it accepted into the main Nixpkgs -repository. This is described in detail in the <link -xlink:href="http://nixos.org/nixpkgs/manual">Nixpkgs manual</link>. -In short, you clone Nixpkgs: - -<screen> -$ git clone git://github.com/NixOS/nixpkgs.git -$ cd nixpkgs -</screen> - -Then you write and test the package as described in the Nixpkgs -manual. Finally, you add it to -<literal>environment.systemPackages</literal>, e.g. - -<programlisting> -environment.systemPackages = [ pkgs.my-package ]; -</programlisting> - -and you run <command>nixos-rebuild</command>, specifying your own -Nixpkgs tree: - -<screen> -$ nixos-rebuild switch -I nixpkgs=/path/to/my/nixpkgs</screen> - -</para> - -<para>The second possibility is to add the package outside of the -Nixpkgs tree. For instance, here is how you specify a build of the -<link xlink:href="http://www.gnu.org/software/hello/">GNU Hello</link> -package directly in <filename>configuration.nix</filename>: - -<programlisting> -environment.systemPackages = - let - my-hello = with pkgs; stdenv.mkDerivation rec { - name = "hello-2.8"; - src = fetchurl { - url = "mirror://gnu/hello/${name}.tar.gz"; - sha256 = "0wqd8sjmxfskrflaxywc7gqw7sfawrfvdxd9skxawzfgyy0pzdz6"; - }; - }; - in - [ my-hello ]; -</programlisting> - -Of course, you can also move the definition of -<literal>my-hello</literal> into a separate Nix expression, e.g. -<programlisting> -environment.systemPackages = [ (import ./my-hello.nix) ]; -</programlisting> -where <filename>my-hello.nix</filename> contains: -<programlisting> -with import <nixpkgs> {}; # bring all of Nixpkgs into scope - -stdenv.mkDerivation rec { - name = "hello-2.8"; - src = fetchurl { - url = "mirror://gnu/hello/${name}.tar.gz"; - sha256 = "0wqd8sjmxfskrflaxywc7gqw7sfawrfvdxd9skxawzfgyy0pzdz6"; - }; -} -</programlisting> - -This allows testing the package easily: -<screen> -$ nix-build my-hello.nix -$ ./result/bin/hello -Hello, world! -</screen> - -</para> - -</section> - -</section> - - -<section><title>Ad hoc package management</title> - -<para>With the command <command>nix-env</command>, you can install and -uninstall packages from the command line. For instance, to install -Mozilla Thunderbird: - -<screen> -$ nix-env -iA nixos.pkgs.thunderbird</screen> - -If you invoke this as root, the package is installed in the Nix -profile <filename>/nix/var/nix/profiles/default</filename> and visible -to all users of the system; otherwise, the package ends up in -<filename>/nix/var/nix/profiles/per-user/<replaceable>username</replaceable>/profile</filename> -and is not visible to other users. The <option>-A</option> flag -specifies the package by its attribute name; without it, the package -is installed by matching against its package name -(e.g. <literal>thunderbird</literal>). The latter is slower because -it requires matching against all available Nix packages, and is -ambiguous if there are multiple matching packages.</para> - -<para>Packages come from the NixOS channel. You typically upgrade a -package by updating to the latest version of the NixOS channel: -<screen> -$ nix-channel --update nixos -</screen> -and then running <literal>nix-env -i</literal> again. Other packages -in the profile are <emphasis>not</emphasis> affected; this is the -crucial difference with the declarative style of package management, -where running <command>nixos-rebuild switch</command> causes all -packages to be updated to their current versions in the NixOS channel. -You can however upgrade all packages for which there is a newer -version by doing: -<screen> -$ nix-env -u '*' -</screen> -</para> - -<para>A package can be uninstalled using the <option>-e</option> -flag: -<screen> -$ nix-env -e thunderbird -</screen> -</para> - -<para>Finally, you can roll back an undesirable -<command>nix-env</command> action: -<screen> -$ nix-env --rollback -</screen> -</para> - -<para><command>nix-env</command> has many more flags. For details, -see the -<citerefentry><refentrytitle>nix-env</refentrytitle><manvolnum>1</manvolnum></citerefentry> -manpage or the Nix manual.</para> - -</section> - - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-user-management"><title>User management</title> - -<para>NixOS supports both declarative and imperative styles of user -management. In the declarative style, users are specified in -<filename>configuration.nix</filename>. For instance, the following -states that a user account named <literal>alice</literal> shall exist: - -<programlisting> -users.extraUsers.alice = - { createHome = true; - home = "/home/alice"; - description = "Alice Foobar"; - extraGroups = [ "wheel" "networkmanager" ]; - useDefaultShell = true; - openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3Nza... alice@foobar" ]; - }; -</programlisting> - -Note that <literal>alice</literal> is a member of the -<literal>wheel</literal> and <literal>networkmanager</literal> groups, -which allows her to use <command>sudo</command> to execute commands as -<literal>root</literal> and to configure the network, respectively. -Also note the SSH public key that allows remote logins with the -corresponding private key. Users created in this way do not have a -password by default, so they cannot log in via mechanisms that require -a password. However, you can use the <command>passwd</command> program -to set a password, which is retained across invocations of -<command>nixos-rebuild</command>.</para> - -<para>A user ID (uid) is assigned automatically. You can also specify -a uid manually by adding - -<programlisting> - uid = 1000; -</programlisting> - -to the user specification.</para> - -<para>Groups can be specified similarly. The following states that a -group named <literal>students</literal> shall exist: - -<programlisting> -users.extraGroups.students.gid = 1000; -</programlisting> - -As with users, the group ID (gid) is optional and will be assigned -automatically if it’s missing.</para> - -<warning><para>Currently declarative user management is not perfect: -<command>nixos-rebuild</command> does not know how to realise certain -configuration changes. This includes removing a user or group, and -removing group membership from a user.</para></warning> - -<para>In the imperative style, users and groups are managed by -commands such as <command>useradd</command>, -<command>groupmod</command> and so on. For instance, to create a user -account named <literal>alice</literal>: - -<screen> -$ useradd -m alice</screen> - -The flag <option>-m</option> causes the creation of a home directory -for the new user, which is generally what you want. The user does not -have an initial password and therefore cannot log in. A password can -be set using the <command>passwd</command> utility: - -<screen> -$ passwd alice -Enter new UNIX password: *** -Retype new UNIX password: *** -</screen> - -A user can be deleted using <command>userdel</command>: - -<screen> -$ userdel -r alice</screen> - -The flag <option>-r</option> deletes the user’s home directory. -Accounts can be modified using <command>usermod</command>. Unix -groups can be managed using <command>groupadd</command>, -<command>groupmod</command> and <command>groupdel</command>.</para> - -</section> - - -<!--===============================================================--> - -<section><title>File systems</title> - -<para>You can define file systems using the -<option>fileSystems</option> configuration option. For instance, the -following definition causes NixOS to mount the Ext4 file system on -device <filename>/dev/disk/by-label/data</filename> onto the mount -point <filename>/data</filename>: - -<programlisting> -fileSystems."/data" = - { device = "/dev/disk/by-label/data"; - fsType = "ext4"; - }; -</programlisting> - -Mount points are created automatically if they don’t already exist. -For <option>device</option>, it’s best to use the topology-independent -device aliases in <filename>/dev/disk/by-label</filename> and -<filename>/dev/disk/by-uuid</filename>, as these don’t change if the -topology changes (e.g. if a disk is moved to another IDE -controller).</para> - -<para>You can usually omit the file system type -(<option>fsType</option>), since <command>mount</command> can usually -detect the type and load the necessary kernel module automatically. -However, if the file system is needed at early boot (in the initial -ramdisk) and is not <literal>ext2</literal>, <literal>ext3</literal> -or <literal>ext4</literal>, then it’s best to specify -<option>fsType</option> to ensure that the kernel module is -available.</para> - -<section><title>LUKS-encrypted file systems</title> - -<para>NixOS supports file systems that are encrypted using -<emphasis>LUKS</emphasis> (Linux Unified Key Setup). For example, -here is how you create an encrypted Ext4 file system on the device -<filename>/dev/sda2</filename>: - -<screen> -$ cryptsetup luksFormat /dev/sda2 - -WARNING! -======== -This will overwrite data on /dev/sda2 irrevocably. - -Are you sure? (Type uppercase yes): YES -Enter LUKS passphrase: *** -Verify passphrase: *** - -$ cryptsetup luksOpen /dev/sda2 crypted -Enter passphrase for /dev/sda2: *** - -$ mkfs.ext4 /dev/mapper/crypted -</screen> - -To ensure that this file system is automatically mounted at boot time -as <filename>/</filename>, add the following to -<filename>configuration.nix</filename>: - -<programlisting> -boot.initrd.luks.devices = [ { device = "/dev/sda2"; name = "crypted"; } ]; -fileSystems."/".device = "/dev/mapper/crypted"; -</programlisting> - -</para> - -</section> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-x11"><title>X Window System</title> - -<para>The X Window System (X11) provides the basis of NixOS’ graphical -user interface. It can be enabled as follows: -<programlisting> -services.xserver.enable = true; -</programlisting> -The X server will automatically detect and use the appropriate video -driver from a set of X.org drivers (such as <literal>vesa</literal> -and <literal>intel</literal>). You can also specify a driver -manually, e.g. -<programlisting> -services.xserver.videoDrivers = [ "r128" ]; -</programlisting> -to enable X.org’s <literal>xf86-video-r128</literal> driver.</para> - -<para>You also need to enable at least one desktop or window manager. -Otherwise, you can only log into a plain undecorated -<command>xterm</command> window. Thus you should pick one or more of -the following lines: -<programlisting> -services.xserver.desktopManager.kde4.enable = true; -services.xserver.desktopManager.xfce.enable = true; -services.xserver.windowManager.xmonad.enable = true; -services.xserver.windowManager.twm.enable = true; -services.xserver.windowManager.icewm.enable = true; -</programlisting> -</para> - -<para>NixOS’s default <emphasis>display manager</emphasis> (the -program that provides a graphical login prompt and manages the X -server) is SLiM. You can select KDE’s <command>kdm</command> instead: -<programlisting> -services.xserver.displayManager.kdm.enable = true; -</programlisting> -</para> - -<para>The X server is started automatically at boot time. If you -don’t want this to happen, you can set: -<programlisting> -services.xserver.autorun = false; -</programlisting> -The X server can then be started manually: -<screen> -$ systemctl start display-manager.service -</screen> -</para> - - -<section><title>NVIDIA graphics cards</title> - -<para>NVIDIA provides a proprietary driver for its graphics cards that -has better 3D performance than the X.org drivers. It is not enabled -by default because it’s not free software. You can enable it as follows: -<programlisting> -services.xserver.videoDrivers = [ "nvidia" ]; -</programlisting> -You may need to reboot after enabling this driver to prevent a clash -with other kernel modules.</para> - -<para>On 64-bit systems, if you want full acceleration for 32-bit -programs such as Wine, you should also set the following: -<programlisting> -services.xserver.driSupport32Bit = true; -</programlisting> -</para> - -</section> - - -<section><title>Touchpads</title> - -<para>Support for Synaptics touchpads (found in many laptops such as -the Dell Latitude series) can be enabled as follows: -<programlisting> -services.xserver.synaptics.enable = true; -</programlisting> -The driver has many options (see <xref linkend="ch-options"/>). For -instance, the following enables two-finger scrolling: -<programlisting> -services.xserver.synaptics.twoFingerScroll = true; -</programlisting> -</para> - -</section> - - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-networking"><title>Networking</title> - -<section xml:id="sec-networkmanager"><title>NetworkManager</title> - -<para>To facilitate network configuration, some desktop environments -use NetworkManager. You can enable NetworkManager by setting: - -<programlisting> -services.networkmanager.enable = true; -</programlisting> - -Some desktop managers (e.g., GNOME) enable NetworkManager -automatically for you.</para> - -<para>All users that should have permission to change network settings -must belong to the <code>networkmanager</code> group.</para> - -<note><para><code>services.networkmanager</code> and -<code>services.wireless</code> can not be enabled at the same time: -you can still connect to the wireless networks using -NetworkManager.</para></note> - -</section> - -<section xml:id="sec-ssh"><title>Secure shell access</title> - -<para>Secure shell (SSH) access to your machine can be enabled by -setting: - -<programlisting> -services.openssh.enable = true; -</programlisting> - -By default, root logins using a password are disallowed. They can be -disabled entirely by setting -<literal>services.openssh.permitRootLogin</literal> to -<literal>"no"</literal>.</para> - -<para>You can declaratively specify authorised RSA/DSA public keys for -a user as follows: - -<!-- FIXME: this might not work if the user is unmanaged. --> -<programlisting> -users.extraUsers.alice.openssh.authorizedKeys.keys = - [ "ssh-dss AAAAB3NzaC1kc3MAAACBAPIkGWVEt4..." ]; -</programlisting> - -</para> - -</section> - - -<section xml:id="sec-ipv4"><title>IPv4 configuration</title> - -<para>By default, NixOS uses DHCP (specifically, -<command>dhcpcd</command>) to automatically configure network -interfaces. However, you can configure an interface manually as -follows: - -<programlisting> -networking.interfaces.eth0 = { ipAddress = "192.168.1.2"; prefixLength = 24; }; -</programlisting> - -(The network prefix can also be specified using the option -<literal>subnetMask</literal>, -e.g. <literal>"255.255.255.0"</literal>, but this is deprecated.) -Typically you’ll also want to set a default gateway and set of name -servers: - -<programlisting> -networking.defaultGateway = "192.168.1.1"; -networking.nameservers = [ "8.8.8.8" ]; -</programlisting> - -</para> - -<note><para>Statically configured interfaces are set up by the systemd -service -<replaceable>interface-name</replaceable><literal>-cfg.service</literal>. -The default gateway and name server configuration is performed by -<literal>network-setup.service</literal>.</para></note> - -<para>The host name is set using <option>networking.hostName</option>: - -<programlisting> -networking.hostName = "cartman"; -</programlisting> - -The default host name is <literal>nixos</literal>. Set it to the -empty string (<literal>""</literal>) to allow the DHCP server to -provide the host name.</para> - -</section> - - -<section xml:id="sec-ipv6"><title>IPv6 configuration</title> - -<para>IPv6 is enabled by default. Stateless address autoconfiguration -is used to automatically assign IPv6 addresses to all interfaces. You -can disable IPv6 support globally by setting: - -<programlisting> -networking.enableIPv6 = false; -</programlisting> - -</para> - -</section> - - -<section xml:id="sec-firewall"><title>Firewall</title> - -<para>NixOS has a simple stateful firewall that blocks incoming -connections and other unexpected packets. The firewall applies to -both IPv4 and IPv6 traffic. It is enabled by default. It can be -disabled as follows: - -<programlisting> -networking.firewall.enable = false; -</programlisting> - -If the firewall is enabled, you can open specific TCP ports to the -outside world: - -<programlisting> -networking.firewall.allowedTCPPorts = [ 80 443 ]; -</programlisting> - -Note that TCP port 22 (ssh) is opened automatically if the SSH daemon -is enabled (<option>services.openssh.enable = true</option>). UDP -ports can be opened through -<option>networking.firewall.allowedUDPPorts</option>. Also of -interest is - -<programlisting> -networking.firewall.allowPing = true; -</programlisting> - -to allow the machine to respond to ping requests. (ICMPv6 pings are -always allowed.)</para> - -</section> - - -<section xml:id="sec-wireless"><title>Wireless networks</title> - -<para>For a desktop installation using NetworkManager (e.g., GNOME), -you just have to make sure the user is in the -<code>networkmanager</code> group and you can skip the rest of this -section on wireless networks.</para> - -<para> -NixOS will start wpa_supplicant for you if you enable this setting: - -<programlisting> -networking.wireless.enable = true; -</programlisting> - -NixOS currently does not generate wpa_supplicant's -configuration file, <literal>/etc/wpa_supplicant.conf</literal>. You should edit this file -yourself to define wireless networks, WPA keys and so on (see -wpa_supplicant.conf(5)). -</para> - -<para> -If you are using WPA2 the <command>wpa_passphrase</command> tool might be useful -to generate the <literal>wpa_supplicant.conf</literal>. - -<screen> -$ wpa_passphrase ESSID PSK > /etc/wpa_supplicant.conf</screen> - -After you have edited the <literal>wpa_supplicant.conf</literal>, -you need to restart the wpa_supplicant service. - -<screen> -$ systemctl restart wpa_supplicant.service</screen> -</para> - - -</section> - - -<section><title>Ad-hoc configuration</title> - -<para>You can use <option>networking.localCommands</option> to specify -shell commands to be run at the end of -<literal>network-setup.service</literal>. This is useful for doing -network configuration not covered by the existing NixOS modules. For -instance, to statically configure an IPv6 address: - -<programlisting> -networking.localCommands = - '' - ip -6 addr add 2001:610:685:1::1/64 dev eth0 - ''; -</programlisting> - -</para> - -</section> - - -<!-- TODO: OpenVPN, NAT --> - - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-kernel-config"><title>Linux kernel</title> - -<para>You can override the Linux kernel and associated packages using -the option <option>boot.kernelPackages</option>. For instance, this -selects the Linux 3.10 kernel: -<programlisting> -boot.kernelPackages = pkgs.linuxPackages_3_10; -</programlisting> -Note that this not only replaces the kernel, but also packages that -are specific to the kernel version, such as the NVIDIA video drivers. -This ensures that driver packages are consistent with the -kernel.</para> - -<para>The default Linux kernel configuration should be fine for most users. You can see the configuration of your current kernel with the following command: -<programlisting> -cat /proc/config.gz | gunzip -</programlisting> -If you want to change the kernel configuration, you can use the -<option>packageOverrides</option> feature (see <xref -linkend="sec-customising-packages" />). For instance, to enable -support for the kernel debugger KGDB: - -<programlisting> -nixpkgs.config.packageOverrides = pkgs: - { linux_3_4 = pkgs.linux_3_4.override { - extraConfig = - '' - KGDB y - ''; - }; - }; -</programlisting> - -<varname>extraConfig</varname> takes a list of Linux kernel -configuration options, one per line. The name of the option should -not include the prefix <literal>CONFIG_</literal>. The option value -is typically <literal>y</literal>, <literal>n</literal> or -<literal>m</literal> (to build something as a kernel module).</para> - -<para>Kernel modules for hardware devices are generally loaded -automatically by <command>udev</command>. You can force a module to -be loaded via <option>boot.kernelModules</option>, e.g. -<programlisting> -boot.kernelModules = [ "fuse" "kvm-intel" "coretemp" ]; -</programlisting> -If the module is required early during the boot (e.g. to mount the -root file system), you can use -<option>boot.initrd.extraKernelModules</option>: -<programlisting> -boot.initrd.extraKernelModules = [ "cifs" ]; -</programlisting> -This causes the specified modules and their dependencies to be added -to the initial ramdark.</para> - -<para>Kernel runtime parameters can be set through -<option>boot.kernel.sysctl</option>, e.g. -<programlisting> -boot.kernel.sysctl."net.ipv4.tcp_keepalive_time" = 120; -</programlisting> -sets the kernel’s TCP keepalive time to 120 seconds. To see the -available parameters, run <command>sysctl -a</command>.</para> - -</section> - - -<!-- Apache; libvirtd virtualisation --> - - -</chapter> diff --git a/nixos/doc/manual/configuration/abstractions.xml b/nixos/doc/manual/configuration/abstractions.xml new file mode 100644 index 00000000000..cbd54bca62f --- /dev/null +++ b/nixos/doc/manual/configuration/abstractions.xml @@ -0,0 +1,166 @@ +<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-module-abstractions"> + +<title>Abstractions</title> + +<para>If you find yourself repeating yourself over and over, it’s time +to abstract. Take, for instance, this Apache HTTP Server configuration: + +<programlisting> +{ + services.httpd.virtualHosts = + [ { hostName = "example.org"; + documentRoot = "/webroot"; + adminAddr = "alice@example.org"; + enableUserDir = true; + } + { hostName = "example.org"; + documentRoot = "/webroot"; + adminAddr = "alice@example.org"; + enableUserDir = true; + enableSSL = true; + sslServerCert = "/root/ssl-example-org.crt"; + sslServerKey = "/root/ssl-example-org.key"; + } + ]; +} +</programlisting> + +It defines two virtual hosts with nearly identical configuration; the +only difference is that the second one has SSL enabled. To prevent +this duplication, we can use a <literal>let</literal>: + +<programlisting> +let + exampleOrgCommon = + { hostName = "example.org"; + documentRoot = "/webroot"; + adminAddr = "alice@example.org"; + enableUserDir = true; + }; +in +{ + services.httpd.virtualHosts = + [ exampleOrgCommon + (exampleOrgCommon // { + enableSSL = true; + sslServerCert = "/root/ssl-example-org.crt"; + sslServerKey = "/root/ssl-example-org.key"; + }) + ]; +} +</programlisting> + +The <literal>let exampleOrgCommon = +<replaceable>...</replaceable></literal> defines a variable named +<literal>exampleOrgCommon</literal>. The <literal>//</literal> +operator merges two attribute sets, so the configuration of the second +virtual host is the set <literal>exampleOrgCommon</literal> extended +with the SSL options.</para> + +<para>You can write a <literal>let</literal> wherever an expression is +allowed. Thus, you also could have written: + +<programlisting> +{ + services.httpd.virtualHosts = + let exampleOrgCommon = <replaceable>...</replaceable>; in + [ exampleOrgCommon + (exampleOrgCommon // { <replaceable>...</replaceable> }) + ]; +} +</programlisting> + +but not <literal>{ let exampleOrgCommon = +<replaceable>...</replaceable>; in <replaceable>...</replaceable>; +}</literal> since attributes (as opposed to attribute values) are not +expressions.</para> + +<para><emphasis>Functions</emphasis> provide another method of +abstraction. For instance, suppose that we want to generate lots of +different virtual hosts, all with identical configuration except for +the host name. This can be done as follows: + +<programlisting> +{ + services.httpd.virtualHosts = + let + makeVirtualHost = name: + { hostName = name; + documentRoot = "/webroot"; + adminAddr = "alice@example.org"; + }; + in + [ (makeVirtualHost "example.org") + (makeVirtualHost "example.com") + (makeVirtualHost "example.gov") + (makeVirtualHost "example.nl") + ]; +} +</programlisting> + +Here, <varname>makeVirtualHost</varname> is a function that takes a +single argument <literal>name</literal> and returns the configuration +for a virtual host. That function is then called for several names to +produce the list of virtual host configurations.</para> + +<para>We can further improve on this by using the function +<varname>map</varname>, which applies another function to every +element in a list: + +<programlisting> +{ + services.httpd.virtualHosts = + let + makeVirtualHost = <replaceable>...</replaceable>; + in map makeVirtualHost + [ "example.org" "example.com" "example.gov" "example.nl" ]; +} +</programlisting> + +(The function <literal>map</literal> is called a +<emphasis>higher-order function</emphasis> because it takes another +function as an argument.)</para> + +<para>What if you need more than one argument, for instance, if we +want to use a different <literal>documentRoot</literal> for each +virtual host? Then we can make <varname>makeVirtualHost</varname> a +function that takes a <emphasis>set</emphasis> as its argument, like this: + +<programlisting> +{ + services.httpd.virtualHosts = + let + makeVirtualHost = { name, root }: + { hostName = name; + documentRoot = root; + adminAddr = "alice@example.org"; + }; + in map makeVirtualHost + [ { name = "example.org"; root = "/sites/example.org"; } + { name = "example.com"; root = "/sites/example.com"; } + { name = "example.gov"; root = "/sites/example.gov"; } + { name = "example.nl"; root = "/sites/example.nl"; } + ]; +} +</programlisting> + +But in this case (where every root is a subdirectory of +<filename>/sites</filename> named after the virtual host), it would +have been shorter to define <varname>makeVirtualHost</varname> as +<programlisting> +makeVirtualHost = name: + { hostName = name; + documentRoot = "/sites/${name}"; + adminAddr = "alice@example.org"; + }; +</programlisting> + +Here, the construct +<literal>${<replaceable>...</replaceable>}</literal> allows the result +of an expression to be spliced into a string.</para> + +</section> diff --git a/nixos/doc/manual/configuration/ad-hoc-network-config.xml b/nixos/doc/manual/configuration/ad-hoc-network-config.xml new file mode 100644 index 00000000000..26a572ba1fb --- /dev/null +++ b/nixos/doc/manual/configuration/ad-hoc-network-config.xml @@ -0,0 +1,24 @@ +<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="ad-hoc-network-config"> + +<title>Ad-Hoc Configuration</title> + +<para>You can use <option>networking.localCommands</option> to specify +shell commands to be run at the end of +<literal>network-setup.service</literal>. This is useful for doing +network configuration not covered by the existing NixOS modules. For +instance, to statically configure an IPv6 address: + +<programlisting> +networking.localCommands = + '' + ip -6 addr add 2001:610:685:1::1/64 dev eth0 + ''; +</programlisting> + +</para> + +</section> diff --git a/nixos/doc/manual/configuration/ad-hoc-packages.xml b/nixos/doc/manual/configuration/ad-hoc-packages.xml new file mode 100644 index 00000000000..e237e20c4ff --- /dev/null +++ b/nixos/doc/manual/configuration/ad-hoc-packages.xml @@ -0,0 +1,63 @@ +<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-ad-hoc-packages"> + +<title>Ad-Hoc Package Management</title> + +<para>With the command <command>nix-env</command>, you can install and +uninstall packages from the command line. For instance, to install +Mozilla Thunderbird: + +<screen> +$ nix-env -iA nixos.pkgs.thunderbird</screen> + +If you invoke this as root, the package is installed in the Nix +profile <filename>/nix/var/nix/profiles/default</filename> and visible +to all users of the system; otherwise, the package ends up in +<filename>/nix/var/nix/profiles/per-user/<replaceable>username</replaceable>/profile</filename> +and is not visible to other users. The <option>-A</option> flag +specifies the package by its attribute name; without it, the package +is installed by matching against its package name +(e.g. <literal>thunderbird</literal>). The latter is slower because +it requires matching against all available Nix packages, and is +ambiguous if there are multiple matching packages.</para> + +<para>Packages come from the NixOS channel. You typically upgrade a +package by updating to the latest version of the NixOS channel: +<screen> +$ nix-channel --update nixos +</screen> +and then running <literal>nix-env -i</literal> again. Other packages +in the profile are <emphasis>not</emphasis> affected; this is the +crucial difference with the declarative style of package management, +where running <command>nixos-rebuild switch</command> causes all +packages to be updated to their current versions in the NixOS channel. +You can however upgrade all packages for which there is a newer +version by doing: +<screen> +$ nix-env -u '*' +</screen> +</para> + +<para>A package can be uninstalled using the <option>-e</option> +flag: +<screen> +$ nix-env -e thunderbird +</screen> +</para> + +<para>Finally, you can roll back an undesirable +<command>nix-env</command> action: +<screen> +$ nix-env --rollback +</screen> +</para> + +<para><command>nix-env</command> has many more flags. For details, +see the +<citerefentry><refentrytitle>nix-env</refentrytitle><manvolnum>1</manvolnum></citerefentry> +manpage or the Nix manual.</para> + +</section> diff --git a/nixos/doc/manual/configuration/adding-custom-packages.xml b/nixos/doc/manual/configuration/adding-custom-packages.xml new file mode 100644 index 00000000000..c1789fcbc04 --- /dev/null +++ b/nixos/doc/manual/configuration/adding-custom-packages.xml @@ -0,0 +1,84 @@ +<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-custom-packages"> + +<title>Adding Custom Packages</title> + +<para>It’s possible that a package you need is not available in NixOS. +In that case, you can do two things. First, you can clone the Nixpkgs +repository, add the package to your clone, and (optionally) submit a +patch or pull request to have it accepted into the main Nixpkgs +repository. This is described in detail in the <link +xlink:href="http://nixos.org/nixpkgs/manual">Nixpkgs manual</link>. +In short, you clone Nixpkgs: + +<screen> +$ git clone git://github.com/NixOS/nixpkgs.git +$ cd nixpkgs +</screen> + +Then you write and test the package as described in the Nixpkgs +manual. Finally, you add it to +<literal>environment.systemPackages</literal>, e.g. + +<programlisting> +environment.systemPackages = [ pkgs.my-package ]; +</programlisting> + +and you run <command>nixos-rebuild</command>, specifying your own +Nixpkgs tree: + +<screen> +$ nixos-rebuild switch -I nixpkgs=/path/to/my/nixpkgs</screen> + +</para> + +<para>The second possibility is to add the package outside of the +Nixpkgs tree. For instance, here is how you specify a build of the +<link xlink:href="http://www.gnu.org/software/hello/">GNU Hello</link> +package directly in <filename>configuration.nix</filename>: + +<programlisting> +environment.systemPackages = + let + my-hello = with pkgs; stdenv.mkDerivation rec { + name = "hello-2.8"; + src = fetchurl { + url = "mirror://gnu/hello/${name}.tar.gz"; + sha256 = "0wqd8sjmxfskrflaxywc7gqw7sfawrfvdxd9skxawzfgyy0pzdz6"; + }; + }; + in + [ my-hello ]; +</programlisting> + +Of course, you can also move the definition of +<literal>my-hello</literal> into a separate Nix expression, e.g. +<programlisting> +environment.systemPackages = [ (import ./my-hello.nix) ]; +</programlisting> +where <filename>my-hello.nix</filename> contains: +<programlisting> +with import <nixpkgs> {}; # bring all of Nixpkgs into scope + +stdenv.mkDerivation rec { + name = "hello-2.8"; + src = fetchurl { + url = "mirror://gnu/hello/${name}.tar.gz"; + sha256 = "0wqd8sjmxfskrflaxywc7gqw7sfawrfvdxd9skxawzfgyy0pzdz6"; + }; +} +</programlisting> + +This allows testing the package easily: +<screen> +$ nix-build my-hello.nix +$ ./result/bin/hello +Hello, world! +</screen> + +</para> + +</section> diff --git a/nixos/doc/manual/configuration/config-file.xml b/nixos/doc/manual/configuration/config-file.xml new file mode 100644 index 00000000000..2a58ff25941 --- /dev/null +++ b/nixos/doc/manual/configuration/config-file.xml @@ -0,0 +1,213 @@ +<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-configuration-file"> + +<title>NixOS Configuration File</title> + +<para>The NixOS configuration file generally looks like this: + +<programlisting> +{ config, pkgs, ... }: + +{ <replaceable>option definitions</replaceable> +} +</programlisting> + +The first line (<literal>{ config, pkgs, ... }:</literal>) denotes +that this is actually a function that takes at least the two arguments + <varname>config</varname> and <varname>pkgs</varname>. (These are +explained later.) The function returns a <emphasis>set</emphasis> of +option definitions (<literal>{ <replaceable>...</replaceable> }</literal>). These definitions have the +form <literal><replaceable>name</replaceable> = +<replaceable>value</replaceable></literal>, where +<replaceable>name</replaceable> is the name of an option and +<replaceable>value</replaceable> is its value. For example, + +<programlisting> +{ config, pkgs, ... }: + +{ services.httpd.enable = true; + services.httpd.adminAddr = "alice@example.org"; + services.httpd.documentRoot = "/webroot"; +} +</programlisting> + +defines a configuration with three option definitions that together +enable the Apache HTTP Server with <filename>/webroot</filename> as +the document root.</para> + +<para>Sets can be nested, and in fact dots in option names are +shorthand for defining a set containing another set. For instance, +<option>services.httpd.enable</option> defines a set named +<varname>services</varname> that contains a set named +<varname>httpd</varname>, which in turn contains an option definition +named <varname>enable</varname> with value <literal>true</literal>. +This means that the example above can also be written as: + +<programlisting> +{ config, pkgs, ... }: + +{ services = { + httpd = { + enable = true; + adminAddr = "alice@example.org"; + documentRoot = "/webroot"; + }; + }; +} +</programlisting> + +which may be more convenient if you have lots of option definitions +that share the same prefix (such as +<literal>services.httpd</literal>).</para> + +<para>NixOS checks your option definitions for correctness. For +instance, if you try to define an option that doesn’t exist (that is, +doesn’t have a corresponding <emphasis>option declaration</emphasis>), +<command>nixos-rebuild</command> will give an error like: +<screen> +The option `services.httpd.enabl' defined in `/etc/nixos/configuration.nix' does not exist. +</screen> +Likewise, values in option definitions must have a correct type. For +instance, <option>services.httpd.enable</option> must be a Boolean +(<literal>true</literal> or <literal>false</literal>). Trying to give +it a value of another type, such as a string, will cause an error: +<screen> +The option value `services.httpd.enable' in `/etc/nixos/configuration.nix' is not a boolean. +</screen> + +</para> + +<para>Options have various types of values. The most important are: + +<variablelist> + <varlistentry> + <term>Strings</term> + <listitem> + <para>Strings are enclosed in double quotes, e.g. + +<programlisting> +networking.hostName = "dexter"; +</programlisting> + + Special characters can be escaped by prefixing them with a + backslash (e.g. <literal>\"</literal>).</para> + + <para>Multi-line strings can be enclosed in <emphasis>double + single quotes</emphasis>, e.g. + +<programlisting> +networking.extraHosts = + '' + 127.0.0.2 other-localhost + 10.0.0.1 server + ''; +</programlisting> + + The main difference is that preceding whitespace is + automatically stripped from each line, and that characters like + <literal>"</literal> and <literal>\</literal> are not special + (making it more convenient for including things like shell + code).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Booleans</term> + <listitem> + <para>These can be <literal>true</literal> or + <literal>false</literal>, e.g. + +<programlisting> +networking.firewall.enable = true; +networking.firewall.allowPing = false; +</programlisting> + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Integers</term> + <listitem> + <para>For example, + +<programlisting> +boot.kernel.sysctl."net.ipv4.tcp_keepalive_time" = 60; +</programlisting> + + (Note that here the attribute name + <literal>net.ipv4.tcp_keepalive_time</literal> is enclosed in + quotes to prevent it from being interpreted as a set named + <literal>net</literal> containing a set named + <literal>ipv4</literal>, and so on. This is because it’s not a + NixOS option but the literal name of a Linux kernel + setting.)</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Sets</term> + <listitem> + <para>Sets were introduced above. They are name/value pairs + enclosed in braces, as in the option definition + +<programlisting> +fileSystems."/boot" = + { device = "/dev/sda1"; + fsType = "ext4"; + options = "rw,data=ordered,relatime"; + }; +</programlisting> + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Lists</term> + <listitem> + <para>The important thing to note about lists is that list + elements are separated by whitespace, like this: + +<programlisting> +boot.kernelModules = [ "fuse" "kvm-intel" "coretemp" ]; +</programlisting> + + List elements can be any other type, e.g. sets: + +<programlisting> +swapDevices = [ { device = "/dev/disk/by-label/swap"; } ]; +</programlisting> + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>Packages</term> + <listitem> + <para>Usually, the packages you need are already part of the Nix + Packages collection, which is a set that can be accessed through + the function argument <varname>pkgs</varname>. Typical uses: + +<programlisting> +environment.systemPackages = + [ pkgs.thunderbird + pkgs.emacs + ]; + +postgresql.package = pkgs.postgresql90; +</programlisting> + + The latter option definition changes the default PostgreSQL + package used by NixOS’s PostgreSQL service to 9.0. For more + information on packages, including how to add new ones, see + <xref linkend="sec-custom-packages"/>.</para> + </listitem> + </varlistentry> + +</variablelist> + +</para> + +</section> diff --git a/nixos/doc/manual/configuration/config-syntax.xml b/nixos/doc/manual/configuration/config-syntax.xml new file mode 100644 index 00000000000..87847f8451e --- /dev/null +++ b/nixos/doc/manual/configuration/config-syntax.xml @@ -0,0 +1,27 @@ +<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="sec-configuration-syntax"> + +<title>Configuration Syntax</title> + +<para>The NixOS configuration file +<filename>/etc/nixos/configuration.nix</filename> is actually a +<emphasis>Nix expression</emphasis>, which is the Nix package +manager’s purely functional language for describing how to build +packages and configurations. This means you have all the expressive +power of that language at your disposal, including the ability to +abstract over common patterns, which is very useful when managing +complex systems. The syntax and semantics of the Nix language are +fully described in the <link +xlink:href="http://nixos.org/nix/manual/#chap-writing-nix-expressions">Nix +manual</link>, but here we give a short overview of the most important +constructs useful in NixOS configuration files.</para> + +<xi:include href="config-file.xml" /> +<xi:include href="abstractions.xml" /> +<xi:include href="modularity.xml" /> +<xi:include href="summary.xml" /> + +</chapter> diff --git a/nixos/doc/manual/configuration/configuration.xml b/nixos/doc/manual/configuration/configuration.xml new file mode 100644 index 00000000000..8fde0dc7e61 --- /dev/null +++ b/nixos/doc/manual/configuration/configuration.xml @@ -0,0 +1,32 @@ +<part 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="ch-configuration"> + +<title>Configuration</title> + +<partintro> + +<para>This chapter describes how to configure various aspects of a +NixOS machine through the configuration file +<filename>/etc/nixos/configuration.nix</filename>. As described in +<xref linkend="sec-changing-config" />, changes to this file only take +effect after you run <command>nixos-rebuild</command>.</para> + +</partintro> + +<xi:include href="config-syntax.xml" /> +<xi:include href="package-mgmt.xml" /> +<xi:include href="user-mgmt.xml" /> +<xi:include href="file-systems.xml" /> +<xi:include href="x-windows.xml" /> +<xi:include href="networking.xml" /> +<xi:include href="linux-kernel.xml" /> + +<!-- FIXME: auto-include NixOS module docs --> +<xi:include href="postgresql.xml" /> + +<!-- Apache; libvirtd virtualisation --> + +</part> diff --git a/nixos/doc/manual/configuration/customizing-packages.xml b/nixos/doc/manual/configuration/customizing-packages.xml new file mode 100644 index 00000000000..6ee7a95dc6f --- /dev/null +++ b/nixos/doc/manual/configuration/customizing-packages.xml @@ -0,0 +1,92 @@ +<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-customising-packages"> + +<title>Customising Packages</title> + +<para>Some packages in Nixpkgs have options to enable or disable +optional functionality or change other aspects of the package. For +instance, the Firefox wrapper package (which provides Firefox with a +set of plugins such as the Adobe Flash player) has an option to enable +the Google Talk plugin. It can be set in +<filename>configuration.nix</filename> as follows: + +<filename> +nixpkgs.config.firefox.enableGoogleTalkPlugin = true; +</filename> +</para> + +<warning><para>Unfortunately, Nixpkgs currently lacks a way to query +available configuration options.</para></warning> + +<para>Apart from high-level options, it’s possible to tweak a package +in almost arbitrary ways, such as changing or disabling dependencies +of a package. For instance, the Emacs package in Nixpkgs by default +has a dependency on GTK+ 2. If you want to build it against GTK+ 3, +you can specify that as follows: + +<programlisting> +environment.systemPackages = [ (pkgs.emacs.override { gtk = pkgs.gtk3; }) ]; +</programlisting> + +The function <varname>override</varname> performs the call to the Nix +function that produces Emacs, with the original arguments amended by +the set of arguments specified by you. So here the function argument +<varname>gtk</varname> gets the value <literal>pkgs.gtk3</literal>, +causing Emacs to depend on GTK+ 3. (The parentheses are necessary +because in Nix, function application binds more weakly than list +construction, so without them, +<literal>environment.systemPackages</literal> would be a list with two +elements.)</para> + +<para>Even greater customisation is possible using the function +<varname>overrideDerivation</varname>. While the +<varname>override</varname> mechanism above overrides the arguments of +a package function, <varname>overrideDerivation</varname> allows +changing the <emphasis>result</emphasis> of the function. This +permits changing any aspect of the package, such as the source code. +For instance, if you want to override the source code of Emacs, you +can say: + +<programlisting> +environment.systemPackages = + [ (pkgs.lib.overrideDerivation pkgs.emacs (attrs: { + name = "emacs-25.0-pre"; + src = /path/to/my/emacs/tree; + })) + ]; +</programlisting> + +Here, <varname>overrideDerivation</varname> takes the Nix derivation +specified by <varname>pkgs.emacs</varname> and produces a new +derivation in which the original’s <literal>name</literal> and +<literal>src</literal> attribute have been replaced by the given +values. The original attributes are accessible via +<varname>attrs</varname>.</para> + +<para>The overrides shown above are not global. They do not affect +the original package; other packages in Nixpkgs continue to depend on +the original rather than the customised package. This means that if +another package in your system depends on the original package, you +end up with two instances of the package. If you want to have +everything depend on your customised instance, you can apply a +<emphasis>global</emphasis> override as follows: + +<screen> +nixpkgs.config.packageOverrides = pkgs: + { emacs = pkgs.emacs.override { gtk = pkgs.gtk3; }; + }; +</screen> + +The effect of this definition is essentially equivalent to modifying +the <literal>emacs</literal> attribute in the Nixpkgs source tree. +Any package in Nixpkgs that depends on <literal>emacs</literal> will +be passed your customised instance. (However, the value +<literal>pkgs.emacs</literal> in +<varname>nixpkgs.config.packageOverrides</varname> refers to the +original rather than overridden instance, to prevent an infinite +recursion.)</para> + +</section> diff --git a/nixos/doc/manual/configuration/declarative-packages.xml b/nixos/doc/manual/configuration/declarative-packages.xml new file mode 100644 index 00000000000..6de38b452e2 --- /dev/null +++ b/nixos/doc/manual/configuration/declarative-packages.xml @@ -0,0 +1,43 @@ +<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-declarative-package-mgmt"> + +<title>Declarative Package Management</title> + +<para>With declarative package management, you specify which packages +you want on your system by setting the option +<option>environment.systemPackages</option>. For instance, adding the +following line to <filename>configuration.nix</filename> enables the +Mozilla Thunderbird email application: + +<programlisting> +environment.systemPackages = [ pkgs.thunderbird ]; +</programlisting> + +The effect of this specification is that the Thunderbird package from +Nixpkgs will be built or downloaded as part of the system when you run +<command>nixos-rebuild switch</command>.</para> + +<para>You can get a list of the available packages as follows: +<screen> +$ nix-env -qaP '*' --description +nixos.pkgs.firefox firefox-23.0 Mozilla Firefox - the browser, reloaded +<replaceable>...</replaceable> +</screen> + +The first column in the output is the <emphasis>attribute +name</emphasis>, such as +<literal>nixos.pkgs.thunderbird</literal>. (The +<literal>nixos</literal> prefix allows distinguishing between +different channels that you might have.)</para> + +<para>To “uninstall” a package, simply remove it from +<option>environment.systemPackages</option> and run +<command>nixos-rebuild switch</command>.</para> + +<xi:include href="customizing-packages.xml" /> +<xi:include href="adding-custom-packages.xml" /> + +</section> diff --git a/nixos/doc/manual/configuration/file-systems.xml b/nixos/doc/manual/configuration/file-systems.xml new file mode 100644 index 00000000000..d1b324af3f1 --- /dev/null +++ b/nixos/doc/manual/configuration/file-systems.xml @@ -0,0 +1,40 @@ +<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="ch-file-systems"> + +<title>File Systems</title> + +<para>You can define file systems using the +<option>fileSystems</option> configuration option. For instance, the +following definition causes NixOS to mount the Ext4 file system on +device <filename>/dev/disk/by-label/data</filename> onto the mount +point <filename>/data</filename>: + +<programlisting> +fileSystems."/data" = + { device = "/dev/disk/by-label/data"; + fsType = "ext4"; + }; +</programlisting> + +Mount points are created automatically if they don’t already exist. +For <option>device</option>, it’s best to use the topology-independent +device aliases in <filename>/dev/disk/by-label</filename> and +<filename>/dev/disk/by-uuid</filename>, as these don’t change if the +topology changes (e.g. if a disk is moved to another IDE +controller).</para> + +<para>You can usually omit the file system type +(<option>fsType</option>), since <command>mount</command> can usually +detect the type and load the necessary kernel module automatically. +However, if the file system is needed at early boot (in the initial +ramdisk) and is not <literal>ext2</literal>, <literal>ext3</literal> +or <literal>ext4</literal>, then it’s best to specify +<option>fsType</option> to ensure that the kernel module is +available.</para> + +<xi:include href="luks-file-systems.xml" /> + +</chapter> diff --git a/nixos/doc/manual/configuration/firewall.xml b/nixos/doc/manual/configuration/firewall.xml new file mode 100644 index 00000000000..87406c28c2f --- /dev/null +++ b/nixos/doc/manual/configuration/firewall.xml @@ -0,0 +1,38 @@ +<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-firewall"> + +<title>Firewall</title> + +<para>NixOS has a simple stateful firewall that blocks incoming +connections and other unexpected packets. The firewall applies to +both IPv4 and IPv6 traffic. It is enabled by default. It can be +disabled as follows: + +<programlisting> +networking.firewall.enable = false; +</programlisting> + +If the firewall is enabled, you can open specific TCP ports to the +outside world: + +<programlisting> +networking.firewall.allowedTCPPorts = [ 80 443 ]; +</programlisting> + +Note that TCP port 22 (ssh) is opened automatically if the SSH daemon +is enabled (<option>services.openssh.enable = true</option>). UDP +ports can be opened through +<option>networking.firewall.allowedUDPPorts</option>. Also of +interest is + +<programlisting> +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/ipv4-config.xml b/nixos/doc/manual/configuration/ipv4-config.xml new file mode 100644 index 00000000000..053501b1736 --- /dev/null +++ b/nixos/doc/manual/configuration/ipv4-config.xml @@ -0,0 +1,44 @@ +<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-ipv4"> + +<title>IPv4 Configuration</title> + +<para>By default, NixOS uses DHCP (specifically, +<command>dhcpcd</command>) to automatically configure network +interfaces. However, you can configure an interface manually as +follows: + +<programlisting> +networking.interfaces.eth0.ip4 = [ { address = "192.168.1.2"; prefixLength = 24; } ]; +</programlisting> + +Typically you’ll also want to set a default gateway and set of name +servers: + +<programlisting> +networking.defaultGateway = "192.168.1.1"; +networking.nameservers = [ "8.8.8.8" ]; +</programlisting> + +</para> + +<note><para>Statically configured interfaces are set up by the systemd +service +<replaceable>interface-name</replaceable><literal>-cfg.service</literal>. +The default gateway and name server configuration is performed by +<literal>network-setup.service</literal>.</para></note> + +<para>The host name is set using <option>networking.hostName</option>: + +<programlisting> +networking.hostName = "cartman"; +</programlisting> + +The default host name is <literal>nixos</literal>. Set it to the +empty string (<literal>""</literal>) to allow the DHCP server to +provide the host name.</para> + +</section> diff --git a/nixos/doc/manual/configuration/ipv6-config.xml b/nixos/doc/manual/configuration/ipv6-config.xml new file mode 100644 index 00000000000..592bf20e545 --- /dev/null +++ b/nixos/doc/manual/configuration/ipv6-config.xml @@ -0,0 +1,19 @@ +<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-ipv6"> + +<title>IPv6 Configuration</title> + +<para>IPv6 is enabled by default. Stateless address autoconfiguration +is used to automatically assign IPv6 addresses to all interfaces. You +can disable IPv6 support globally by setting: + +<programlisting> +networking.enableIPv6 = false; +</programlisting> + +</para> + +</section> diff --git a/nixos/doc/manual/configuration/linux-kernel.xml b/nixos/doc/manual/configuration/linux-kernel.xml new file mode 100644 index 00000000000..8fe2f5255df --- /dev/null +++ b/nixos/doc/manual/configuration/linux-kernel.xml @@ -0,0 +1,69 @@ +<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="sec-kernel-config"> + +<title>Linux Kernel</title> + +<para>You can override the Linux kernel and associated packages using +the option <option>boot.kernelPackages</option>. For instance, this +selects the Linux 3.10 kernel: +<programlisting> +boot.kernelPackages = pkgs.linuxPackages_3_10; +</programlisting> +Note that this not only replaces the kernel, but also packages that +are specific to the kernel version, such as the NVIDIA video drivers. +This ensures that driver packages are consistent with the +kernel.</para> + +<para>The default Linux kernel configuration should be fine for most users. You can see the configuration of your current kernel with the following command: +<programlisting> +cat /proc/config.gz | gunzip +</programlisting> +If you want to change the kernel configuration, you can use the +<option>packageOverrides</option> feature (see <xref +linkend="sec-customising-packages" />). For instance, to enable +support for the kernel debugger KGDB: + +<programlisting> +nixpkgs.config.packageOverrides = pkgs: + { linux_3_4 = pkgs.linux_3_4.override { + extraConfig = + '' + KGDB y + ''; + }; + }; +</programlisting> + +<varname>extraConfig</varname> takes a list of Linux kernel +configuration options, one per line. The name of the option should +not include the prefix <literal>CONFIG_</literal>. The option value +is typically <literal>y</literal>, <literal>n</literal> or +<literal>m</literal> (to build something as a kernel module).</para> + +<para>Kernel modules for hardware devices are generally loaded +automatically by <command>udev</command>. You can force a module to +be loaded via <option>boot.kernelModules</option>, e.g. +<programlisting> +boot.kernelModules = [ "fuse" "kvm-intel" "coretemp" ]; +</programlisting> +If the module is required early during the boot (e.g. to mount the +root file system), you can use +<option>boot.initrd.extraKernelModules</option>: +<programlisting> +boot.initrd.extraKernelModules = [ "cifs" ]; +</programlisting> +This causes the specified modules and their dependencies to be added +to the initial ramdark.</para> + +<para>Kernel runtime parameters can be set through +<option>boot.kernel.sysctl</option>, e.g. +<programlisting> +boot.kernel.sysctl."net.ipv4.tcp_keepalive_time" = 120; +</programlisting> +sets the kernel’s TCP keepalive time to 120 seconds. To see the +available parameters, run <command>sysctl -a</command>.</para> + +</chapter> diff --git a/nixos/doc/manual/configuration/luks-file-systems.xml b/nixos/doc/manual/configuration/luks-file-systems.xml new file mode 100644 index 00000000000..45475dbcd44 --- /dev/null +++ b/nixos/doc/manual/configuration/luks-file-systems.xml @@ -0,0 +1,42 @@ +<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-luks-file-systems"> + +<title>LUKS-Encrypted File Systems</title> + +<para>NixOS supports file systems that are encrypted using +<emphasis>LUKS</emphasis> (Linux Unified Key Setup). For example, +here is how you create an encrypted Ext4 file system on the device +<filename>/dev/sda2</filename>: + +<screen> +$ cryptsetup luksFormat /dev/sda2 + +WARNING! +======== +This will overwrite data on /dev/sda2 irrevocably. + +Are you sure? (Type uppercase yes): YES +Enter LUKS passphrase: *** +Verify passphrase: *** + +$ cryptsetup luksOpen /dev/sda2 crypted +Enter passphrase for /dev/sda2: *** + +$ mkfs.ext4 /dev/mapper/crypted +</screen> + +To ensure that this file system is automatically mounted at boot time +as <filename>/</filename>, add the following to +<filename>configuration.nix</filename>: + +<programlisting> +boot.initrd.luks.devices = [ { device = "/dev/sda2"; name = "crypted"; } ]; +fileSystems."/".device = "/dev/mapper/crypted"; +</programlisting> + +</para> + +</section> diff --git a/nixos/doc/manual/configuration/modularity.xml b/nixos/doc/manual/configuration/modularity.xml new file mode 100644 index 00000000000..d95091bd162 --- /dev/null +++ b/nixos/doc/manual/configuration/modularity.xml @@ -0,0 +1,143 @@ +<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-modularity"> + +<title>Modularity</title> + +<para>The NixOS configuration mechanism is modular. If your +<filename>configuration.nix</filename> becomes too big, you can split +it into multiple files. Likewise, if you have multiple NixOS +configurations (e.g. for different computers) with some commonality, +you can move the common configuration into a shared file.</para> + +<para>Modules have exactly the same syntax as +<filename>configuration.nix</filename>. In fact, +<filename>configuration.nix</filename> is itself a module. You can +use other modules by including them from +<filename>configuration.nix</filename>, e.g.: + +<programlisting> +{ config, pkgs, ... }: + +{ imports = [ ./vpn.nix ./kde.nix ]; + services.httpd.enable = true; + environment.systemPackages = [ pkgs.emacs ]; + <replaceable>...</replaceable> +} +</programlisting> + +Here, we include two modules from the same directory, +<filename>vpn.nix</filename> and <filename>kde.nix</filename>. The +latter might look like this: + +<programlisting> +{ config, pkgs, ... }: + +{ services.xserver.enable = true; + services.xserver.displayManager.kdm.enable = true; + services.xserver.desktopManager.kde4.enable = true; + environment.systemPackages = [ pkgs.kde4.kscreensaver ]; +} +</programlisting> + +Note that both <filename>configuration.nix</filename> and +<filename>kde.nix</filename> define the option +<option>environment.systemPackages</option>. When multiple modules +define an option, NixOS will try to <emphasis>merge</emphasis> the +definitions. In the case of +<option>environment.systemPackages</option>, that’s easy: the lists of +packages can simply be concatenated. The value in +<filename>configuration.nix</filename> is merged last, so for +list-type options, it will appear at the end of the merged list. If +you want it to appear first, you can use <varname>mkBefore</varname>: + +<programlisting> +boot.kernelModules = mkBefore [ "kvm-intel" ]; +</programlisting> + +This causes the <literal>kvm-intel</literal> kernel module to be +loaded before any other kernel modules.</para> + +<para>For other types of options, a merge may not be possible. For +instance, if two modules define +<option>services.httpd.adminAddr</option>, +<command>nixos-rebuild</command> will give an error: + +<screen> +The unique option `services.httpd.adminAddr' is defined multiple times, in `/etc/nixos/httpd.nix' and `/etc/nixos/configuration.nix'. +</screen> + +When that happens, it’s possible to force one definition take +precedence over the others: + +<programlisting> +services.httpd.adminAddr = pkgs.lib.mkForce "bob@example.org"; +</programlisting> + +</para> + +<para>When using multiple modules, you may need to access +configuration values defined in other modules. This is what the +<varname>config</varname> function argument is for: it contains the +complete, merged system configuration. That is, +<varname>config</varname> is the result of combining the +configurations returned by every module<footnote><para>If you’re +wondering how it’s possible that the (indirect) +<emphasis>result</emphasis> of a function is passed as an +<emphasis>input</emphasis> to that same function: that’s because Nix +is a “lazy” language — it only computes values when they are needed. +This works as long as no individual configuration value depends on +itself.</para></footnote>. For example, here is a module that adds +some packages to <option>environment.systemPackages</option> only if +<option>services.xserver.enable</option> is set to +<literal>true</literal> somewhere else: + +<programlisting> +{ config, pkgs, ... }: + +{ environment.systemPackages = + if config.services.xserver.enable then + [ pkgs.firefox + pkgs.thunderbird + ] + else + [ ]; +} +</programlisting> + +</para> + +<para>With multiple modules, it may not be obvious what the final +value of a configuration option is. The command +<option>nixos-option</option> allows you to find out: + +<screen> +$ nixos-option services.xserver.enable +true + +$ nixos-option boot.kernelModules +[ "tun" "ipv6" "loop" <replaceable>...</replaceable> ] +</screen> + +Interactive exploration of the configuration is possible using +<command +xlink:href="https://github.com/edolstra/nix-repl">nix-repl</command>, +a read-eval-print loop for Nix expressions. It’s not installed by +default; run <literal>nix-env -i nix-repl</literal> to get it. A +typical use: + +<screen> +$ nix-repl '<nixos>' + +nix-repl> config.networking.hostName +"mandark" + +nix-repl> map (x: x.hostName) config.services.httpd.virtualHosts +[ "example.org" "example.gov" ] +</screen> + +</para> + +</section> diff --git a/nixos/doc/manual/configuration/network-manager.xml b/nixos/doc/manual/configuration/network-manager.xml new file mode 100644 index 00000000000..e65060021b4 --- /dev/null +++ b/nixos/doc/manual/configuration/network-manager.xml @@ -0,0 +1,27 @@ +<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-networkmanager"> + +<title>NetworkManager</title> + +<para>To facilitate network configuration, some desktop environments +use NetworkManager. You can enable NetworkManager by setting: + +<programlisting> +services.networkmanager.enable = true; +</programlisting> + +Some desktop managers (e.g., GNOME) enable NetworkManager +automatically for you.</para> + +<para>All users that should have permission to change network settings +must belong to the <code>networkmanager</code> group.</para> + +<note><para><code>services.networkmanager</code> and +<code>services.wireless</code> can not be enabled at the same time: +you can still connect to the wireless networks using +NetworkManager.</para></note> + +</section> diff --git a/nixos/doc/manual/configuration/networking.xml b/nixos/doc/manual/configuration/networking.xml new file mode 100644 index 00000000000..5f08bc1f127 --- /dev/null +++ b/nixos/doc/manual/configuration/networking.xml @@ -0,0 +1,22 @@ +<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="sec-networking"> + +<title>Networking</title> + +<para>This section describes how to configure networking components on +your NixOS machine.</para> + +<xi:include href="network-manager.xml" /> +<xi:include href="ssh.xml" /> +<xi:include href="ipv4-config.xml" /> +<xi:include href="ipv6-config.xml" /> +<xi:include href="firewall.xml" /> +<xi:include href="wireless.xml" /> +<xi:include href="ad-hoc-network-config.xml" /> + +<!-- TODO: OpenVPN, NAT --> + +</chapter> diff --git a/nixos/doc/manual/configuration/package-mgmt.xml b/nixos/doc/manual/configuration/package-mgmt.xml new file mode 100644 index 00000000000..73c1722da02 --- /dev/null +++ b/nixos/doc/manual/configuration/package-mgmt.xml @@ -0,0 +1,34 @@ +<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="sec-package-management"> + +<title>Package Management</title> + +<para>This section describes how to add additional packages to your +system. NixOS has two distinct styles of package management: + +<itemizedlist> + + <listitem><para><emphasis>Declarative</emphasis>, where you declare + what packages you want in your + <filename>configuration.nix</filename>. Every time you run + <command>nixos-rebuild</command>, NixOS will ensure that you get a + consistent set of binaries corresponding to your + specification.</para></listitem> + + <listitem><para><emphasis>Ad hoc</emphasis>, where you install, + upgrade and uninstall packages via the <command>nix-env</command> + command. This style allows mixing packages from different Nixpkgs + versions. It’s the only choice for non-root + users.</para></listitem> + +</itemizedlist> + +</para> + +<xi:include href="declarative-packages.xml" /> +<xi:include href="ad-hoc-packages.xml" /> + +</chapter> diff --git a/nixos/doc/manual/configuration/ssh.xml b/nixos/doc/manual/configuration/ssh.xml new file mode 100644 index 00000000000..7c928baaf89 --- /dev/null +++ b/nixos/doc/manual/configuration/ssh.xml @@ -0,0 +1,32 @@ +<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-ssh"> + +<title>Secure Shell Access</title> + +<para>Secure shell (SSH) access to your machine can be enabled by +setting: + +<programlisting> +services.openssh.enable = true; +</programlisting> + +By default, root logins using a password are disallowed. They can be +disabled entirely by setting +<literal>services.openssh.permitRootLogin</literal> to +<literal>"no"</literal>.</para> + +<para>You can declaratively specify authorised RSA/DSA public keys for +a user as follows: + +<!-- FIXME: this might not work if the user is unmanaged. --> +<programlisting> +users.extraUsers.alice.openssh.authorizedKeys.keys = + [ "ssh-dss AAAAB3NzaC1kc3MAAACBAPIkGWVEt4..." ]; +</programlisting> + +</para> + +</section> diff --git a/nixos/doc/manual/configuration/summary.xml b/nixos/doc/manual/configuration/summary.xml new file mode 100644 index 00000000000..9bb5e35e16b --- /dev/null +++ b/nixos/doc/manual/configuration/summary.xml @@ -0,0 +1,191 @@ +<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-nix-syntax-summary"> + +<title>Syntax Summary</title> + +<para>Below is a summary of the most important syntactic constructs in +the Nix expression language. It’s not complete. In particular, there +are many other built-in functions. See the <link +xlink:href="http://nixos.org/nix/manual/#chap-writing-nix-expressions">Nix +manual</link> for the rest.</para> + +<informaltable frame='none'> + <tgroup cols='2'> + <colspec colname='c1' rowsep='1' colsep='1' /> + <colspec colname='c2' rowsep='1' /> + <thead> + <row> + <entry>Example</entry> + <entry>Description</entry> + </row> + </thead> + <tbody> + + <row> + <entry namest="c1" nameend="c2"><emphasis>Basic values</emphasis></entry> + </row> + <row> + <entry><literal>"Hello world"</literal></entry> + <entry>A string</entry> + </row> + <row> + <entry><literal>"${pkgs.bash}/bin/sh"</literal></entry> + <entry>A string containing an expression (expands to <literal>"/nix/store/<replaceable>hash</replaceable>-bash-<replaceable>version</replaceable>/bin/sh"</literal>)</entry> + </row> + <row> + <entry><literal>true</literal>, <literal>false</literal></entry> + <entry>Booleans</entry> + </row> + <row> + <entry><literal>123</literal></entry> + <entry>An integer</entry> + </row> + <row> + <entry><literal>./foo.png</literal></entry> + <entry>A path (relative to the containing Nix expression)</entry> + </row> + + <row> + <entry namest="c1" nameend="c2"><emphasis>Compound values</emphasis></entry> + </row> + <row> + <entry><literal>{ x = 1; y = 2; }</literal></entry> + <entry>An set with attributes names <literal>x</literal> and <literal>y</literal></entry> + </row> + <row> + <entry><literal>{ foo.bar = 1; }</literal></entry> + <entry>A nested set, equivalent to <literal>{ foo = { bar = 1; }; }</literal></entry> + </row> + <row> + <entry><literal>rec { x = "bla"; y = x + "bar"; }</literal></entry> + <entry>A recursive set, equivalent to <literal>{ x = "foo"; y = "foobar"; }</literal></entry> + </row> + <row> + <entry><literal>[ "foo" "bar" ]</literal></entry> + <entry>A list with two elements</entry> + </row> + + <row> + <entry namest="c1" nameend="c2"><emphasis>Operators</emphasis></entry> + </row> + <row> + <entry><literal>"foo" + "bar"</literal></entry> + <entry>String concatenation</entry> + </row> + <row> + <entry><literal>1 + 2</literal></entry> + <entry>Integer addition</entry> + </row> + <row> + <entry><literal>"foo" == "f" + "oo"</literal></entry> + <entry>Equality test (evaluates to <literal>true</literal>)</entry> + </row> + <row> + <entry><literal>"foo" != "bar"</literal></entry> + <entry>Inequality test (evaluates to <literal>true</literal>)</entry> + </row> + <row> + <entry><literal>!true</literal></entry> + <entry>Boolean negation</entry> + </row> + <row> + <entry><literal>{ x = 1; y = 2; }.x</literal></entry> + <entry>Attribute selection (evaluates to <literal>1</literal>)</entry> + </row> + <row> + <entry><literal>{ x = 1; y = 2; }.z or 3</literal></entry> + <entry>Attribute selection with default (evaluates to <literal>3</literal>)</entry> + </row> + <row> + <entry><literal>{ x = 1; y = 2; } // { z = 3; }</literal></entry> + <entry>Merge two sets (attributes in the right-hand set taking precedence)</entry> + </row> + + <row> + <entry namest="c1" nameend="c2"><emphasis>Control structures</emphasis></entry> + </row> + <row> + <entry><literal>if 1 + 1 == 2 then "yes!" else "no!"</literal></entry> + <entry>Conditional expression</entry> + </row> + <row> + <entry><literal>assert 1 + 1 == 2; "yes!"</literal></entry> + <entry>Assertion check (evaluates to <literal>"yes!"</literal>)</entry> + </row> + <row> + <entry><literal>let x = "foo"; y = "bar"; in x + y</literal></entry> + <entry>Variable definition</entry> + </row> + <row> + <entry><literal>with pkgs.lib; head [ 1 2 3 ]</literal></entry> + <entry>Add all attributes from the given set to the scope + (evaluates to <literal>1</literal>)</entry> + </row> + + <row> + <entry namest="c1" nameend="c2"><emphasis>Functions (lambdas)</emphasis></entry> + </row> + <row> + <entry><literal>x: x + 1</literal></entry> + <entry>A function that expects an integer and returns it increased by 1</entry> + </row> + <row> + <entry><literal>(x: x + 1) 100</literal></entry> + <entry>A function call (evaluates to 101)</entry> + </row> + <row> + <entry><literal>let inc = x: x + 1; in inc (inc (inc 100))</literal></entry> + <entry>A function bound to a variable and subsequently called by name (evaluates to 103)</entry> + </row> + <row> + <entry><literal>{ x, y }: x + y</literal></entry> + <entry>A function that expects a set with required attributes + <literal>x</literal> and <literal>y</literal> and concatenates + them</entry> + </row> + <row> + <entry><literal>{ x, y ? "bar" }: x + y</literal></entry> + <entry>A function that expects a set with required attribute + <literal>x</literal> and optional <literal>y</literal>, using + <literal>"bar"</literal> as default value for + <literal>y</literal></entry> + </row> + <row> + <entry><literal>{ x, y, ... }: x + y</literal></entry> + <entry>A function that expects a set with required attributes + <literal>x</literal> and <literal>y</literal> and ignores any + other attributes</entry> + </row> + <row> + <entry><literal>{ x, y } @ args: x + y</literal></entry> + <entry>A function that expects a set with required attributes + <literal>x</literal> and <literal>y</literal>, and binds the + whole set to <literal>args</literal></entry> + </row> + + <row> + <entry namest="c1" nameend="c2"><emphasis>Built-in functions</emphasis></entry> + </row> + <row> + <entry><literal>import ./foo.nix</literal></entry> + <entry>Load and return Nix expression in given file</entry> + </row> + <row> + <entry><literal>map (x: x + x) [ 1 2 3 ]</literal></entry> + <entry>Apply a function to every element of a list (evaluates to <literal>[ 2 4 6 ]</literal>)</entry> + </row> + <!-- + <row> + <entry><literal>throw "Urgh"</literal></entry> + <entry>Raise an error condition</entry> + </row> + --> + + </tbody> + </tgroup> +</informaltable> + +</section> diff --git a/nixos/doc/manual/configuration/user-mgmt.xml b/nixos/doc/manual/configuration/user-mgmt.xml new file mode 100644 index 00000000000..40dc687d03b --- /dev/null +++ b/nixos/doc/manual/configuration/user-mgmt.xml @@ -0,0 +1,95 @@ +<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="sec-user-management"> + +<title>User Management</title> + +<para>NixOS supports both declarative and imperative styles of user +management. In the declarative style, users are specified in +<filename>configuration.nix</filename>. For instance, the following +states that a user account named <literal>alice</literal> shall exist: + +<programlisting> +users.extraUsers.alice = + { createHome = true; + home = "/home/alice"; + description = "Alice Foobar"; + extraGroups = [ "wheel" "networkmanager" ]; + useDefaultShell = true; + openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3Nza... alice@foobar" ]; + }; +</programlisting> + +Note that <literal>alice</literal> is a member of the +<literal>wheel</literal> and <literal>networkmanager</literal> groups, +which allows her to use <command>sudo</command> to execute commands as +<literal>root</literal> and to configure the network, respectively. +Also note the SSH public key that allows remote logins with the +corresponding private key. Users created in this way do not have a +password by default, so they cannot log in via mechanisms that require +a password. However, you can use the <command>passwd</command> program +to set a password, which is retained across invocations of +<command>nixos-rebuild</command>.</para> + +<para>If you set users.mutableUsers to false, then the contents of /etc/passwd +and /etc/group will be congruent to your NixOS configuration. For instance, +if you remove a user from users.extraUsers and run nixos-rebuild, the user +account will cease to exist. Also, imperative commands for managing users +and groups, such as useradd, are no longer available.</para> + +<para>A user ID (uid) is assigned automatically. You can also specify +a uid manually by adding + +<programlisting> + uid = 1000; +</programlisting> + +to the user specification.</para> + +<para>Groups can be specified similarly. The following states that a +group named <literal>students</literal> shall exist: + +<programlisting> +users.extraGroups.students.gid = 1000; +</programlisting> + +As with users, the group ID (gid) is optional and will be assigned +automatically if it’s missing.</para> + +<warning><para>Currently declarative user management is not perfect: +<command>nixos-rebuild</command> does not know how to realise certain +configuration changes. This includes removing a user or group, and +removing group membership from a user.</para></warning> + +<para>In the imperative style, users and groups are managed by +commands such as <command>useradd</command>, +<command>groupmod</command> and so on. For instance, to create a user +account named <literal>alice</literal>: + +<screen> +$ useradd -m alice</screen> + +The flag <option>-m</option> causes the creation of a home directory +for the new user, which is generally what you want. The user does not +have an initial password and therefore cannot log in. A password can +be set using the <command>passwd</command> utility: + +<screen> +$ passwd alice +Enter new UNIX password: *** +Retype new UNIX password: *** +</screen> + +A user can be deleted using <command>userdel</command>: + +<screen> +$ userdel -r alice</screen> + +The flag <option>-r</option> deletes the user’s home directory. +Accounts can be modified using <command>usermod</command>. Unix +groups can be managed using <command>groupadd</command>, +<command>groupmod</command> and <command>groupdel</command>.</para> + +</chapter> diff --git a/nixos/doc/manual/configuration/wireless.xml b/nixos/doc/manual/configuration/wireless.xml new file mode 100644 index 00000000000..373a9168cc8 --- /dev/null +++ b/nixos/doc/manual/configuration/wireless.xml @@ -0,0 +1,41 @@ +<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-wireless"> + +<title>Wireless Networks</title> + +<para>For a desktop installation using NetworkManager (e.g., GNOME), +you just have to make sure the user is in the +<code>networkmanager</code> group and you can skip the rest of this +section on wireless networks.</para> + +<para> +NixOS will start wpa_supplicant for you if you enable this setting: + +<programlisting> +networking.wireless.enable = true; +</programlisting> + +NixOS currently does not generate wpa_supplicant's +configuration file, <literal>/etc/wpa_supplicant.conf</literal>. You should edit this file +yourself to define wireless networks, WPA keys and so on (see +wpa_supplicant.conf(5)). +</para> + +<para> +If you are using WPA2 the <command>wpa_passphrase</command> tool might be useful +to generate the <literal>wpa_supplicant.conf</literal>. + +<screen> +$ wpa_passphrase ESSID PSK > /etc/wpa_supplicant.conf</screen> + +After you have edited the <literal>wpa_supplicant.conf</literal>, +you need to restart the wpa_supplicant service. + +<screen> +$ systemctl restart wpa_supplicant.service</screen> +</para> + +</section> diff --git a/nixos/doc/manual/configuration/x-windows.xml b/nixos/doc/manual/configuration/x-windows.xml new file mode 100644 index 00000000000..bc58bb1f066 --- /dev/null +++ b/nixos/doc/manual/configuration/x-windows.xml @@ -0,0 +1,94 @@ +<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="sec-x11"> + +<title>X Window System</title> + +<para>The X Window System (X11) provides the basis of NixOS’ graphical +user interface. It can be enabled as follows: +<programlisting> +services.xserver.enable = true; +</programlisting> +The X server will automatically detect and use the appropriate video +driver from a set of X.org drivers (such as <literal>vesa</literal> +and <literal>intel</literal>). You can also specify a driver +manually, e.g. +<programlisting> +services.xserver.videoDrivers = [ "r128" ]; +</programlisting> +to enable X.org’s <literal>xf86-video-r128</literal> driver.</para> + +<para>You also need to enable at least one desktop or window manager. +Otherwise, you can only log into a plain undecorated +<command>xterm</command> window. Thus you should pick one or more of +the following lines: +<programlisting> +services.xserver.desktopManager.kde4.enable = true; +services.xserver.desktopManager.xfce.enable = true; +services.xserver.windowManager.xmonad.enable = true; +services.xserver.windowManager.twm.enable = true; +services.xserver.windowManager.icewm.enable = true; +</programlisting> +</para> + +<para>NixOS’s default <emphasis>display manager</emphasis> (the +program that provides a graphical login prompt and manages the X +server) is SLiM. You can select KDE’s <command>kdm</command> instead: +<programlisting> +services.xserver.displayManager.kdm.enable = true; +</programlisting> +</para> + +<para>The X server is started automatically at boot time. If you +don’t want this to happen, you can set: +<programlisting> +services.xserver.autorun = false; +</programlisting> +The X server can then be started manually: +<screen> +$ systemctl start display-manager.service +</screen> +</para> + + +<simplesect><title>NVIDIA Graphics Cards</title> + +<para>NVIDIA provides a proprietary driver for its graphics cards that +has better 3D performance than the X.org drivers. It is not enabled +by default because it’s not free software. You can enable it as follows: +<programlisting> +services.xserver.videoDrivers = [ "nvidia" ]; +</programlisting> +You may need to reboot after enabling this driver to prevent a clash +with other kernel modules.</para> + +<para>On 64-bit systems, if you want full acceleration for 32-bit +programs such as Wine, you should also set the following: +<programlisting> +services.xserver.driSupport32Bit = true; +</programlisting> +</para> + +</simplesect> + + +<simplesect><title>Touchpads</title> + +<para>Support for Synaptics touchpads (found in many laptops such as +the Dell Latitude series) can be enabled as follows: +<programlisting> +services.xserver.synaptics.enable = true; +</programlisting> +The driver has many options (see <xref linkend="ch-options"/>). For +instance, the following enables two-finger scrolling: +<programlisting> +services.xserver.synaptics.twoFingerScroll = true; +</programlisting> +</para> + +</simplesect> + + +</chapter> diff --git a/nixos/doc/manual/containers.xml b/nixos/doc/manual/containers.xml deleted file mode 100644 index 2530d519521..00000000000 --- a/nixos/doc/manual/containers.xml +++ /dev/null @@ -1,242 +0,0 @@ -<chapter xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="ch-containers"> - -<title>Containers</title> - -<para>NixOS allows you to easily run other NixOS instances as -<emphasis>containers</emphasis>. Containers are a light-weight -approach to virtualisation that runs software in the container at the -same speed as in the host system. NixOS containers share the Nix store -of the host, making container creation very efficient.</para> - -<warning><para>Currently, NixOS containers are not perfectly isolated -from the host system. This means that a user with root access to the -container can do things that affect the host. So you should not give -container root access to untrusted users.</para></warning> - -<para>NixOS containers can be created in two ways: imperatively, using -the command <command>nixos-container</command>, and declaratively, by -specifying them in your <filename>configuration.nix</filename>. The -declarative approach implies that containers get upgraded along with -your host system when you run <command>nixos-rebuild</command>, which -is often not what you want. By contrast, in the imperative approach, -containers are configured and updated independently from the host -system.</para> - - -<section><title>Imperative container management</title> - -<para>We’ll cover imperative container management using -<command>nixos-container</command> first. You create a container with -identifier <literal>foo</literal> as follows: - -<screen> -$ nixos-container create foo -</screen> - -This creates the container’s root directory in -<filename>/var/lib/containers/foo</filename> and a small configuration -file in <filename>/etc/containers/foo.conf</filename>. It also builds -the container’s initial system configuration and stores it in -<filename>/nix/var/nix/profiles/per-container/foo/system</filename>. You -can modify the initial configuration of the container on the command -line. For instance, to create a container that has -<command>sshd</command> running, with the given public key for -<literal>root</literal>: - -<screen> -$ nixos-container create foo --config 'services.openssh.enable = true; \ - users.extraUsers.root.openssh.authorizedKeys.keys = ["ssh-dss AAAAB3N…"];' -</screen> - -</para> - -<para>Creating a container does not start it. To start the container, -run: - -<screen> -$ nixos-container start foo -</screen> - -This command will return as soon as the container has booted and has -reached <literal>multi-user.target</literal>. On the host, the -container runs within a systemd unit called -<literal>container@<replaceable>container-name</replaceable>.service</literal>. -Thus, if something went wrong, you can get status info using -<command>systemctl</command>: - -<screen> -$ systemctl status container@foo -</screen> - -</para> - -<para>If the container has started succesfully, you can log in as -root using the <command>root-login</command> operation: - -<screen> -$ nixos-container root-login foo -[root@foo:~]# -</screen> - -Note that only root on the host can do this (since there is no -authentication). You can also get a regular login prompt using the -<command>login</command> operation, which is available to all users on -the host: - -<screen> -$ nixos-container login foo -foo login: alice -Password: *** -</screen> - -With <command>nixos-container run</command>, you can execute arbitrary -commands in the container: - -<screen> -$ nixos-container run foo -- uname -a -Linux foo 3.4.82 #1-NixOS SMP Thu Mar 20 14:44:05 UTC 2014 x86_64 GNU/Linux -</screen> - -</para> - -<para>There are several ways to change the configuration of the -container. First, on the host, you can edit -<literal>/var/lib/container/<replaceable>name</replaceable>/etc/nixos/configuration.nix</literal>, -and run - -<screen> -$ nixos-container update foo -</screen> - -This will build and activate the new configuration. You can also -specify a new configuration on the command line: - -<screen> -$ nixos-container update foo --config 'services.httpd.enable = true; \ - services.httpd.adminAddr = "foo@example.org";' - -$ curl http://$(nixos-container show-ip foo)/ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">… -</screen> - -However, note that this will overwrite the container’s -<filename>/etc/nixos/configuration.nix</filename>.</para> - -<para>Alternatively, you can change the configuration from within the -container itself by running <command>nixos-rebuild switch</command> -inside the container. Note that the container by default does not have -a copy of the NixOS channel, so you should run <command>nix-channel ---update</command> first.</para> - -<para>Containers can be stopped and started using -<literal>nixos-container stop</literal> and <literal>nixos-container -start</literal>, respectively, or by using -<command>systemctl</command> on the container’s service unit. To -destroy a container, including its file system, do - -<screen> -$ nixos-container destroy foo -</screen> - -</para> - -</section> - - -<section><title>Declarative container specification</title> - -<para>You can also specify containers and their configuration in the -host’s <filename>configuration.nix</filename>. For example, the -following specifies that there shall be a container named -<literal>database</literal> running PostgreSQL: - -<programlisting> -containers.database = - { config = - { config, pkgs, ... }: - { services.postgresql.enable = true; - services.postgresql.package = pkgs.postgresql92; - }; - }; -</programlisting> - -If you run <literal>nixos-rebuild switch</literal>, the container will -be built and started. If the container was already running, it will be -updated in place, without rebooting.</para> - -<para>By default, declarative containers share the network namespace -of the host, meaning that they can listen on (privileged) -ports. However, they cannot change the network configuration. You can -give a container its own network as follows: - -<programlisting> -containers.database = - { privateNetwork = true; - hostAddress = "192.168.100.10"; - localAddress = "192.168.100.11"; - }; -</programlisting> - -This gives the container a private virtual Ethernet interface with IP -address <literal>192.168.100.11</literal>, which is hooked up to a -virtual Ethernet interface on the host with IP address -<literal>192.168.100.10</literal>. (See the next section for details -on container networking.)</para> - -<para>To disable the container, just remove it from -<filename>configuration.nix</filename> and run <literal>nixos-rebuild -switch</literal>. Note that this will not delete the root directory of -the container in <literal>/var/lib/containers</literal>.</para> - -</section> - - -<section><title>Networking</title> - -<para>When you create a container using <literal>nixos-container -create</literal>, it gets it own private IPv4 address in the range -<literal>10.233.0.0/16</literal>. You can get the container’s IPv4 -address as follows: - -<screen> -$ nixos-container show-ip foo -10.233.4.2 - -$ ping -c1 10.233.4.2 -64 bytes from 10.233.4.2: icmp_seq=1 ttl=64 time=0.106 ms -</screen> - -</para> - -<para>Networking is implemented using a pair of virtual Ethernet -devices. The network interface in the container is called -<literal>eth0</literal>, while the matching interface in the host is -called <literal>ve-<replaceable>container-name</replaceable></literal> -(e.g., <literal>ve-foo</literal>). The container has its own network -namespace and the <literal>CAP_NET_ADMIN</literal> capability, so it -can perform arbitrary network configuration such as setting up -firewall rules, without affecting or having access to the host’s -network.</para> - -<para>By default, containers cannot talk to the outside network. If -you want that, you should set up Network Address Translation (NAT) -rules on the host to rewrite container traffic to use your external -IP address. This can be accomplished using the following configuration -on the host: - -<programlisting> -networking.nat.enable = true; -networking.nat.internalInterfaces = ["ve-+"]; -networking.nat.externalInterface = "eth0"; -</programlisting> -where <literal>eth0</literal> should be replaced with the desired -external interface. Note that <literal>ve-+</literal> is a wildcard -that matches all container interfaces.</para> - -</section> - - -</chapter> - diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix index 55533a05b06..47e01437ccc 100644 --- a/nixos/doc/manual/default.nix +++ b/nixos/doc/manual/default.nix @@ -36,30 +36,29 @@ let -o $out ${./options-to-docbook.xsl} ${optionsXML} ''; + sources = sourceFilesBySuffices ./. [".xml"]; + + copySources = + '' + cp -prd $sources/* . # */ + chmod -R u+w . + cp ${../../modules/services/databases/postgresql.xml} configuration/postgresql.xml + ln -s ${optionsDocBook} options-db.xml + echo "${version}" > version + ''; + in rec { # Generate the NixOS manual. manual = stdenv.mkDerivation { name = "nixos-manual"; - sources = sourceFilesBySuffices ./. [".xml"]; + inherit sources; buildInputs = [ libxml2 libxslt ]; - xsltFlags = '' - --param section.autolabel 1 - --param section.label.includes.component.label 1 - --param html.stylesheet 'style.css' - --param xref.with.number.and.title 1 - --param toc.section.depth 3 - --param admon.style ''' - --param callout.graphics.extension '.gif' - ''; - buildCommand = '' - ln -s $sources/*.xml . # */ - ln -s ${optionsDocBook} options-db.xml - echo "${version}" > version + ${copySources} # Check the validity of the manual sources. xmllint --noout --nonet --xinclude --noxincludenode \ @@ -69,10 +68,20 @@ in rec { # Generate the HTML manual. dst=$out/share/doc/nixos mkdir -p $dst - xsltproc $xsltFlags --nonet --xinclude \ - --output $dst/manual.html \ - ${docbook5_xsl}/xml/xsl/docbook/xhtml/docbook.xsl \ - ./manual.xml + xsltproc \ + --param section.autolabel 1 \ + --param section.label.includes.component.label 1 \ + --stringparam html.stylesheet style.css \ + --param xref.with.number.and.title 1 \ + --param toc.section.depth 3 \ + --stringparam admon.style "" \ + --stringparam callout.graphics.extension .gif \ + --param chunk.section.depth 0 \ + --param chunk.first.sections 1 \ + --param use.id.as.filename 1 \ + --stringparam generate.toc "book toc chapter toc appendix toc" \ + --nonet --xinclude --output $dst/ \ + ${docbook5_xsl}/xml/xsl/docbook/xhtml/chunkfast.xsl ./manual.xml mkdir -p $dst/images/callouts cp ${docbook5_xsl}/xml/xsl/docbook/images/callouts/*.gif $dst/images/callouts/ @@ -90,7 +99,7 @@ in rec { manualPDF = stdenv.mkDerivation { name = "nixos-manual-pdf"; - sources = sourceFilesBySuffices ./. [".xml"]; + inherit sources; buildInputs = [ libxml2 libxslt dblatex tetex ]; @@ -98,9 +107,7 @@ in rec { # TeX needs a writable font cache. export VARTEXFONTS=$TMPDIR/texfonts - ln -s $sources/*.xml . # */ - ln -s ${optionsDocBook} options-db.xml - echo "${version}" > version + ${copySources} dst=$out/share/doc/nixos mkdir -p $dst @@ -117,13 +124,12 @@ in rec { manpages = stdenv.mkDerivation { name = "nixos-manpages"; - sources = sourceFilesBySuffices ./. [".xml"]; + inherit sources; buildInputs = [ libxml2 libxslt ]; buildCommand = '' - ln -s $sources/*.xml . # */ - ln -s ${optionsDocBook} options-db.xml + ${copySources} # Check the validity of the manual sources. xmllint --noout --nonet --xinclude --noxincludenode \ diff --git a/nixos/doc/manual/development.xml b/nixos/doc/manual/development.xml deleted file mode 100644 index 2f0c2a7aa8d..00000000000 --- a/nixos/doc/manual/development.xml +++ /dev/null @@ -1,1119 +0,0 @@ -<chapter xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="ch-development"> - -<title>Development</title> - -<para>This chapter describes how you can modify and extend -NixOS.</para> - - -<!--===============================================================--> - -<section xml:id="sec-getting-sources"> - -<title>Getting the sources</title> - -<para>By default, NixOS’s <command>nixos-rebuild</command> command -uses the NixOS and Nixpkgs sources provided by the -<literal>nixos-unstable</literal> channel (kept in -<filename>/nix/var/nix/profiles/per-user/root/channels/nixos</filename>). -To modify NixOS, however, you should check out the latest sources from -Git. This is done using the following command: - -<screen> -$ nixos-checkout <replaceable>/my/sources</replaceable> -</screen> - -or - -<screen> -$ mkdir -p <replaceable>/my/sources</replaceable> -$ cd <replaceable>/my/sources</replaceable> -$ nix-env -i git -$ git clone git://github.com/NixOS/nixpkgs.git -</screen> - -This will check out the latest NixOS sources to -<filename><replaceable>/my/sources</replaceable>/nixpkgs/nixos</filename> -and the Nixpkgs sources to -<filename><replaceable>/my/sources</replaceable>/nixpkgs</filename>. -(The NixOS source tree lives in a subdirectory of the Nixpkgs -repository.)</para> - -<para>It’s often inconvenient to develop directly on the master -branch, since if somebody has just committed (say) a change to GCC, -then the binary cache may not have caught up yet and you’ll have to -rebuild everything from source. So you may want to create a local -branch based on your current NixOS version: - -<screen> -$ nixos-version -14.04.273.ea1952b (Baboon) - -$ git checkout -b local ea1952b -</screen> - -Or, to base your local branch on the latest version available in the -NixOS channel: - -<screen> -$ curl -sI http://nixos.org/channels/nixos-unstable/ | grep Location -Location: http://releases.nixos.org/nixos/unstable/nixos-14.10pre43986.acaf4a6/ - -$ git checkout -b local acaf4a6 -</screen> - -You can then use <command>git rebase</command> to sync your local -branch with the upstream branch, and use <command>git -cherry-pick</command> to copy commits from your local branch to the -upstream branch.</para> - -<para>If you want to rebuild your system using your (modified) -sources, you need to tell <command>nixos-rebuild</command> about them -using the <option>-I</option> flag: - -<screen> -$ nixos-rebuild switch -I nixpkgs=<replaceable>/my/sources</replaceable>/nixpkgs -</screen> - -</para> - -<para>If you want <command>nix-env</command> to use the expressions in -<replaceable>/my/sources</replaceable>, use <command>nix-env -f -<replaceable>/my/sources</replaceable>/nixpkgs</command>, or change -the default by adding a symlink in -<filename>~/.nix-defexpr</filename>: - -<screen> -$ ln -s <replaceable>/my/sources</replaceable>/nixpkgs ~/.nix-defexpr/nixpkgs -</screen> - -You may want to delete the symlink -<filename>~/.nix-defexpr/channels_root</filename> to prevent root’s -NixOS channel from clashing with your own tree.</para> - -<!-- FIXME: not sure what this means. -<para>You should not pass the base directory -<filename><replaceable>/my/sources</replaceable></filename> -to <command>nix-env</command>, as it will break after interpreting expressions -in <filename>nixos/</filename> as packages.</para> ---> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-writing-modules"> - -<title>Writing NixOS modules</title> - -<para>NixOS has a modular system for declarative configuration. This -system combines multiple <emphasis>modules</emphasis> to produce the -full system configuration. One of the modules that constitute the -configuration is <filename>/etc/nixos/configuration.nix</filename>. -Most of the others live in the <link -xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/modules"><filename>nixos/modules</filename></link> -subdirectory of the Nixpkgs tree.</para> - -<para>Each NixOS module is a file that handles one logical aspect of -the configuration, such as a specific kind of hardware, a service, or -network settings. A module configuration does not have to handle -everything from scratch; it can use the functionality provided by -other modules for its implementation. Thus a module can -<emphasis>declare</emphasis> options that can be used by other -modules, and conversely can <emphasis>define</emphasis> options -provided by other modules in its own implementation. For example, the -module <link -xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/pam.nix"><filename>pam.nix</filename></link> -declares the option <option>security.pam.services</option> that allows -other modules (e.g. <link -xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/ssh/sshd.nix"><filename>sshd.nix</filename></link>) -to define PAM services; and it defines the option -<option>environment.etc</option> (declared by <link -xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/system/etc/etc.nix"><filename>etc.nix</filename></link>) -to cause files to be created in -<filename>/etc/pam.d</filename>.</para> - -<para xml:id="para-module-syn">In <xref -linkend="sec-configuration-syntax"/>, we saw the following structure -of NixOS modules: - -<programlisting> -{ config, pkgs, ... }: - -{ <replaceable>option definitions</replaceable> -} -</programlisting> - -This is actually an <emphasis>abbreviated</emphasis> form of module -that only defines options, but does not declare any. The structure of -full NixOS modules is shown in <xref linkend='ex-module-syntax' />.</para> - -<example xml:id='ex-module-syntax'><title>Structure of NixOS modules</title> -<programlisting> -{ config, pkgs, ... }: <co xml:id='module-syntax-1' /> - -{ - imports = - [ <replaceable>paths of other modules</replaceable> <co xml:id='module-syntax-2' /> - ]; - - options = { - <replaceable>option declarations</replaceable> <co xml:id='module-syntax-3' /> - }; - - config = { - <replaceable>option definitions</replaceable> <co xml:id='module-syntax-4' /> - }; -}</programlisting> -</example> - -<para>The meaning of each part is as follows. - -<calloutlist> - <callout arearefs='module-syntax-1'> - <para>This line makes the current Nix expression a function. The - variable <varname>pkgs</varname> contains Nixpkgs, while - <varname>config</varname> contains the full system configuration. - This line can be omitted if there is no reference to - <varname>pkgs</varname> and <varname>config</varname> inside the - module.</para> - </callout> - - <callout arearefs='module-syntax-2'> - <para>This list enumerates the paths to other NixOS modules that - should be included in the evaluation of the system configuration. - A default set of modules is defined in the file - <filename>modules/module-list.nix</filename>. These don't need to - be added in the import list.</para> - </callout> - - <callout arearefs='module-syntax-3'> - <para>The attribute <varname>options</varname> is a nested set of - <emphasis>option declarations</emphasis> (described below).</para> - </callout> - - <callout arearefs='module-syntax-4'> - <para>The attribute <varname>config</varname> is a nested set of - <emphasis>option definitions</emphasis> (also described - below).</para> - </callout> -</calloutlist> - -</para> - -<para><xref linkend='locate-example' /> shows a module that handles -the regular update of the “locate” database, an index of all files in -the file system. This module declares two options that can be defined -by other modules (typically the user’s -<filename>configuration.nix</filename>): -<option>services.locate.enable</option> (whether the database should -be updated) and <option>services.locate.period</option> (when the -update should be done). It implements its functionality by defining -two options declared by other modules: -<option>systemd.services</option> (the set of all systemd services) -and <option>services.cron.systemCronJobs</option> (the list of -commands to be executed periodically by <command>cron</command>).</para> - -<example xml:id='locate-example'><title>NixOS module for the “locate” service</title> -<programlisting> -{ config, lib, pkgs, ... }: - -with lib; - -let locatedb = "/var/cache/locatedb"; in - -{ - options = { - - services.locate = { - - enable = mkOption { - type = types.bool; - default = false; - description = '' - If enabled, NixOS will periodically update the database of - files used by the <command>locate</command> command. - ''; - }; - - period = mkOption { - type = types.str; - default = "15 02 * * *"; - description = '' - This option defines (in the format used by cron) when the - locate database is updated. The default is to update at - 02:15 at night every day. - ''; - }; - - }; - - }; - - config = { - - systemd.services.update-locatedb = - { description = "Update Locate Database"; - path = [ pkgs.su ]; - script = - '' - mkdir -m 0755 -p $(dirname ${locatedb}) - exec updatedb --localuser=nobody --output=${locatedb} --prunepaths='/tmp /var/tmp /media /run' - ''; - }; - - services.cron.systemCronJobs = optional config.services.locate.enable - "${config.services.locate.period} root ${config.systemd.package}/bin/systemctl start update-locatedb.service"; - - }; -}</programlisting> -</example> - -<section><title>Option declarations</title> - -<para>An option declaration specifies the name, type and description -of a NixOS configuration option. It is illegal to define an option -that hasn’t been declared in any module. A option declaration -generally looks like this: - -<programlisting> -options = { - <replaceable>name</replaceable> = mkOption { - type = <replaceable>type specification</replaceable>; - default = <replaceable>default value</replaceable>; - example = <replaceable>example value</replaceable>; - description = "<replaceable>Description for use in the NixOS manual.</replaceable>"; - }; -}; -</programlisting> - -</para> - -<para>The function <varname>mkOption</varname> accepts the following arguments. - -<variablelist> - - <varlistentry> - <term><varname>type</varname></term> - <listitem> - <para>The type of the option (see below). It may be omitted, - but that’s not advisable since it may lead to errors that are - hard to diagnose.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>default</varname></term> - <listitem> - <para>The default value used if no value is defined by any - module. A default is not required; in that case, if the option - value is ever used, an error will be thrown.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>example</varname></term> - <listitem> - <para>An example value that will be shown in the NixOS manual.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>description</varname></term> - <listitem> - <para>A textual description of the option, in DocBook format, - that will be included in the NixOS manual.</para> - </listitem> - </varlistentry> - -</variablelist> - -</para> - -<para>Here is a non-exhaustive list of option types: - -<variablelist> - - <varlistentry> - <term><varname>types.bool</varname></term> - <listitem> - <para>A Boolean.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>types.int</varname></term> - <listitem> - <para>An integer.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>types.str</varname></term> - <listitem> - <para>A string.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>types.lines</varname></term> - <listitem> - <para>A string. If there are multiple definitions, they are - concatenated, with newline characters in between.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>types.path</varname></term> - <listitem> - <para>A path, defined as anything that, when coerced to a - string, starts with a slash. This includes derivations.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>types.listOf</varname> <replaceable>t</replaceable></term> - <listitem> - <para>A list of elements of type <replaceable>t</replaceable> - (e.g., <literal>types.listOf types.str</literal> is a list of - strings). Multiple definitions are concatenated together.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>types.attrsOf</varname> <replaceable>t</replaceable></term> - <listitem> - <para>A set of elements of type <replaceable>t</replaceable> - (e.g., <literal>types.attrsOf types.int</literal> is a set of - name/value pairs, the values being integers).</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>types.nullOr</varname> <replaceable>t</replaceable></term> - <listitem> - <para>Either the value <literal>null</literal> or something of - type <replaceable>t</replaceable>.</para> - </listitem> - </varlistentry> - -</variablelist> - -You can also create new types using the function -<varname>mkOptionType</varname>. See -<filename>lib/types.nix</filename> in Nixpkgs for details.</para> - -</section> - - -<section><title>Option definitions</title> - -<para>Option definitions are generally straight-forward bindings of values to option names, like - -<programlisting> -config = { - services.httpd.enable = true; -}; -</programlisting> - -However, sometimes you need to wrap an option definition or set of -option definitions in a <emphasis>property</emphasis> to achieve -certain effects:</para> - -<simplesect><title>Delaying conditionals</title> - -<para>If a set of option definitions is conditional on the value of -another option, you may need to use <varname>mkIf</varname>. -Consider, for instance: - -<programlisting> -config = if config.services.httpd.enable then { - environment.systemPackages = [ <replaceable>...</replaceable> ]; - <replaceable>...</replaceable> -} else {}; -</programlisting> - -This definition will cause Nix to fail with an “infinite recursion” -error. Why? Because the value of -<option>config.services.httpd.enable</option> depends on the value -being constructed here. After all, you could also write the clearly -circular and contradictory: -<programlisting> -config = if config.services.httpd.enable then { - services.httpd.enable = false; -} else { - services.httpd.enable = true; -}; -</programlisting> - -The solution is to write: - -<programlisting> -config = mkIf config.services.httpd.enable { - environment.systemPackages = [ <replaceable>...</replaceable> ]; - <replaceable>...</replaceable> -}; -</programlisting> - -The special function <varname>mkIf</varname> causes the evaluation of -the conditional to be “pushed down” into the individual definitions, -as if you had written: - -<programlisting> -config = { - environment.systemPackages = if config.services.httpd.enable then [ <replaceable>...</replaceable> ] else []; - <replaceable>...</replaceable> -}; -</programlisting> - -</para> - -</simplesect> - -<simplesect><title>Setting priorities</title> - -<para>A module can override the definitions of an option in other -modules by setting a <emphasis>priority</emphasis>. All option -definitions that do not have the lowest priority value are discarded. -By default, option definitions have priority 1000. You can specify an -explicit priority by using <varname>mkOverride</varname>, e.g. - -<programlisting> -services.openssh.enable = mkOverride 10 false; -</programlisting> - -This definition causes all other definitions with priorities above 10 -to be discarded. The function <varname>mkForce</varname> is -equal to <varname>mkOverride 50</varname>.</para> - -</simplesect> - -<simplesect><title>Merging configurations</title> - -<para>In conjunction with <literal>mkIf</literal>, it is sometimes -useful for a module to return multiple sets of option definitions, to -be merged together as if they were declared in separate modules. This -can be done using <varname>mkMerge</varname>: - -<programlisting> -config = mkMerge - [ # Unconditional stuff. - { environment.systemPackages = [ <replaceable>...</replaceable> ]; - } - # Conditional stuff. - (mkIf config.services.bla.enable { - environment.systemPackages = [ <replaceable>...</replaceable> ]; - }) - ]; -</programlisting> - -</para> - -</simplesect> - -</section> - - -<section><title>Important options</title> - -<para>NixOS has many options, but some are of particular importance to -module writers.</para> - -<variablelist> - - <varlistentry> - <term><option>environment.etc</option></term> - <listitem> - <para>This set defines files in <filename>/etc</filename>. A - typical use is: -<programlisting> -environment.etc."os-release".text = - '' - NAME=NixOS - <replaceable>...</replaceable> - ''; -</programlisting> - which causes a file named <filename>/etc/os-release</filename> - to be created with the given contents.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><option>system.activationScripts</option></term> - <listitem> - <para>A set of shell script fragments that must be executed - whenever the configuration is activated (i.e., at boot time, or - after running <command>nixos-rebuild switch</command>). For instance, -<programlisting> -system.activationScripts.media = - '' - mkdir -m 0755 -p /media - ''; -</programlisting> - causes the directory <filename>/media</filename> to be created. - Activation scripts must be idempotent. They should not start - background processes such as daemons; use - <option>systemd.services</option> for that.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><option>systemd.services</option></term> - <listitem> - <para>This is the set of systemd services. Example: -<programlisting> -systemd.services.dhcpcd = - { description = "DHCP Client"; - wantedBy = [ "multi-user.target" ]; - after = [ "systemd-udev-settle.service" ]; - path = [ dhcpcd pkgs.nettools pkgs.openresolv ]; - serviceConfig = - { Type = "forking"; - PIDFile = "/run/dhcpcd.pid"; - ExecStart = "${dhcpcd}/sbin/dhcpcd --config ${dhcpcdConf}"; - Restart = "always"; - }; - }; -</programlisting> - which creates the systemd unit - <literal>dhcpcd.service</literal>. The option - <option>wantedBy</option> determined which other units pull this - one in; <literal>multi-user.target</literal> is the default - target of the system, so <literal>dhcpcd.service</literal> will - always be started. The option - <option>serviceConfig.ExecStart</option> provides the main - command for the service; it’s also possible to provide pre-start - actions, stop scripts, and so on.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><option>users.extraUsers</option></term> - <term><option>users.extraGroups</option></term> - <listitem> - <para>If your service requires special UIDs or GIDs, you can - define them with these options. See <xref - linkend="sec-user-management"/> for details.</para> - </listitem> - </varlistentry> - -</variablelist> - -</section> - - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-building-parts"> - -<title>Building specific parts of NixOS</title> - -<para>With the command <command>nix-build</command>, you can build -specific parts of your NixOS configuration. This is done as follows: - -<screen> -$ cd <replaceable>/path/to/nixpkgs/nixos</replaceable> -$ nix-build -A config.<replaceable>option</replaceable></screen> - -where <replaceable>option</replaceable> is a NixOS option with type -“derivation” (i.e. something that can be built). Attributes of -interest include: - -<variablelist> - - <varlistentry> - <term><varname>system.build.toplevel</varname></term> - <listitem> - <para>The top-level option that builds the entire NixOS system. - Everything else in your configuration is indirectly pulled in by - this option. This is what <command>nixos-rebuild</command> - builds and what <filename>/run/current-system</filename> points - to afterwards.</para> - - <para>A shortcut to build this is: - -<screen> -$ nix-build -A system</screen> - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>system.build.manual.manual</varname></term> - <listitem><para>The NixOS manual.</para></listitem> - </varlistentry> - - <varlistentry> - <term><varname>system.build.etc</varname></term> - <listitem><para>A tree of symlinks that form the static parts of - <filename>/etc</filename>.</para></listitem> - </varlistentry> - - <varlistentry> - <term><varname>system.build.initialRamdisk</varname></term> - <term><varname>system.build.kernel</varname></term> - <listitem> - <para>The initial ramdisk and kernel of the system. This allows - a quick way to test whether the kernel and the initial ramdisk - boot correctly, by using QEMU’s <option>-kernel</option> and - <option>-initrd</option> options: - -<screen> -$ nix-build -A config.system.build.initialRamdisk -o initrd -$ nix-build -A config.system.build.kernel -o kernel -$ qemu-system-x86_64 -kernel ./kernel/bzImage -initrd ./initrd/initrd -hda /dev/null -</screen> - - </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>system.build.nixos-rebuild</varname></term> - <term><varname>system.build.nixos-install</varname></term> - <term><varname>system.build.nixos-generate-config</varname></term> - <listitem> - <para>These build the corresponding NixOS commands.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><varname>systemd.units.<replaceable>unit-name</replaceable>.unit</varname></term> - <listitem> - <para>This builds the unit with the specified name. Note that - since unit names contain dots - (e.g. <literal>httpd.service</literal>), you need to put them - between quotes, like this: - -<screen> -$ nix-build -A 'config.systemd.units."httpd.service".unit' -</screen> - - You can also test individual units, without rebuilding the whole - system, by putting them in - <filename>/run/systemd/system</filename>: - -<screen> -$ cp $(nix-build -A 'config.systemd.units."httpd.service".unit')/httpd.service \ - /run/systemd/system/tmp-httpd.service -$ systemctl daemon-reload -$ systemctl start tmp-httpd.service -</screen> - - Note that the unit must not have the same name as any unit in - <filename>/etc/systemd/system</filename> since those take - precedence over <filename>/run/systemd/system</filename>. - That’s why the unit is installed as - <filename>tmp-httpd.service</filename> here.</para> - </listitem> - </varlistentry> - -</variablelist> - -</para> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-building-cd"> - -<title>Building your own NixOS CD</title> - -<para>Building a NixOS CD is as easy as configuring your own computer. The -idea is to use another module which will replace -your <filename>configuration.nix</filename> to configure the system that -would be installed on the CD.</para> - -<para>Default CD/DVD configurations are available -inside <filename>nixos/modules/installer/cd-dvd</filename>. To build them -you have to set <envar>NIXOS_CONFIG</envar> before -running <command>nix-build</command> to build the ISO. - -<screen> -$ nix-build -A config.system.build.isoImage -I nixos-config=modules/installer/cd-dvd/installation-cd-minimal.nix</screen> - -</para> - -<para>Before burning your CD/DVD, you can check the content of the image by mounting anywhere like -suggested by the following command: - -<screen> -$ mount -o loop -t iso9660 ./result/iso/cd.iso /mnt/iso</screen> - -</para> - -</section> - - -<!--===============================================================--> - -<section> - -<title>Testing the installer</title> - -<para>Building, burning, and booting from an installation CD is rather -tedious, so here is a quick way to see if the installer works -properly: - -<screen> -$ nix-build -A config.system.build.nixos-install -$ mount -t tmpfs none /mnt -$ ./result/bin/nixos-install</screen> - -To start a login shell in the new NixOS installation in -<filename>/mnt</filename>: - -<screen> -$ ./result/bin/nixos-install --chroot -</screen> - -</para> - -</section> - - - -<!--===============================================================--> - -<section xml:id="sec-nixos-tests"> - -<title>NixOS tests</title> - -<para>When you add some feature to NixOS, you should write a test for -it. NixOS tests are kept in the directory <filename -xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/tests">nixos/tests</filename>, -and are executed (using Nix) by a testing framework that automatically -starts one or more virtual machines containing the NixOS system(s) -required for the test.</para> - -<simplesect><title>Writing tests</title> - -<para>A NixOS test is a Nix expression that has the following structure: - -<programlisting> -import ./make-test.nix { - - # Either the configuration of a single machine: - machine = - { config, pkgs, ... }: - { <replaceable>configuration…</replaceable> - }; - - # Or a set of machines: - nodes = - { <replaceable>machine1</replaceable> = - { config, pkgs, ... }: { <replaceable>…</replaceable> }; - <replaceable>machine2</replaceable> = - { config, pkgs, ... }: { <replaceable>…</replaceable> }; - … - }; - - testScript = - '' - <replaceable>Perl code…</replaceable> - ''; -} -</programlisting> - -The attribute <literal>testScript</literal> is a bit of Perl code that -executes the test (described below). During the test, it will start -one or more virtual machines, the configuration of which is described -by the attribute <literal>machine</literal> (if you need only one -machine in your test) or by the attribute <literal>nodes</literal> (if -you need multiple machines). For instance, <filename -xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename> -only needs a single machine to test whether users can log in on the -virtual console, whether device ownership is correctly maintained when -switching between consoles, and so on. On the other hand, <filename -xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs.nix">nfs.nix</filename>, -which tests NFS client and server functionality in the Linux kernel -(including whether locks are maintained across server crashes), -requires three machines: a server and two clients.</para> - -<para>There are a few special NixOS configuration options for test -VMs: - -<!-- FIXME: would be nice to generate this automatically. --> - -<variablelist> - - <varlistentry> - <term><option>virtualisation.memorySize</option></term> - <listitem><para>The memory of the VM in - megabytes.</para></listitem> - </varlistentry> - - <varlistentry> - <term><option>virtualisation.vlans</option></term> - <listitem><para>The virtual networks to which the VM is - connected. See <filename - xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix">nat.nix</filename> - for an example.</para></listitem> - </varlistentry> - - <varlistentry> - <term><option>virtualisation.writableStore</option></term> - <listitem><para>By default, the Nix store in the VM is not - writable. If you enable this option, a writable union file system - is mounted on top of the Nix store to make it appear - writable. This is necessary for tests that run Nix operations that - modify the store.</para></listitem> - </varlistentry> - -</variablelist> - -For more options, see the module <filename -xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix">qemu-vm.nix</filename>.</para> - -<para>The test script is a sequence of Perl statements that perform -various actions, such as starting VMs, executing commands in the VMs, -and so on. Each virtual machine is represented as an object stored in -the variable <literal>$<replaceable>name</replaceable></literal>, -where <replaceable>name</replaceable> is the identifier of the machine -(which is just <literal>machine</literal> if you didn’t specify -multiple machines using the <literal>nodes</literal> attribute). For -instance, the following starts the machine, waits until it has -finished booting, then executes a command and checks that the output -is more-or-less correct: - -<programlisting> -$machine->start; -$machine->waitForUnit("default.target"); -$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> or <literal>succeed</literal>). If you -have multiple machines, you can speed up the test by starting them in -parallel: - -<programlisting> -startAll; -</programlisting> - -</para> - -<para>The following methods are available on machine objects: - -<variablelist> - - <varlistentry> - <term><methodname>start</methodname></term> - <listitem><para>Start the virtual machine. This method is - asynchronous — it does not wait for the machine to finish - booting.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>shutdown</methodname></term> - <listitem><para>Shut down the machine, waiting for the VM to - exit.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>crash</methodname></term> - <listitem><para>Simulate a sudden power failure, by telling the VM - to exit immediately.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>block</methodname></term> - <listitem><para>Simulate unplugging the Ethernet cable that - connects the machine to the other machines.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>unblock</methodname></term> - <listitem><para>Undo the effect of - <methodname>block</methodname>.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>screenshot</methodname></term> - <listitem><para>Take a picture of the display of the virtual - machine, in PNG format. The screenshot is linked from the HTML - log.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>sendMonitorCommand</methodname></term> - <listitem><para>Send a command to the QEMU monitor. This is rarely - used, but allows doing stuff such as attaching virtual USB disks - to a running machine.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>sendKeys</methodname></term> - <listitem><para>Simulate pressing keys on the virtual keyboard, - e.g., <literal>sendKeys("ctrl-alt-delete")</literal>.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>sendChars</methodname></term> - <listitem><para>Simulate typing a sequence of characters on the - virtual keyboard, e.g., <literal>sendKeys("foobar\n")</literal> - will type the string <literal>foobar</literal> followed by the - Enter key.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>execute</methodname></term> - <listitem><para>Execute a shell command, returning a list - <literal>(<replaceable>status</replaceable>, - <replaceable>stdout</replaceable>)</literal>.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>succeed</methodname></term> - <listitem><para>Execute a shell command, raising an exception if - the exit status is not zero, otherwise returning the standard - output.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>fail</methodname></term> - <listitem><para>Like <methodname>succeed</methodname>, but raising - an exception if the command returns a zero status.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>waitUntilSucceeds</methodname></term> - <listitem><para>Repeat a shell command with 1-second intervals - until it succeeds.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>waitUntilFails</methodname></term> - <listitem><para>Repeat a shell command with 1-second intervals - until it fails.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>waitForUnit</methodname></term> - <listitem><para>Wait until the specified systemd unit has reached - the “active” state.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>waitForFile</methodname></term> - <listitem><para>Wait until the specified file - exists.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>waitForOpenPort</methodname></term> - <listitem><para>Wait until a process is listening on the given TCP - port (on <literal>localhost</literal>, at least).</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>waitForClosedPort</methodname></term> - <listitem><para>Wait until nobody is listening on the given TCP - port.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>waitForX</methodname></term> - <listitem><para>Wait until the X11 server is accepting - connections.</para></listitem> - </varlistentry> - - <varlistentry> - <term><methodname>waitForWindow</methodname></term> - <listitem><para>Wait until an X11 window has appeared whose name - matches the given regular expression, e.g., - <literal>waitForWindow(qr/Terminal/)</literal>.</para></listitem> - </varlistentry> - -</variablelist> - -</para> - -</simplesect> - - -<simplesect><title>Running tests</title> - -<para>You can run tests using <command>nix-build</command>. For -example, to run the test <filename -xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename>, -you just do: - -<screen> -$ nix-build '<nixpkgs/nixos/tests/login.nix>' -</screen> - -or, if you don’t want to rely on <envar>NIX_PATH</envar>: - -<screen> -$ cd /my/nixpkgs/nixos/tests -$ nix-build login.nix -… -running the VM test script -machine: QEMU running (pid 8841) -… -6 out of 6 tests succeeded -</screen> - -After building/downloading all required dependencies, this will -perform a build that starts a QEMU/KVM virtual machine containing a -NixOS system. The virtual machine mounts the Nix store of the host; -this makes VM creation very fast, as no disk image needs to be -created. Afterwards, you can view a pretty-printed log of the test: - -<screen> -$ firefox result/log.html -</screen> - -</para> - -<para>It is also possible to run the test environment interactively, -allowing you to experiment with the VMs. For example: - -<screen> -$ nix-build 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>.</para> - -<para>Finally, the test itself can be run interactively. This is -particularly useful when developing or debugging a test: - -<screen> -$ nix-build tests/ -A nfs.driver -$ ./result/bin/nixos-test-driver -starting VDE switch for network 1 -> -</screen> - -You can then take any Perl statement, e.g. - -<screen> -> startAll -> $machine->succeed("touch /tmp/foo") -</screen> - -The function <command>testScript</command> executes the entire test -script and drops you back into the test driver command line upon its -completion. This allows you to inspect the state of the VMs after the -test (e.g. to debug the test script).</para> - -</simplesect> - -</section> - - -</chapter> diff --git a/nixos/doc/manual/development/building-nixos.xml b/nixos/doc/manual/development/building-nixos.xml new file mode 100644 index 00000000000..21c5bfe6a5b --- /dev/null +++ b/nixos/doc/manual/development/building-nixos.xml @@ -0,0 +1,32 @@ +<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="sec-building-cd"> + +<title>Building Your Own NixOS CD</title> + +<para>Building a NixOS CD is as easy as configuring your own computer. The +idea is to use another module which will replace +your <filename>configuration.nix</filename> to configure the system that +would be installed on the CD.</para> + +<para>Default CD/DVD configurations are available +inside <filename>nixos/modules/installer/cd-dvd</filename>. To build them +you have to set <envar>NIXOS_CONFIG</envar> before +running <command>nix-build</command> to build the ISO. + +<screen> +$ nix-build -A config.system.build.isoImage -I nixos-config=modules/installer/cd-dvd/installation-cd-minimal.nix</screen> + +</para> + +<para>Before burning your CD/DVD, you can check the content of the image by mounting anywhere like +suggested by the following command: + +<screen> +$ mount -o loop -t iso9660 ./result/iso/cd.iso /mnt/iso</screen> + +</para> + +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/development/building-parts.xml b/nixos/doc/manual/development/building-parts.xml new file mode 100644 index 00000000000..cb8dee039c8 --- /dev/null +++ b/nixos/doc/manual/development/building-parts.xml @@ -0,0 +1,113 @@ +<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="sec-building-parts"> + +<title>Building Specific Parts of NixOS</title> + +<para>With the command <command>nix-build</command>, you can build +specific parts of your NixOS configuration. This is done as follows: + +<screen> +$ cd <replaceable>/path/to/nixpkgs/nixos</replaceable> +$ nix-build -A config.<replaceable>option</replaceable></screen> + +where <replaceable>option</replaceable> is a NixOS option with type +“derivation” (i.e. something that can be built). Attributes of +interest include: + +<variablelist> + + <varlistentry> + <term><varname>system.build.toplevel</varname></term> + <listitem> + <para>The top-level option that builds the entire NixOS system. + Everything else in your configuration is indirectly pulled in by + this option. This is what <command>nixos-rebuild</command> + builds and what <filename>/run/current-system</filename> points + to afterwards.</para> + + <para>A shortcut to build this is: + +<screen> +$ nix-build -A system</screen> + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>system.build.manual.manual</varname></term> + <listitem><para>The NixOS manual.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>system.build.etc</varname></term> + <listitem><para>A tree of symlinks that form the static parts of + <filename>/etc</filename>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>system.build.initialRamdisk</varname></term> + <term><varname>system.build.kernel</varname></term> + <listitem> + <para>The initial ramdisk and kernel of the system. This allows + a quick way to test whether the kernel and the initial ramdisk + boot correctly, by using QEMU’s <option>-kernel</option> and + <option>-initrd</option> options: + +<screen> +$ nix-build -A config.system.build.initialRamdisk -o initrd +$ nix-build -A config.system.build.kernel -o kernel +$ qemu-system-x86_64 -kernel ./kernel/bzImage -initrd ./initrd/initrd -hda /dev/null +</screen> + + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>system.build.nixos-rebuild</varname></term> + <term><varname>system.build.nixos-install</varname></term> + <term><varname>system.build.nixos-generate-config</varname></term> + <listitem> + <para>These build the corresponding NixOS commands.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>systemd.units.<replaceable>unit-name</replaceable>.unit</varname></term> + <listitem> + <para>This builds the unit with the specified name. Note that + since unit names contain dots + (e.g. <literal>httpd.service</literal>), you need to put them + between quotes, like this: + +<screen> +$ nix-build -A 'config.systemd.units."httpd.service".unit' +</screen> + + You can also test individual units, without rebuilding the whole + system, by putting them in + <filename>/run/systemd/system</filename>: + +<screen> +$ cp $(nix-build -A 'config.systemd.units."httpd.service".unit')/httpd.service \ + /run/systemd/system/tmp-httpd.service +$ systemctl daemon-reload +$ systemctl start tmp-httpd.service +</screen> + + Note that the unit must not have the same name as any unit in + <filename>/etc/systemd/system</filename> since those take + precedence over <filename>/run/systemd/system</filename>. + That’s why the unit is installed as + <filename>tmp-httpd.service</filename> here.</para> + </listitem> + </varlistentry> + +</variablelist> + +</para> + +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/development/development.xml b/nixos/doc/manual/development/development.xml new file mode 100644 index 00000000000..747159c4427 --- /dev/null +++ b/nixos/doc/manual/development/development.xml @@ -0,0 +1,20 @@ +<part 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="ch-development"> + +<title>Development</title> + +<partintro> +<para>This chapter describes how you can modify and extend +NixOS.</para> +</partintro> + +<xi:include href="sources.xml" /> +<xi:include href="writing-modules.xml" /> +<xi:include href="building-parts.xml" /> +<xi:include href="building-nixos.xml" /> +<xi:include href="testing-installer.xml" /> + +</part> diff --git a/nixos/doc/manual/development/nixos-tests.xml b/nixos/doc/manual/development/nixos-tests.xml new file mode 100644 index 00000000000..a98da993330 --- /dev/null +++ b/nixos/doc/manual/development/nixos-tests.xml @@ -0,0 +1,19 @@ +<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="sec-nixos-tests"> + +<title>NixOS Tests</title> + +<para>When you add some feature to NixOS, you should write a test for +it. NixOS tests are kept in the directory <filename +xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/tests">nixos/tests</filename>, +and are executed (using Nix) by a testing framework that automatically +starts one or more virtual machines containing the NixOS system(s) +required for the test.</para> + +<xi:include href="writing-nixos-tests.xml" /> +<xi:include href="running-nixos-tests.xml" /> + +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/development/option-declarations.xml b/nixos/doc/manual/development/option-declarations.xml new file mode 100644 index 00000000000..6d93dc5c009 --- /dev/null +++ b/nixos/doc/manual/development/option-declarations.xml @@ -0,0 +1,141 @@ +<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-option-declarations"> + +<title>Option Declarations</title> + +<para>An option declaration specifies the name, type and description +of a NixOS configuration option. It is illegal to define an option +that hasn’t been declared in any module. A option declaration +generally looks like this: + +<programlisting> +options = { + <replaceable>name</replaceable> = mkOption { + type = <replaceable>type specification</replaceable>; + default = <replaceable>default value</replaceable>; + example = <replaceable>example value</replaceable>; + description = "<replaceable>Description for use in the NixOS manual.</replaceable>"; + }; +}; +</programlisting> + +</para> + +<para>The function <varname>mkOption</varname> accepts the following arguments. + +<variablelist> + + <varlistentry> + <term><varname>type</varname></term> + <listitem> + <para>The type of the option (see below). It may be omitted, + but that’s not advisable since it may lead to errors that are + hard to diagnose.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>default</varname></term> + <listitem> + <para>The default value used if no value is defined by any + module. A default is not required; in that case, if the option + value is ever used, an error will be thrown.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>example</varname></term> + <listitem> + <para>An example value that will be shown in the NixOS manual.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>description</varname></term> + <listitem> + <para>A textual description of the option, in DocBook format, + that will be included in the NixOS manual.</para> + </listitem> + </varlistentry> + +</variablelist> + +</para> + +<para>Here is a non-exhaustive list of option types: + +<variablelist> + + <varlistentry> + <term><varname>types.bool</varname></term> + <listitem> + <para>A Boolean.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>types.int</varname></term> + <listitem> + <para>An integer.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>types.str</varname></term> + <listitem> + <para>A string.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>types.lines</varname></term> + <listitem> + <para>A string. If there are multiple definitions, they are + concatenated, with newline characters in between.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>types.path</varname></term> + <listitem> + <para>A path, defined as anything that, when coerced to a + string, starts with a slash. This includes derivations.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>types.listOf</varname> <replaceable>t</replaceable></term> + <listitem> + <para>A list of elements of type <replaceable>t</replaceable> + (e.g., <literal>types.listOf types.str</literal> is a list of + strings). Multiple definitions are concatenated together.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>types.attrsOf</varname> <replaceable>t</replaceable></term> + <listitem> + <para>A set of elements of type <replaceable>t</replaceable> + (e.g., <literal>types.attrsOf types.int</literal> is a set of + name/value pairs, the values being integers).</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>types.nullOr</varname> <replaceable>t</replaceable></term> + <listitem> + <para>Either the value <literal>null</literal> or something of + type <replaceable>t</replaceable>.</para> + </listitem> + </varlistentry> + +</variablelist> + +You can also create new types using the function +<varname>mkOptionType</varname>. See +<filename>lib/types.nix</filename> in Nixpkgs for details.</para> + +</section> \ No newline at end of file diff --git a/nixos/doc/manual/development/option-def.xml b/nixos/doc/manual/development/option-def.xml new file mode 100644 index 00000000000..4e267ecfd1e --- /dev/null +++ b/nixos/doc/manual/development/option-def.xml @@ -0,0 +1,112 @@ +<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-option-definitions"> + +<title>Option Definitions</title> + +<para>Option definitions are generally straight-forward bindings of values to option names, like + +<programlisting> +config = { + services.httpd.enable = true; +}; +</programlisting> + +However, sometimes you need to wrap an option definition or set of +option definitions in a <emphasis>property</emphasis> to achieve +certain effects:</para> + +<simplesect><title>Delaying Conditionals</title> + +<para>If a set of option definitions is conditional on the value of +another option, you may need to use <varname>mkIf</varname>. +Consider, for instance: + +<programlisting> +config = if config.services.httpd.enable then { + environment.systemPackages = [ <replaceable>...</replaceable> ]; + <replaceable>...</replaceable> +} else {}; +</programlisting> + +This definition will cause Nix to fail with an “infinite recursion” +error. Why? Because the value of +<option>config.services.httpd.enable</option> depends on the value +being constructed here. After all, you could also write the clearly +circular and contradictory: +<programlisting> +config = if config.services.httpd.enable then { + services.httpd.enable = false; +} else { + services.httpd.enable = true; +}; +</programlisting> + +The solution is to write: + +<programlisting> +config = mkIf config.services.httpd.enable { + environment.systemPackages = [ <replaceable>...</replaceable> ]; + <replaceable>...</replaceable> +}; +</programlisting> + +The special function <varname>mkIf</varname> causes the evaluation of +the conditional to be “pushed down” into the individual definitions, +as if you had written: + +<programlisting> +config = { + environment.systemPackages = if config.services.httpd.enable then [ <replaceable>...</replaceable> ] else []; + <replaceable>...</replaceable> +}; +</programlisting> + +</para> + +</simplesect> + +<simplesect><title>Setting Priorities</title> + +<para>A module can override the definitions of an option in other +modules by setting a <emphasis>priority</emphasis>. All option +definitions that do not have the lowest priority value are discarded. +By default, option definitions have priority 1000. You can specify an +explicit priority by using <varname>mkOverride</varname>, e.g. + +<programlisting> +services.openssh.enable = mkOverride 10 false; +</programlisting> + +This definition causes all other definitions with priorities above 10 +to be discarded. The function <varname>mkForce</varname> is +equal to <varname>mkOverride 50</varname>.</para> + +</simplesect> + +<simplesect><title>Merging Configurations</title> + +<para>In conjunction with <literal>mkIf</literal>, it is sometimes +useful for a module to return multiple sets of option definitions, to +be merged together as if they were declared in separate modules. This +can be done using <varname>mkMerge</varname>: + +<programlisting> +config = mkMerge + [ # Unconditional stuff. + { environment.systemPackages = [ <replaceable>...</replaceable> ]; + } + # Conditional stuff. + (mkIf config.services.bla.enable { + environment.systemPackages = [ <replaceable>...</replaceable> ]; + }) + ]; +</programlisting> + +</para> + +</simplesect> + +</section> \ No newline at end of file diff --git a/nixos/doc/manual/development/running-nixos-tests.xml b/nixos/doc/manual/development/running-nixos-tests.xml new file mode 100644 index 00000000000..d9be761eb01 --- /dev/null +++ b/nixos/doc/manual/development/running-nixos-tests.xml @@ -0,0 +1,77 @@ +<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-running-nixos-tests"> + +<title>Running Tests</title> + +<para>You can run tests using <command>nix-build</command>. For +example, to run the test <filename +xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename>, +you just do: + +<screen> +$ nix-build '<nixpkgs/nixos/tests/login.nix>' +</screen> + +or, if you don’t want to rely on <envar>NIX_PATH</envar>: + +<screen> +$ cd /my/nixpkgs/nixos/tests +$ nix-build login.nix +… +running the VM test script +machine: QEMU running (pid 8841) +… +6 out of 6 tests succeeded +</screen> + +After building/downloading all required dependencies, this will +perform a build that starts a QEMU/KVM virtual machine containing a +NixOS system. The virtual machine mounts the Nix store of the host; +this makes VM creation very fast, as no disk image needs to be +created. Afterwards, you can view a pretty-printed log of the test: + +<screen> +$ firefox result/log.html +</screen> + +</para> + +<para>It is also possible to run the test environment interactively, +allowing you to experiment with the VMs. For example: + +<screen> +$ nix-build 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>.</para> + +<para>Finally, the test itself can be run interactively. This is +particularly useful when developing or debugging a test: + +<screen> +$ nix-build tests/ -A nfs.driver +$ ./result/bin/nixos-test-driver +starting VDE switch for network 1 +> +</screen> + +You can then take any Perl statement, e.g. + +<screen> +> startAll +> $machine->succeed("touch /tmp/foo") +</screen> + +The function <command>testScript</command> executes the entire test +script and drops you back into the test driver command line upon its +completion. This allows you to inspect the state of the VMs after the +test (e.g. to debug the test script).</para> + +</section> \ No newline at end of file diff --git a/nixos/doc/manual/development/sources.xml b/nixos/doc/manual/development/sources.xml new file mode 100644 index 00000000000..992a07af981 --- /dev/null +++ b/nixos/doc/manual/development/sources.xml @@ -0,0 +1,95 @@ +<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="sec-getting-sources"> + +<title>Getting the Sources</title> + +<para>By default, NixOS’s <command>nixos-rebuild</command> command +uses the NixOS and Nixpkgs sources provided by the +<literal>nixos-unstable</literal> channel (kept in +<filename>/nix/var/nix/profiles/per-user/root/channels/nixos</filename>). +To modify NixOS, however, you should check out the latest sources from +Git. This is done using the following command: + +<screen> +$ nixos-checkout <replaceable>/my/sources</replaceable> +</screen> + +or + +<screen> +$ mkdir -p <replaceable>/my/sources</replaceable> +$ cd <replaceable>/my/sources</replaceable> +$ nix-env -i git +$ git clone git://github.com/NixOS/nixpkgs.git +</screen> + +This will check out the latest NixOS sources to +<filename><replaceable>/my/sources</replaceable>/nixpkgs/nixos</filename> +and the Nixpkgs sources to +<filename><replaceable>/my/sources</replaceable>/nixpkgs</filename>. +(The NixOS source tree lives in a subdirectory of the Nixpkgs +repository.)</para> + +<para>It’s often inconvenient to develop directly on the master +branch, since if somebody has just committed (say) a change to GCC, +then the binary cache may not have caught up yet and you’ll have to +rebuild everything from source. So you may want to create a local +branch based on your current NixOS version: + +<screen> +$ nixos-version +14.04.273.ea1952b (Baboon) + +$ git checkout -b local ea1952b +</screen> + +Or, to base your local branch on the latest version available in the +NixOS channel: + +<screen> +$ curl -sI http://nixos.org/channels/nixos-unstable/ | grep Location +Location: http://releases.nixos.org/nixos/unstable/nixos-14.10pre43986.acaf4a6/ + +$ git checkout -b local acaf4a6 +</screen> + +You can then use <command>git rebase</command> to sync your local +branch with the upstream branch, and use <command>git +cherry-pick</command> to copy commits from your local branch to the +upstream branch.</para> + +<para>If you want to rebuild your system using your (modified) +sources, you need to tell <command>nixos-rebuild</command> about them +using the <option>-I</option> flag: + +<screen> +$ nixos-rebuild switch -I nixpkgs=<replaceable>/my/sources</replaceable>/nixpkgs +</screen> + +</para> + +<para>If you want <command>nix-env</command> to use the expressions in +<replaceable>/my/sources</replaceable>, use <command>nix-env -f +<replaceable>/my/sources</replaceable>/nixpkgs</command>, or change +the default by adding a symlink in +<filename>~/.nix-defexpr</filename>: + +<screen> +$ ln -s <replaceable>/my/sources</replaceable>/nixpkgs ~/.nix-defexpr/nixpkgs +</screen> + +You may want to delete the symlink +<filename>~/.nix-defexpr/channels_root</filename> to prevent root’s +NixOS channel from clashing with your own tree.</para> + +<!-- FIXME: not sure what this means. +<para>You should not pass the base directory +<filename><replaceable>/my/sources</replaceable></filename> +to <command>nix-env</command>, as it will break after interpreting expressions +in <filename>nixos/</filename> as packages.</para> +--> + +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/development/testing-installer.xml b/nixos/doc/manual/development/testing-installer.xml new file mode 100644 index 00000000000..87e40e32617 --- /dev/null +++ b/nixos/doc/manual/development/testing-installer.xml @@ -0,0 +1,27 @@ +<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="ch-testing-installer"> + +<title>Testing the Installer</title> + +<para>Building, burning, and booting from an installation CD is rather +tedious, so here is a quick way to see if the installer works +properly: + +<screen> +$ nix-build -A config.system.build.nixos-install +$ mount -t tmpfs none /mnt +$ ./result/bin/nixos-install</screen> + +To start a login shell in the new NixOS installation in +<filename>/mnt</filename>: + +<screen> +$ ./result/bin/nixos-install --chroot +</screen> + +</para> + +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/development/writing-modules.xml b/nixos/doc/manual/development/writing-modules.xml new file mode 100644 index 00000000000..9cf29e5dc57 --- /dev/null +++ b/nixos/doc/manual/development/writing-modules.xml @@ -0,0 +1,175 @@ +<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="sec-writing-modules"> + +<title>Writing NixOS Modules</title> + +<para>NixOS has a modular system for declarative configuration. This +system combines multiple <emphasis>modules</emphasis> to produce the +full system configuration. One of the modules that constitute the +configuration is <filename>/etc/nixos/configuration.nix</filename>. +Most of the others live in the <link +xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/modules"><filename>nixos/modules</filename></link> +subdirectory of the Nixpkgs tree.</para> + +<para>Each NixOS module is a file that handles one logical aspect of +the configuration, such as a specific kind of hardware, a service, or +network settings. A module configuration does not have to handle +everything from scratch; it can use the functionality provided by +other modules for its implementation. Thus a module can +<emphasis>declare</emphasis> options that can be used by other +modules, and conversely can <emphasis>define</emphasis> options +provided by other modules in its own implementation. For example, the +module <link +xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/pam.nix"><filename>pam.nix</filename></link> +declares the option <option>security.pam.services</option> that allows +other modules (e.g. <link +xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/ssh/sshd.nix"><filename>sshd.nix</filename></link>) +to define PAM services; and it defines the option +<option>environment.etc</option> (declared by <link +xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/system/etc/etc.nix"><filename>etc.nix</filename></link>) +to cause files to be created in +<filename>/etc/pam.d</filename>.</para> + +<para xml:id="para-module-syn">In <xref +linkend="sec-configuration-syntax"/>, we saw the following structure +of NixOS modules: + +<programlisting> +{ config, pkgs, ... }: + +{ <replaceable>option definitions</replaceable> +} +</programlisting> + +This is actually an <emphasis>abbreviated</emphasis> form of module +that only defines options, but does not declare any. The structure of +full NixOS modules is shown in <xref linkend='ex-module-syntax' />.</para> + +<example xml:id='ex-module-syntax'><title>Structure of NixOS Modules</title> +<programlisting> +{ config, pkgs, ... }: <co xml:id='module-syntax-1' /> + +{ + imports = + [ <replaceable>paths of other modules</replaceable> <co xml:id='module-syntax-2' /> + ]; + + options = { + <replaceable>option declarations</replaceable> <co xml:id='module-syntax-3' /> + }; + + config = { + <replaceable>option definitions</replaceable> <co xml:id='module-syntax-4' /> + }; +}</programlisting> +</example> + +<para>The meaning of each part is as follows. + +<calloutlist> + <callout arearefs='module-syntax-1'> + <para>This line makes the current Nix expression a function. The + variable <varname>pkgs</varname> contains Nixpkgs, while + <varname>config</varname> contains the full system configuration. + This line can be omitted if there is no reference to + <varname>pkgs</varname> and <varname>config</varname> inside the + module.</para> + </callout> + + <callout arearefs='module-syntax-2'> + <para>This list enumerates the paths to other NixOS modules that + should be included in the evaluation of the system configuration. + A default set of modules is defined in the file + <filename>modules/module-list.nix</filename>. These don't need to + be added in the import list.</para> + </callout> + + <callout arearefs='module-syntax-3'> + <para>The attribute <varname>options</varname> is a nested set of + <emphasis>option declarations</emphasis> (described below).</para> + </callout> + + <callout arearefs='module-syntax-4'> + <para>The attribute <varname>config</varname> is a nested set of + <emphasis>option definitions</emphasis> (also described + below).</para> + </callout> +</calloutlist> + +</para> + +<para><xref linkend='locate-example' /> shows a module that handles +the regular update of the “locate” database, an index of all files in +the file system. This module declares two options that can be defined +by other modules (typically the user’s +<filename>configuration.nix</filename>): +<option>services.locate.enable</option> (whether the database should +be updated) and <option>services.locate.period</option> (when the +update should be done). It implements its functionality by defining +two options declared by other modules: +<option>systemd.services</option> (the set of all systemd services) +and <option>services.cron.systemCronJobs</option> (the list of +commands to be executed periodically by <command>cron</command>).</para> + +<example xml:id='locate-example'><title>NixOS Module for the “locate” Service</title> +<programlisting> +{ config, lib, pkgs, ... }: + +with lib; + +let locatedb = "/var/cache/locatedb"; in + +{ + options = { + + services.locate = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + If enabled, NixOS will periodically update the database of + files used by the <command>locate</command> command. + ''; + }; + + period = mkOption { + type = types.str; + default = "15 02 * * *"; + description = '' + This option defines (in the format used by cron) when the + locate database is updated. The default is to update at + 02:15 at night every day. + ''; + }; + + }; + + }; + + config = { + + systemd.services.update-locatedb = + { description = "Update Locate Database"; + path = [ pkgs.su ]; + script = + '' + mkdir -m 0755 -p $(dirname ${locatedb}) + exec updatedb --localuser=nobody --output=${locatedb} --prunepaths='/tmp /var/tmp /media /run' + ''; + }; + + services.cron.systemCronJobs = optional config.services.locate.enable + "${config.services.locate.period} root ${config.systemd.package}/bin/systemctl start update-locatedb.service"; + + }; +}</programlisting> +</example> + +<xi:include href="option-declarations.xml" /> +<xi:include href="option-def.xml" /> + +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/development/writing-nixos-tests.xml b/nixos/doc/manual/development/writing-nixos-tests.xml new file mode 100644 index 00000000000..bbb655eed2a --- /dev/null +++ b/nixos/doc/manual/development/writing-nixos-tests.xml @@ -0,0 +1,251 @@ +<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-writing-nixos-tests"> + +<title>Writing Tests</title> + +<para>A NixOS test is a Nix expression that has the following structure: + +<programlisting> +import ./make-test.nix { + + # Either the configuration of a single machine: + machine = + { config, pkgs, ... }: + { <replaceable>configuration…</replaceable> + }; + + # Or a set of machines: + nodes = + { <replaceable>machine1</replaceable> = + { config, pkgs, ... }: { <replaceable>…</replaceable> }; + <replaceable>machine2</replaceable> = + { config, pkgs, ... }: { <replaceable>…</replaceable> }; + … + }; + + testScript = + '' + <replaceable>Perl code…</replaceable> + ''; +} +</programlisting> + +The attribute <literal>testScript</literal> is a bit of Perl code that +executes the test (described below). During the test, it will start +one or more virtual machines, the configuration of which is described +by the attribute <literal>machine</literal> (if you need only one +machine in your test) or by the attribute <literal>nodes</literal> (if +you need multiple machines). For instance, <filename +xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/login.nix">login.nix</filename> +only needs a single machine to test whether users can log in on the +virtual console, whether device ownership is correctly maintained when +switching between consoles, and so on. On the other hand, <filename +xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nfs.nix">nfs.nix</filename>, +which tests NFS client and server functionality in the Linux kernel +(including whether locks are maintained across server crashes), +requires three machines: a server and two clients.</para> + +<para>There are a few special NixOS configuration options for test +VMs: + +<!-- FIXME: would be nice to generate this automatically. --> + +<variablelist> + + <varlistentry> + <term><option>virtualisation.memorySize</option></term> + <listitem><para>The memory of the VM in + megabytes.</para></listitem> + </varlistentry> + + <varlistentry> + <term><option>virtualisation.vlans</option></term> + <listitem><para>The virtual networks to which the VM is + connected. See <filename + xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/tests/nat.nix">nat.nix</filename> + for an example.</para></listitem> + </varlistentry> + + <varlistentry> + <term><option>virtualisation.writableStore</option></term> + <listitem><para>By default, the Nix store in the VM is not + writable. If you enable this option, a writable union file system + is mounted on top of the Nix store to make it appear + writable. This is necessary for tests that run Nix operations that + modify the store.</para></listitem> + </varlistentry> + +</variablelist> + +For more options, see the module <filename +xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/qemu-vm.nix">qemu-vm.nix</filename>.</para> + +<para>The test script is a sequence of Perl statements that perform +various actions, such as starting VMs, executing commands in the VMs, +and so on. Each virtual machine is represented as an object stored in +the variable <literal>$<replaceable>name</replaceable></literal>, +where <replaceable>name</replaceable> is the identifier of the machine +(which is just <literal>machine</literal> if you didn’t specify +multiple machines using the <literal>nodes</literal> attribute). For +instance, the following starts the machine, waits until it has +finished booting, then executes a command and checks that the output +is more-or-less correct: + +<programlisting> +$machine->start; +$machine->waitForUnit("default.target"); +$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> or <literal>succeed</literal>). If you +have multiple machines, you can speed up the test by starting them in +parallel: + +<programlisting> +startAll; +</programlisting> + +</para> + +<para>The following methods are available on machine objects: + +<variablelist> + + <varlistentry> + <term><methodname>start</methodname></term> + <listitem><para>Start the virtual machine. This method is + asynchronous — it does not wait for the machine to finish + booting.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>shutdown</methodname></term> + <listitem><para>Shut down the machine, waiting for the VM to + exit.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>crash</methodname></term> + <listitem><para>Simulate a sudden power failure, by telling the VM + to exit immediately.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>block</methodname></term> + <listitem><para>Simulate unplugging the Ethernet cable that + connects the machine to the other machines.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>unblock</methodname></term> + <listitem><para>Undo the effect of + <methodname>block</methodname>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>screenshot</methodname></term> + <listitem><para>Take a picture of the display of the virtual + machine, in PNG format. The screenshot is linked from the HTML + log.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>sendMonitorCommand</methodname></term> + <listitem><para>Send a command to the QEMU monitor. This is rarely + used, but allows doing stuff such as attaching virtual USB disks + to a running machine.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>sendKeys</methodname></term> + <listitem><para>Simulate pressing keys on the virtual keyboard, + e.g., <literal>sendKeys("ctrl-alt-delete")</literal>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>sendChars</methodname></term> + <listitem><para>Simulate typing a sequence of characters on the + virtual keyboard, e.g., <literal>sendKeys("foobar\n")</literal> + will type the string <literal>foobar</literal> followed by the + Enter key.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>execute</methodname></term> + <listitem><para>Execute a shell command, returning a list + <literal>(<replaceable>status</replaceable>, + <replaceable>stdout</replaceable>)</literal>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>succeed</methodname></term> + <listitem><para>Execute a shell command, raising an exception if + the exit status is not zero, otherwise returning the standard + output.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>fail</methodname></term> + <listitem><para>Like <methodname>succeed</methodname>, but raising + an exception if the command returns a zero status.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>waitUntilSucceeds</methodname></term> + <listitem><para>Repeat a shell command with 1-second intervals + until it succeeds.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>waitUntilFails</methodname></term> + <listitem><para>Repeat a shell command with 1-second intervals + until it fails.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>waitForUnit</methodname></term> + <listitem><para>Wait until the specified systemd unit has reached + the “active” state.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>waitForFile</methodname></term> + <listitem><para>Wait until the specified file + exists.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>waitForOpenPort</methodname></term> + <listitem><para>Wait until a process is listening on the given TCP + port (on <literal>localhost</literal>, at least).</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>waitForClosedPort</methodname></term> + <listitem><para>Wait until nobody is listening on the given TCP + port.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>waitForX</methodname></term> + <listitem><para>Wait until the X11 server is accepting + connections.</para></listitem> + </varlistentry> + + <varlistentry> + <term><methodname>waitForWindow</methodname></term> + <listitem><para>Wait until an X11 window has appeared whose name + matches the given regular expression, e.g., + <literal>waitForWindow(qr/Terminal/)</literal>.</para></listitem> + </varlistentry> + +</variablelist> + +</para> + +</section> \ No newline at end of file diff --git a/nixos/doc/manual/installation.xml b/nixos/doc/manual/installation.xml deleted file mode 100644 index 4cbfcc229fa..00000000000 --- a/nixos/doc/manual/installation.xml +++ /dev/null @@ -1,570 +0,0 @@ -<chapter xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="ch-installation"> - -<title>Installing NixOS</title> - - -<!--===============================================================--> - -<section xml:id="sec-obtaining"> - -<title>Obtaining NixOS</title> - -<para>NixOS ISO images can be downloaded from the <link -xlink:href="http://nixos.org/nixos/download.html">NixOS -homepage</link>. These can be burned onto a CD. It is also possible -to copy them onto a USB stick and install NixOS from there. For -details, see the <link -xlink:href="https://nixos.org/wiki/Installing_NixOS_from_a_USB_stick">NixOS -Wiki</link>.</para> - -<para>As an alternative to installing NixOS yourself, you can get a -running NixOS system through several other means: - -<itemizedlist> - <listitem> - <para>Using virtual appliances in Open Virtualization Format (OVF) - that can be imported into VirtualBox. These are available from - the <link xlink:href="http://nixos.org/nixos/download.html">NixOS - homepage</link>.</para> - </listitem> - <listitem> - <para>Using AMIs for Amazon’s EC2. To find one for your region - and instance type, please refer to the <link - xlink:href="https://github.com/NixOS/nixops/blob/master/nix/ec2-amis.nix">list - of most recent AMIs</link>.</para> - </listitem> - <listitem> - <para>Using NixOps, the NixOS-based cloud deployment tool, which - allows you to provision VirtualBox and EC2 NixOS instances from - declarative specifications. Check out the <link - xlink:href="https://github.com/NixOS/nixops">NixOps - homepage</link> for details.</para> - </listitem> -</itemizedlist> - -</para> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-installation"> - -<title>Installation</title> - -<orderedlist> - - <listitem><para>Boot from the CD.</para></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 and brought up networking (check - <command>ifconfig</command>). Networking is necessary for the - installer, since it will download lots of stuff (such as source - tarballs or Nixpkgs channel binaries). It’s best if you have a DHCP - server on your network. Otherwise configure networking manually - using <command>ifconfig</command>.</para></listitem> - - <listitem><para>The NixOS manual is available on virtual console 8 - (press Alt+F8 to access).</para></listitem> - - <listitem><para>Login as <literal>root</literal> and the empty - password.</para></listitem> - - <listitem><para>If you downloaded the graphical ISO image, you can - run <command>start display-manager</command> to start KDE.</para></listitem> - - <listitem><para>The NixOS installer doesn’t do any partitioning or - formatting yet, so you need to that yourself. Use the following - commands: - - <itemizedlist> - - <listitem><para>For partitioning: - <command>fdisk</command>.</para></listitem> - - <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>, since this - makes the file system configuration independent from device - changes. For example: - -<screen> -$ mkfs.ext4 -L nixos /dev/sda1</screen> - - </para></listitem> - - <listitem><para>For creating swap partitions: - <command>mkswap</command>. Again it’s recommended to assign a - label to the swap partition: <option>-L - <replaceable>label</replaceable></option>.</para></listitem> - - <listitem><para>For creating LVM volumes, the LVM commands, e.g., - -<screen> -$ pvcreate /dev/sda1 /dev/sdb1 -$ vgcreate MyVolGroup /dev/sda1 /dev/sdb1 -$ lvcreate --size 2G --name bigdisk MyVolGroup -$ lvcreate --size 1G --name smalldisk MyVolGroup</screen> - - </para></listitem> - - <listitem><para>For creating software RAID devices, use - <command>mdadm</command>.</para></listitem> - - </itemizedlist> - - </para></listitem> - - <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><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> - - <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 - linkend="ex-config"/>.</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: - -<screen> -$ nano /mnt/etc/nixos/configuration.nix -</screen> - - The <command>vim</command> text editor is also available.</para> - - <para>You <emphasis>must</emphasis> set the option - <option>boot.loader.grub.device</option> to specify on which disk - the GRUB boot loader is to be installed. Without it, NixOS cannot - boot.</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><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.</para></note> - - <para>Examples of real-world NixOS configuration files can be - found at <link - xlink:href="https://nixos.org/repos/nix/configurations/trunk/"/>.</para> - - </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. - -<screen> -setting root password... -Enter new UNIX password: *** -Retype new UNIX password: *** -</screen> - - </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 <xref - linkend="sec-changing-config" />), a new item appears in the menu. - This allows you to easily roll back to another 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, - -<screen> -$ nix-env -qa \*</screen> - - 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" -/> 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> -$ mkfs.ext4 -L nixos /dev/sda1 -$ mkswap -L swap /dev/sda2 -$ swapon /dev/sda2 -$ mount /dev/disk/by-label/nixos /mnt -$ nixos-generate-config --root /mnt -$ nano /mnt/etc/nixos/configuration.nix -$ nixos-install -$ reboot</screen> -</example> - -<example xml:id='ex-config'><title>NixOS configuration</title> -<screen> -{ config, pkgs, ... }: - -{ - imports = - [ # Include the results of the hardware scan. - ./hardware-configuration.nix - ]; - - boot.loader.grub.device = "/dev/sda"; - - # Note: setting fileSystems is generally not - # necessary, since nixos-generate-config figures them out - # automatically in hardware-configuration.nix. - #fileSystems."/".device = "/dev/disk/by-label/nixos"; - - # Enable the OpenSSH server. - services.sshd.enable = true; -}</screen> -</example> - -<section xml:id="sec-uefi-installation"> - -<title>UEFI Installation</title> - -<para>NixOS can also be installed on UEFI systems. The procedure -is by and large the same as a BIOS installation, with the following -changes: - -<itemizedlist> - <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> - <listitem> - <para>Instead of <command>fdisk</command>, you should use - <command>gdisk</command> to partition your disks. You will need to - have a separate partition for <filename>/boot</filename> with - partition code EF00, and it should be formatted as a - <literal>vfat</literal> filesystem.</para> - </listitem> - <listitem> - <para>You must set <option>boot.loader.gummiboot.enable</option> to - <literal>true</literal>. <command>nixos-generate-config</command> - should do this automatically for new configurations when booted in - UEFI mode.</para> - </listitem> - <listitem> - <para>After having mounted your installation partition to - <code>/mnt</code>, you must mount the <code>boot</code> partition - to <code>/mnt/boot</code>.</para> - </listitem> - <listitem> - <para>You may want to look at the options starting with - <option>boot.loader.efi</option> and <option>boot.loader.gummiboot</option> - as well.</para> - </listitem> - <listitem> - <para>To see console messages during early boot, add <literal>"fbcon"</literal> - to your <option>boot.initrd.kernelModules</option>.</para> - </listitem> -</itemizedlist> -</para> - -</section> - -<section> - -<title xml:id="sec-booting-from-usb">Booting from a USB stick</title> - -<para>For systems without CD drive, the NixOS livecd can be booted from -a usb stick. For non-UEFI installations, -<link xlink:href="http://unetbootin.sourceforge.net/">unetbootin</link> -will work. For UEFI installations, you should 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/kernel-parameters.txt"> - the kernel documentation</link> for more details).</para> - </listitem> -</itemizedlist> -</para> -</section> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-changing-config"> - -<title>Changing the configuration</title> - -<para>The file <filename>/etc/nixos/configuration.nix</filename> -contains the current configuration of your machine. Whenever you’ve -changed something to that file, you should do - -<screen> -$ nixos-rebuild switch</screen> - -to build the new configuration, make it the default configuration for -booting, and try to realise the configuration in the running system -(e.g., by restarting system services).</para> - -<warning><para>These commands must be executed as root, so you should -either run them from a root shell or by prefixing them with -<literal>sudo -i</literal>.</para></warning> - -<para>You can also do - -<screen> -$ nixos-rebuild test</screen> - -to build the configuration and switch the running system to it, but -without making it the boot default. So if (say) the configuration -locks up your machine, you can just reboot to get back to a working -configuration.</para> - -<para>There is also - -<screen> -$ nixos-rebuild boot</screen> - -to build the configuration and make it the boot default, but not -switch to it now (so it will only take effect after the next -reboot).</para> - -<para>You can make your configuration show up in a different submenu -of the GRUB 2 boot screen by giving it a different <emphasis>profile -name</emphasis>, e.g. - -<screen> -$ nixos-rebuild switch -p test </screen> - -which causes the new configuration (and previous ones created using -<literal>-p test</literal>) to show up in the GRUB submenu “NixOS - -Profile 'test'”. This can be useful to separate test configurations -from “stable” configurations.</para> - -<para>Finally, you can do - -<screen> -$ nixos-rebuild build</screen> - -to build the configuration but nothing more. This is useful to see -whether everything compiles cleanly.</para> - -<para>If you have a machine that supports hardware virtualisation, you -can also test the new configuration in a sandbox by building and -running a QEMU <emphasis>virtual machine</emphasis> that contains the -desired configuration. Just do - -<screen> -$ nixos-rebuild build-vm -$ ./result/bin/run-*-vm -</screen> - -The VM does not have any data from your host system, so your existing -user accounts and home directories will not be available. You can -forward ports on the host to the guest. For instance, the following -will forward host port 2222 to guest port 22 (SSH): - -<screen> -$ QEMU_NET_OPTS="hostfwd=tcp::2222-:22" ./result/bin/run-*-vm -</screen> - -allowing you to log in via SSH (assuming you have set the appropriate -passwords or SSH authorized keys): - -<screen> -$ ssh -p 2222 localhost -</screen> - -</para> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-upgrading"> - -<title>Upgrading NixOS</title> - -<para>The best way to keep your NixOS installation up to date is to -use one of the NixOS <emphasis>channels</emphasis>. A channel is a -Nix mechanism for distributing Nix expressions and associated -binaries. The NixOS channels are updated automatically from NixOS’s -Git repository after certain tests have passed and all packages have -been built. These channels are: - -<itemizedlist> - <listitem> - <para>Stable channels, such as <literal - xlink:href="http://nixos.org/channels/nixos-14.04">nixos-14.04</literal>. - These only get conservative bug fixes and package upgrades. For - instance, a channel update may cause the Linux kernel on your - system to be upgraded from 3.4.66 to 3.4.67 (a minor bug fix), but - not from 3.4.<replaceable>x</replaceable> to - 3.11.<replaceable>x</replaceable> (a major change that has the - potential to break things). Stable channels are generally - maintained until the next stable branch is created.</para> - </listitem> - <listitem> - <para>The unstable channel, <literal - xlink:href="http://nixos.org/channels/nixos-unstable">nixos-unstable</literal>. - This corresponds to NixOS’s main development branch, and may thus - see radical changes between channel updates. It’s not recommended - for production systems.</para> - </listitem> -</itemizedlist> - -To see what channels are available, go to <link -xlink:href="http://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.)</para> - -<para>When you first install NixOS, you’re automatically subscribed to -the NixOS channel that corresponds to your installation source. For -instance, if you installed from a 14.04 ISO, you will be subscribed to -the <literal>nixos-14.04</literal> channel. To see which NixOS -channel you’re subscribed to, run the following as root: - -<screen> -$ nix-channel --list | grep nixos -nixos https://nixos.org/channels/nixos-unstable -</screen> - -To switch to a different NixOS channel, do - -<screen> -$ nix-channel --add http://nixos.org/channels/<replaceable>channel-name</replaceable> nixos -</screen> - -(Be sure to include the <literal>nixos</literal> parameter at the -end.) For instance, to use the NixOS 14.04 stable channel: - -<screen> -$ nix-channel --add http://nixos.org/channels/nixos-14.04 nixos -</screen> - -But it you want to live on the bleeding edge: - -<screen> -$ nix-channel --add http://nixos.org/channels/nixos-unstable nixos -</screen> - -</para> - -<para>You can then upgrade NixOS to the latest version in your chosen -channel by running - -<screen> -$ nixos-rebuild switch --upgrade -</screen> - -which is equivalent to the more verbose <literal>nix-channel --update -nixos; nixos-rebuild switch</literal>.</para> - -<warning><para>It is generally safe to switch back and forth between -channels. The only exception is that a newer NixOS may also have a -newer Nix version, which may involve an upgrade of Nix’s database -schema. This cannot be undone easily, so in that case you will not be -able to go back to your original channel.</para></warning> - -</section> - -</chapter> diff --git a/nixos/doc/manual/installation/changing-config.xml b/nixos/doc/manual/installation/changing-config.xml new file mode 100644 index 00000000000..aa31742434e --- /dev/null +++ b/nixos/doc/manual/installation/changing-config.xml @@ -0,0 +1,90 @@ +<chapter xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="5.0" + xml:id="sec-changing-config"> + +<title>Changing the Configuration</title> + +<para>The file <filename>/etc/nixos/configuration.nix</filename> +contains the current configuration of your machine. Whenever you’ve +changed something to that file, you should do + +<screen> +$ nixos-rebuild switch</screen> + +to build the new configuration, make it the default configuration for +booting, and try to realise the configuration in the running system +(e.g., by restarting system services).</para> + +<warning><para>These commands must be executed as root, so you should +either run them from a root shell or by prefixing them with +<literal>sudo -i</literal>.</para></warning> + +<para>You can also do + +<screen> +$ nixos-rebuild test</screen> + +to build the configuration and switch the running system to it, but +without making it the boot default. So if (say) the configuration +locks up your machine, you can just reboot to get back to a working +configuration.</para> + +<para>There is also + +<screen> +$ nixos-rebuild boot</screen> + +to build the configuration and make it the boot default, but not +switch to it now (so it will only take effect after the next +reboot).</para> + +<para>You can make your configuration show up in a different submenu +of the GRUB 2 boot screen by giving it a different <emphasis>profile +name</emphasis>, e.g. + +<screen> +$ nixos-rebuild switch -p test </screen> + +which causes the new configuration (and previous ones created using +<literal>-p test</literal>) to show up in the GRUB submenu “NixOS - +Profile 'test'”. This can be useful to separate test configurations +from “stable” configurations.</para> + +<para>Finally, you can do + +<screen> +$ nixos-rebuild build</screen> + +to build the configuration but nothing more. This is useful to see +whether everything compiles cleanly.</para> + +<para>If you have a machine that supports hardware virtualisation, you +can also test the new configuration in a sandbox by building and +running a QEMU <emphasis>virtual machine</emphasis> that contains the +desired configuration. Just do + +<screen> +$ nixos-rebuild build-vm +$ ./result/bin/run-*-vm +</screen> + +The VM does not have any data from your host system, so your existing +user accounts and home directories will not be available. You can +forward ports on the host to the guest. For instance, the following +will forward host port 2222 to guest port 22 (SSH): + +<screen> +$ QEMU_NET_OPTS="hostfwd=tcp::2222-:22" ./result/bin/run-*-vm +</screen> + +allowing you to log in via SSH (assuming you have set the appropriate +passwords or SSH authorized keys): + +<screen> +$ ssh -p 2222 localhost +</screen> + +</para> + +</chapter> diff --git a/nixos/doc/manual/installation/installation.xml b/nixos/doc/manual/installation/installation.xml new file mode 100644 index 00000000000..ee61bedc418 --- /dev/null +++ b/nixos/doc/manual/installation/installation.xml @@ -0,0 +1,21 @@ +<part 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="ch-installation"> + +<title>Installation</title> + +<partintro> + +<para>This section describes how to obtain, install, and configure +NixOS for first-time use.</para> + +</partintro> + +<xi:include href="obtaining.xml" /> +<xi:include href="installing.xml" /> +<xi:include href="changing-config.xml" /> +<xi:include href="upgrading.xml" /> + +</part> diff --git a/nixos/doc/manual/installation/installing-uefi.xml b/nixos/doc/manual/installation/installing-uefi.xml new file mode 100644 index 00000000000..dbd5606c4a5 --- /dev/null +++ b/nixos/doc/manual/installation/installing-uefi.xml @@ -0,0 +1,51 @@ +<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-uefi-installation"> + +<title>UEFI Installation</title> + +<para>NixOS can also be installed on UEFI systems. The procedure +is by and large the same as a BIOS installation, with the following +changes: + +<itemizedlist> + <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> + <listitem> + <para>Instead of <command>fdisk</command>, you should use + <command>gdisk</command> to partition your disks. You will need to + have a separate partition for <filename>/boot</filename> with + partition code EF00, and it should be formatted as a + <literal>vfat</literal> filesystem.</para> + </listitem> + <listitem> + <para>You must set <option>boot.loader.gummiboot.enable</option> to + <literal>true</literal>. <command>nixos-generate-config</command> + should do this automatically for new configurations when booted in + UEFI mode.</para> + </listitem> + <listitem> + <para>After having mounted your installation partition to + <code>/mnt</code>, you must mount the <code>boot</code> partition + to <code>/mnt/boot</code>.</para> + </listitem> + <listitem> + <para>You may want to look at the options starting with + <option>boot.loader.efi</option> and <option>boot.loader.gummiboot</option> + as well.</para> + </listitem> + <listitem> + <para>To see console messages during early boot, add <literal>"fbcon"</literal> + to your <option>boot.initrd.kernelModules</option>.</para> + </listitem> +</itemizedlist> +</para> + +</section> diff --git a/nixos/doc/manual/installation/installing-usb.xml b/nixos/doc/manual/installation/installing-usb.xml new file mode 100644 index 00000000000..97e3d2eaa1c --- /dev/null +++ b/nixos/doc/manual/installation/installing-usb.xml @@ -0,0 +1,30 @@ +<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-booting-from-usb"> + +<title>Booting from a USB Drive</title> + +<para>For systems without CD drive, the NixOS livecd can be booted from +a usb stick. For non-UEFI installations, +<link xlink:href="http://unetbootin.sourceforge.net/">unetbootin</link> +will work. For UEFI installations, you should 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/kernel-parameters.txt"> + the kernel documentation</link> for more details).</para> + </listitem> +</itemizedlist> +</para> + +</section> diff --git a/nixos/doc/manual/installation/installing.xml b/nixos/doc/manual/installation/installing.xml new file mode 100644 index 00000000000..b140c56fbee --- /dev/null +++ b/nixos/doc/manual/installation/installing.xml @@ -0,0 +1,264 @@ +<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="sec-installation"> + +<title>Installing NixOS</title> + +<orderedlist> + + <listitem><para>Boot from the CD.</para></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 and brought up networking (check + <command>ifconfig</command>). Networking is necessary for the + installer, since it will download lots of stuff (such as source + tarballs or Nixpkgs channel binaries). It’s best if you have a DHCP + server on your network. Otherwise configure networking manually + using <command>ifconfig</command>.</para></listitem> + + <listitem><para>The NixOS manual is available on virtual console 8 + (press Alt+F8 to access).</para></listitem> + + <listitem><para>Login as <literal>root</literal> and the empty + password.</para></listitem> + + <listitem><para>If you downloaded the graphical ISO image, you can + run <command>start display-manager</command> to start KDE.</para></listitem> + + <listitem><para>The NixOS installer doesn’t do any partitioning or + formatting yet, so you need to that yourself. Use the following + commands: + + <itemizedlist> + + <listitem><para>For partitioning: + <command>fdisk</command>.</para></listitem> + + <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>, since this + makes the file system configuration independent from device + changes. For example: + +<screen> +$ mkfs.ext4 -L nixos /dev/sda1</screen> + + </para></listitem> + + <listitem><para>For creating swap partitions: + <command>mkswap</command>. Again it’s recommended to assign a + label to the swap partition: <option>-L + <replaceable>label</replaceable></option>.</para></listitem> + + <listitem><para>For creating LVM volumes, the LVM commands, e.g., + +<screen> +$ pvcreate /dev/sda1 /dev/sdb1 +$ vgcreate MyVolGroup /dev/sda1 /dev/sdb1 +$ lvcreate --size 2G --name bigdisk MyVolGroup +$ lvcreate --size 1G --name smalldisk MyVolGroup</screen> + + </para></listitem> + + <listitem><para>For creating software RAID devices, use + <command>mdadm</command>.</para></listitem> + + </itemizedlist> + + </para></listitem> + + <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><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> + + <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 + linkend="ex-config"/>.</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: + +<screen> +$ nano /mnt/etc/nixos/configuration.nix +</screen> + + The <command>vim</command> text editor is also available.</para> + + <para>You <emphasis>must</emphasis> set the option + <option>boot.loader.grub.device</option> to specify on which disk + the GRUB boot loader is to be installed. Without it, NixOS cannot + boot.</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><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.</para></note> + + <para>Examples of real-world NixOS configuration files can be + found at <link + xlink:href="https://nixos.org/repos/nix/configurations/trunk/"/>.</para> + + </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. + +<screen> +setting root password... +Enter new UNIX password: *** +Retype new UNIX password: *** +</screen> + + </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 linkend="sec-changing-config">Changing + Configuration</link> ), a new item appears in the menu. This allows you to + easily roll back to another 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, + +<screen> +$ nix-env -qa \*</screen> + + 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" +/> 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> +$ mkfs.ext4 -L nixos /dev/sda1 +$ mkswap -L swap /dev/sda2 +$ swapon /dev/sda2 +$ mount /dev/disk/by-label/nixos /mnt +$ nixos-generate-config --root /mnt +$ nano /mnt/etc/nixos/configuration.nix +$ nixos-install +$ reboot</screen> +</example> + +<example xml:id='ex-config'><title>NixOS Configuration</title> +<screen> +{ config, pkgs, ... }: + +{ + imports = + [ # Include the results of the hardware scan. + ./hardware-configuration.nix + ]; + + boot.loader.grub.device = "/dev/sda"; + + # Note: setting fileSystems is generally not + # necessary, since nixos-generate-config figures them out + # automatically in hardware-configuration.nix. + #fileSystems."/".device = "/dev/disk/by-label/nixos"; + + # Enable the OpenSSH server. + services.sshd.enable = true; +}</screen> +</example> + +<xi:include href="installing-uefi.xml" /> +<xi:include href="installing-usb.xml" /> + +</chapter> diff --git a/nixos/doc/manual/installation/obtaining.xml b/nixos/doc/manual/installation/obtaining.xml new file mode 100644 index 00000000000..ceeeb5c0ac0 --- /dev/null +++ b/nixos/doc/manual/installation/obtaining.xml @@ -0,0 +1,44 @@ +<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="sec-obtaining"> + +<title>Obtaining NixOS</title> + +<para>NixOS ISO images can be downloaded from the <link +xlink:href="http://nixos.org/nixos/download.html">NixOS +homepage</link>. These can be burned onto a CD. It is also possible +to copy them onto a USB stick and install NixOS from there. For +details, see the <link +xlink:href="https://nixos.org/wiki/Installing_NixOS_from_a_USB_stick">NixOS +Wiki</link>.</para> + +<para>As an alternative to installing NixOS yourself, you can get a +running NixOS system through several other means: + +<itemizedlist> + <listitem> + <para>Using virtual appliances in Open Virtualization Format (OVF) + that can be imported into VirtualBox. These are available from + the <link xlink:href="http://nixos.org/nixos/download.html">NixOS + homepage</link>.</para> + </listitem> + <listitem> + <para>Using AMIs for Amazon’s EC2. To find one for your region + and instance type, please refer to the <link + xlink:href="https://github.com/NixOS/nixops/blob/master/nix/ec2-amis.nix">list + of most recent AMIs</link>.</para> + </listitem> + <listitem> + <para>Using NixOps, the NixOS-based cloud deployment tool, which + allows you to provision VirtualBox and EC2 NixOS instances from + declarative specifications. Check out the <link + xlink:href="https://github.com/NixOS/nixops">NixOps + homepage</link> for details.</para> + </listitem> +</itemizedlist> + +</para> + +</chapter> diff --git a/nixos/doc/manual/installation/upgrading.xml b/nixos/doc/manual/installation/upgrading.xml new file mode 100644 index 00000000000..ed71a7e23a3 --- /dev/null +++ b/nixos/doc/manual/installation/upgrading.xml @@ -0,0 +1,90 @@ +<chapter xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="5.0" + xml:id="sec-upgrading"> + +<title>Upgrading NixOS</title> + +<para>The best way to keep your NixOS installation up to date is to +use one of the NixOS <emphasis>channels</emphasis>. A channel is a +Nix mechanism for distributing Nix expressions and associated +binaries. The NixOS channels are updated automatically from NixOS’s +Git repository after certain tests have passed and all packages have +been built. These channels are: + +<itemizedlist> + <listitem> + <para>Stable channels, such as <literal + xlink:href="http://nixos.org/channels/nixos-14.04">nixos-14.04</literal>. + These only get conservative bug fixes and package upgrades. For + instance, a channel update may cause the Linux kernel on your + system to be upgraded from 3.4.66 to 3.4.67 (a minor bug fix), but + not from 3.4.<replaceable>x</replaceable> to + 3.11.<replaceable>x</replaceable> (a major change that has the + potential to break things). Stable channels are generally + maintained until the next stable branch is created.</para> + </listitem> + <listitem> + <para>The unstable channel, <literal + xlink:href="http://nixos.org/channels/nixos-unstable">nixos-unstable</literal>. + This corresponds to NixOS’s main development branch, and may thus + see radical changes between channel updates. It’s not recommended + for production systems.</para> + </listitem> +</itemizedlist> + +To see what channels are available, go to <link +xlink:href="http://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.)</para> + +<para>When you first install NixOS, you’re automatically subscribed to +the NixOS channel that corresponds to your installation source. For +instance, if you installed from a 14.04 ISO, you will be subscribed to +the <literal>nixos-14.04</literal> channel. To see which NixOS +channel you’re subscribed to, run the following as root: + +<screen> +$ nix-channel --list | grep nixos +nixos https://nixos.org/channels/nixos-unstable +</screen> + +To switch to a different NixOS channel, do + +<screen> +$ nix-channel --add http://nixos.org/channels/<replaceable>channel-name</replaceable> nixos +</screen> + +(Be sure to include the <literal>nixos</literal> parameter at the +end.) For instance, to use the NixOS 14.04 stable channel: + +<screen> +$ nix-channel --add http://nixos.org/channels/nixos-14.04 nixos +</screen> + +But it you want to live on the bleeding edge: + +<screen> +$ nix-channel --add http://nixos.org/channels/nixos-unstable nixos +</screen> + +</para> + +<para>You can then upgrade NixOS to the latest version in your chosen +channel by running + +<screen> +$ nixos-rebuild switch --upgrade +</screen> + +which is equivalent to the more verbose <literal>nix-channel --update +nixos; nixos-rebuild switch</literal>.</para> + +<warning><para>It is generally safe to switch back and forth between +channels. The only exception is that a newer NixOS may also have a +newer Nix version, which may involve an upgrade of Nix’s database +schema. This cannot be undone easily, so in that case you will not be +able to go back to your original channel.</para></warning> + +</chapter> diff --git a/nixos/doc/manual/man-nixos-option.xml b/nixos/doc/manual/man-nixos-option.xml index 7952847d4db..554b2969180 100644 --- a/nixos/doc/manual/man-nixos-option.xml +++ b/nixos/doc/manual/man-nixos-option.xml @@ -17,11 +17,6 @@ <refsynopsisdiv> <cmdsynopsis> <command>nixos-option</command> - <group choice="opt"> - <option>-v</option> - <option>-d</option> - <option>-l</option> - </group> <arg choice='plain'><replaceable>option.name</replaceable></arg> </cmdsynopsis> </refsynopsisdiv> @@ -31,50 +26,13 @@ <para>This command evaluates the configuration specified in <filename>/etc/nixos/configuration.nix</filename> and returns the properties -of the option name given as argument. By default, it returns the value of -the option.</para> +of the option name given as argument.</para> <para>When the option name is not an option, the command prints the list of attributes contained in the attribute set.</para> </refsection> -<refsection><title>Options</title> - -<para>This command accepts the following options:</para> - -<variablelist> - - <varlistentry> - <term><option>--value</option>, <option>-v</option></term> - <listitem> - <para>Returns the value of the option. This is the default operation - if no other options are defined.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><option>--description</option>, <option>-d</option></term> - <listitem> - <para>Return the default value, the example and the description of the - option when available.</para> - </listitem> - </varlistentry> - - <varlistentry> - <term><option>--lookup</option>, <option>-l</option></term> - <listitem> - <para>Return the locations where the option is declared and where it - is defined. This is extremely useful to find sources of errors in - your configuration.</para> - </listitem> - </varlistentry> - -</variablelist> - -</refsection> - - <refsection><title>Environment</title> <variablelist> @@ -103,27 +61,21 @@ grub initScript $ nixos-option boot.loader.grub.enable -true</screen></para> +Value: +true -<para>Prints option information: +Default: +true -<screen>$ nixos-option -d networking.hostName -Default: "nixos" Description: -The name of the machine. Leave it empty if you want to obtain -it from a DHCP server (if using DHCP).</screen></para> - -<para>Find the locations which are declaring and defining an option: +Whether to enable the GNU GRUB boot loader. -<screen>$ nixos-option -l hardware.firmware Declared by: - /mnt/data/nix-sources/nixos/modules/services/hardware/udev.nix + "/path/to/nixpkgs/nixos/modules/system/boot/loader/grub/grub.nix" Defined by: - /path/to/nixpkgs/nixos/modules/system/boot/kernel.nix - /path/to/nixpkgs/nixos/modules/hardware/network/rt73.nix - /path/to/nixpkgs/nixos/modules/hardware/network/intel-3945abg.nix - /path/to/nixpkgs/nixos/modules/hardware/network/intel-2200bg.nix</screen></para> + "/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/nixos/modules/system/boot/loader/grub/grub.nix" +</screen></para> </refsection> diff --git a/nixos/doc/manual/manual.xml b/nixos/doc/manual/manual.xml index f51a04cdf25..a3ad76209ac 100644 --- a/nixos/doc/manual/manual.xml +++ b/nixos/doc/manual/manual.xml @@ -1,15 +1,14 @@ <book xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:xi="http://www.w3.org/2001/XInclude"> - + xmlns:xi="http://www.w3.org/2001/XInclude" + version="5.0" + xml:id="NixOSManual"> + <info> - <title>NixOS Manual</title> <subtitle>Version <xi:include href="version" parse="text" /></subtitle> - </info> - <preface> <title>Preface</title> @@ -29,19 +28,14 @@ </preface> - - <xi:include href="installation.xml" /> - <xi:include href="configuration.xml" /> - <xi:include href="running.xml" /> + <xi:include href="installation/installation.xml" /> + <xi:include href="configuration/configuration.xml" /> + <xi:include href="administration/running.xml" /> <!-- <xi:include href="userconfiguration.xml" /> --> - <xi:include href="troubleshooting.xml" /> - <xi:include href="containers.xml" /> - <xi:include href="development.xml" /> - - <xi:include href="release-notes.xml" /> + <xi:include href="release-notes/release-notes.xml" /> <appendix xml:id="ch-options"> - <title>Configuration options</title> + <title>Configuration Options</title> <xi:include href="options-db.xml" /> </appendix> diff --git a/nixos/doc/manual/release-notes/release-notes.xml b/nixos/doc/manual/release-notes/release-notes.xml new file mode 100644 index 00000000000..fb82d5adcef --- /dev/null +++ b/nixos/doc/manual/release-notes/release-notes.xml @@ -0,0 +1,17 @@ +<part 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="ch-release-notes"> + +<title>Release Notes</title> + +<partintro> +<para>This section lists the release notes for each stable version of NixOS.</para> +</partintro> + +<xi:include href="rl-1410.xml" /> +<xi:include href="rl-1404.xml" /> +<xi:include href="rl-1310.xml" /> + +</part> diff --git a/nixos/doc/manual/release-notes/rl-1310.xml b/nixos/doc/manual/release-notes/rl-1310.xml new file mode 100644 index 00000000000..234fb5a643f --- /dev/null +++ b/nixos/doc/manual/release-notes/rl-1310.xml @@ -0,0 +1,11 @@ +<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="sec-release-13.10"> + +<title>Release 13.10 (“Aardvark”, 2013/10/31)</title> + +<para>This is the first stable release branch of NixOS.</para> + +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/release-notes.xml b/nixos/doc/manual/release-notes/rl-1404.xml index 52e88bb4c86..74af1ed1274 100644 --- a/nixos/doc/manual/release-notes.xml +++ b/nixos/doc/manual/release-notes/rl-1404.xml @@ -1,34 +1,8 @@ -<appendix xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="ch-release-notes"> - -<title>Release notes</title> - -<!--==================================================================--> - -<section xml:id="sec-release-14.10"> - -<title>Release 14.10 (“Caterpillar”, 2014/10/??)</title> - -<para>When upgrading from a previous release, please be aware of the -following incompatible changes: - -<itemizedlist> - - <listitem><para>The host side of a container virtual Ethernet pair - is now called <literal>ve-<replaceable>container-name</replaceable></literal> - rather than <literal>c-<replaceable>container-name</replaceable></literal>.</para></listitem> - -</itemizedlist> - -</para> - -</section> - - -<!--==================================================================--> - -<section xml:id="sec-release-14.04"> +<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="sec-release-14.04"> <title>Release 14.04 (“Baboon”, 2014/04/30)</title> @@ -183,16 +157,4 @@ networking.firewall.enable = false; </para> -</section> - -<!--==================================================================--> - -<section xml:id="sec-release-13.10"> - -<title>Release 13.10 (“Aardvark”, 2013/10/31)</title> - -<para>This is the first stable release branch of NixOS.</para> - -</section> - -</appendix> +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/release-notes/rl-1410.xml b/nixos/doc/manual/release-notes/rl-1410.xml new file mode 100644 index 00000000000..09da15ce236 --- /dev/null +++ b/nixos/doc/manual/release-notes/rl-1410.xml @@ -0,0 +1,22 @@ +<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="sec-release-14.10"> + +<title>Release 14.10 (“Caterpillar”, 2014/10/??)</title> + +<para>When upgrading from a previous release, please be aware of the +following incompatible changes: + +<itemizedlist> + + <listitem><para>The host side of a container virtual Ethernet pair + is now called <literal>ve-<replaceable>container-name</replaceable></literal> + rather than <literal>c-<replaceable>container-name</replaceable></literal>.</para></listitem> + +</itemizedlist> + +</para> + +</chapter> \ No newline at end of file diff --git a/nixos/doc/manual/running.xml b/nixos/doc/manual/running.xml deleted file mode 100644 index e1a358df2aa..00000000000 --- a/nixos/doc/manual/running.xml +++ /dev/null @@ -1,369 +0,0 @@ -<chapter xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="ch-running"> - -<title>Running NixOS</title> - -<para>This chapter describes various aspects of managing a running -NixOS system, such as how to use the <command>systemd</command> -service manager.</para> - - -<!--===============================================================--> - -<section xml:id="sec-systemctl"><title>Service management</title> - -<para>In NixOS, all system services are started and monitored using -the systemd program. Systemd is the “init” process of the system -(i.e. PID 1), the parent of all other processes. It manages a set of -so-called “units”, which can be things like system services -(programs), but also mount points, swap files, devices, targets -(groups of units) and more. Units can have complex dependencies; for -instance, one unit can require that another unit must be successfully -started before the first unit can be started. When the system boots, -it starts a unit named <literal>default.target</literal>; the -dependencies of this unit cause all system services to be started, -file systems to be mounted, swap files to be activated, and so -on.</para> - -<para>The command <command>systemctl</command> is the main way to -interact with <command>systemd</command>. Without any arguments, it -shows the status of active units: - -<screen> -$ systemctl --.mount loaded active mounted / -swapfile.swap loaded active active /swapfile -sshd.service loaded active running SSH Daemon -graphical.target loaded active active Graphical Interface -<replaceable>...</replaceable> -</screen> - -</para> - -<para>You can ask for detailed status information about a unit, for -instance, the PostgreSQL database service: - -<screen> -$ systemctl status postgresql.service -postgresql.service - PostgreSQL Server - Loaded: loaded (/nix/store/pn3q73mvh75gsrl8w7fdlfk3fq5qm5mw-unit/postgresql.service) - Active: active (running) since Mon, 2013-01-07 15:55:57 CET; 9h ago - Main PID: 2390 (postgres) - CGroup: name=systemd:/system/postgresql.service - ├─2390 postgres - ├─2418 postgres: writer process - ├─2419 postgres: wal writer process - ├─2420 postgres: autovacuum launcher process - ├─2421 postgres: stats collector process - └─2498 postgres: zabbix zabbix [local] idle - -Jan 07 15:55:55 hagbard postgres[2394]: [1-1] LOG: database system was shut down at 2013-01-07 15:55:05 CET -Jan 07 15:55:57 hagbard postgres[2390]: [1-1] LOG: database system is ready to accept connections -Jan 07 15:55:57 hagbard postgres[2420]: [1-1] LOG: autovacuum launcher started -Jan 07 15:55:57 hagbard systemd[1]: Started PostgreSQL Server. -</screen> - -Note that this shows the status of the unit (active and running), all -the processes belonging to the service, as well as the most recent log -messages from the service. - -</para> - -<para>Units can be stopped, started or restarted: - -<screen> -$ systemctl stop postgresql.service -$ systemctl start postgresql.service -$ systemctl restart postgresql.service -</screen> - -These operations are synchronous: they wait until the service has -finished starting or stopping (or has failed). Starting a unit will -cause the dependencies of that unit to be started as well (if -necessary).</para> - -<!-- - cgroups: each service and user session is a cgroup - -- cgroup resource management --> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-rebooting"><title>Rebooting and shutting down</title> - -<para>The system can be shut down (and automatically powered off) by -doing: - -<screen> -$ shutdown -</screen> - -This is equivalent to running <command>systemctl -poweroff</command>.</para> - -<para>To reboot the system, run - -<screen> -$ reboot -</screen> - -which is equivalent to <command>systemctl reboot</command>. -Alternatively, you can quickly reboot the system using -<literal>kexec</literal>, which bypasses the BIOS by directly loading -the new kernel into memory: - -<screen> -$ systemctl kexec -</screen> - -</para> - -<para>The machine can be suspended to RAM (if supported) using -<command>systemctl suspend</command>, and suspended to disk using -<command>systemctl hibernate</command>.</para> - -<para>These commands can be run by any user who is logged in locally, -i.e. on a virtual console or in X11; otherwise, the user is asked for -authentication.</para> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-user-sessions"><title>User sessions</title> - -<para>Systemd keeps track of all users who are logged into the system -(e.g. on a virtual console or remotely via SSH). The command -<command>loginctl</command> allows querying and manipulating user -sessions. For instance, to list all user sessions: - -<screen> -$ loginctl - SESSION UID USER SEAT - c1 500 eelco seat0 - c3 0 root seat0 - c4 500 alice -</screen> - -This shows that two users are logged in locally, while another is -logged in remotely. (“Seats” are essentially the combinations of -displays and input devices attached to the system; usually, there is -only one seat.) To get information about a session: - -<screen> -$ loginctl session-status c3 -c3 - root (0) - Since: Tue, 2013-01-08 01:17:56 CET; 4min 42s ago - Leader: 2536 (login) - Seat: seat0; vc3 - TTY: /dev/tty3 - Service: login; type tty; class user - State: online - CGroup: name=systemd:/user/root/c3 - ├─ 2536 /nix/store/10mn4xip9n7y9bxqwnsx7xwx2v2g34xn-shadow-4.1.5.1/bin/login -- - ├─10339 -bash - └─10355 w3m nixos.org -</screen> - -This shows that the user is logged in on virtual console 3. It also -lists the processes belonging to this session. Since systemd keeps -track of this, you can terminate a session in a way that ensures that -all the session’s processes are gone: - -<screen> -$ loginctl terminate-session c3 -</screen> - -</para> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-cgroups"><title>Control groups</title> - -<para>To keep track of the processes in a running system, systemd uses -<emphasis>control groups</emphasis> (cgroups). A control group is a -set of processes used to allocate resources such as CPU, memory or I/O -bandwidth. There can be multiple control group hierarchies, allowing -each kind of resource to be managed independently.</para> - -<para>The command <command>systemd-cgls</command> lists all control -groups in the <literal>systemd</literal> hierarchy, which is what -systemd uses to keep track of the processes belonging to each service -or user session: - -<screen> -$ systemd-cgls -├─user -│ └─eelco -│ └─c1 -│ ├─ 2567 -:0 -│ ├─ 2682 kdeinit4: kdeinit4 Running... -│ ├─ <replaceable>...</replaceable> -│ └─10851 sh -c less -R -└─system - ├─httpd.service - │ ├─2444 httpd -f /nix/store/3pyacby5cpr55a03qwbnndizpciwq161-httpd.conf -DNO_DETACH - │ └─<replaceable>...</replaceable> - ├─dhcpcd.service - │ └─2376 dhcpcd --config /nix/store/f8dif8dsi2yaa70n03xir8r653776ka6-dhcpcd.conf - └─ <replaceable>...</replaceable> -</screen> - -Similarly, <command>systemd-cgls cpu</command> shows the cgroups in -the CPU hierarchy, which allows per-cgroup CPU scheduling priorities. -By default, every systemd service gets its own CPU cgroup, while all -user sessions are in the top-level CPU cgroup. This ensures, for -instance, that a thousand run-away processes in the -<literal>httpd.service</literal> cgroup cannot starve the CPU for one -process in the <literal>postgresql.service</literal> cgroup. (By -contrast, it they were in the same cgroup, then the PostgreSQL process -would get 1/1001 of the cgroup’s CPU time.) You can limit a service’s -CPU share in <filename>configuration.nix</filename>: - -<programlisting> -systemd.services.httpd.serviceConfig.CPUShares = 512; -</programlisting> - -By default, every cgroup has 1024 CPU shares, so this will halve the -CPU allocation of the <literal>httpd.service</literal> cgroup.</para> - -<para>There also is a <literal>memory</literal> hierarchy that -controls memory allocation limits; by default, all processes are in -the top-level cgroup, so any service or session can exhaust all -available memory. Per-cgroup memory limits can be specified in -<filename>configuration.nix</filename>; for instance, to limit -<literal>httpd.service</literal> to 512 MiB of RAM (excluding swap) -and 640 MiB of RAM (including swap): - -<programlisting> -systemd.services.httpd.serviceConfig.MemoryLimit = "512M"; -systemd.services.httpd.serviceConfig.ControlGroupAttribute = [ "memory.memsw.limit_in_bytes 640M" ]; -</programlisting> - -</para> - -<para>The command <command>systemd-cgtop</command> shows a -continuously updated list of all cgroups with their CPU and memory -usage.</para> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-logging"><title>Logging</title> - -<para>System-wide logging is provided by systemd’s -<emphasis>journal</emphasis>, which subsumes traditional logging -daemons such as syslogd and klogd. Log entries are kept in binary -files in <filename>/var/log/journal/</filename>. The command -<literal>journalctl</literal> allows you to see the contents of the -journal. For example, - -<screen> -$ journalctl -b -</screen> - -shows all journal entries since the last reboot. (The output of -<command>journalctl</command> is piped into <command>less</command> by -default.) You can use various options and match operators to restrict -output to messages of interest. For instance, to get all messages -from PostgreSQL: - -<screen> -$ journalctl -u postgresql.service --- Logs begin at Mon, 2013-01-07 13:28:01 CET, end at Tue, 2013-01-08 01:09:57 CET. -- -... -Jan 07 15:44:14 hagbard postgres[2681]: [2-1] LOG: database system is shut down --- Reboot -- -Jan 07 15:45:10 hagbard postgres[2532]: [1-1] LOG: database system was shut down at 2013-01-07 15:44:14 CET -Jan 07 15:45:13 hagbard postgres[2500]: [1-1] LOG: database system is ready to accept connections -</screen> - -Or to get all messages since the last reboot that have at least a -“critical” severity level: - -<screen> -$ journalctl -b -p crit -Dec 17 21:08:06 mandark sudo[3673]: pam_unix(sudo:auth): auth could not identify password for [alice] -Dec 29 01:30:22 mandark kernel[6131]: [1053513.909444] CPU6: Core temperature above threshold, cpu clock throttled (total events = 1) -</screen> - -</para> - -<para>The system journal is readable by root and by users in the -<literal>wheel</literal> and <literal>systemd-journal</literal> -groups. All users have a private journal that can be read using -<command>journalctl</command>.</para> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-nix-gc"><title>Cleaning up the Nix store</title> - -<para>Nix has a purely functional model, meaning that packages are -never upgraded in place. Instead new versions of packages end up in a -different location in the Nix store (<filename>/nix/store</filename>). -You should periodically run Nix’s <emphasis>garbage -collector</emphasis> to remove old, unreferenced packages. This is -easy: - -<screen> -$ nix-collect-garbage -</screen> - -Alternatively, you can use a systemd unit that does the same in the -background: - -<screen> -$ systemctl start nix-gc.service -</screen> - -You can tell NixOS in <filename>configuration.nix</filename> to run -this unit automatically at certain points in time, for instance, every -night at 03:15: - -<programlisting> -nix.gc.automatic = true; -nix.gc.dates = "03:15"; -</programlisting> - -</para> - -<para>The commands above do not remove garbage collector roots, such -as old system configurations. Thus they do not remove the ability to -roll back to previous configurations. The following command deletes -old roots, removing the ability to roll back to them: -<screen> -$ nix-collect-garbage -d -</screen> -You can also do this for specific profiles, e.g. -<screen> -$ nix-env -p /nix/var/nix/profiles/per-user/eelco/profile --delete-generations old -</screen> -Note that NixOS system configurations are stored in the profile -<filename>/nix/var/nix/profiles/system</filename>.</para> - -<para>Another way to reclaim disk space (often as much as 40% of the -size of the Nix store) is to run Nix’s store optimiser, which seeks -out identical files in the store and replaces them with hard links to -a single copy. -<screen> -$ nix-store --optimise -</screen> -Since this command needs to read the entire Nix store, it can take -quite a while to finish.</para> - -</section> - - -</chapter> diff --git a/nixos/doc/manual/style.css b/nixos/doc/manual/style.css index e2204c159e2..3118b37ead1 100644 --- a/nixos/doc/manual/style.css +++ b/nixos/doc/manual/style.css @@ -262,7 +262,6 @@ table.simplelist margin-bottom: 1em; } -div.affiliation -{ - font-style: italic; -} \ No newline at end of file +div.navheader table, div.navfooter table { + box-shadow: none; +} diff --git a/nixos/doc/manual/troubleshooting.xml b/nixos/doc/manual/troubleshooting.xml deleted file mode 100644 index c7d65112b64..00000000000 --- a/nixos/doc/manual/troubleshooting.xml +++ /dev/null @@ -1,199 +0,0 @@ -<chapter xmlns="http://docbook.org/ns/docbook" - xmlns:xlink="http://www.w3.org/1999/xlink" - xml:id="ch-troubleshooting"> - -<title>Troubleshooting</title> - - -<!--===============================================================--> - -<section xml:id="sec-boot-problems"><title>Boot problems</title> - -<para>If NixOS fails to boot, there are a number of kernel command -line parameters that may help you to identify or fix the issue. You -can add these parameters in the GRUB boot menu by pressing “e” to -modify the selected boot entry and editing the line starting with -<literal>linux</literal>. The following are some useful kernel command -line parameters that are recognised by the NixOS boot scripts or by -systemd: - -<variablelist> - - <varlistentry><term><literal>boot.shell_on_fail</literal></term> - <listitem><para>Start a root shell if something goes wrong in - stage 1 of the boot process (the initial ramdisk). This is - disabled by default because there is no authentication for the - root shell.</para></listitem> - </varlistentry> - - <varlistentry><term><literal>boot.debug1</literal></term> - <listitem><para>Start an interactive shell in stage 1 before - anything useful has been done. That is, no modules have been - loaded and no file systems have been mounted, except for - <filename>/proc</filename> and - <filename>/sys</filename>.</para></listitem> - </varlistentry> - - <varlistentry><term><literal>boot.trace</literal></term> - <listitem><para>Print every shell command executed by the stage 1 - and 2 boot scripts.</para></listitem> - </varlistentry> - - <varlistentry><term><literal>single</literal></term> - <listitem><para>Boot into rescue mode (a.k.a. single user mode). - This will cause systemd to start nothing but the unit - <literal>rescue.target</literal>, which runs - <command>sulogin</command> to prompt for the root password and - start a root login shell. Exiting the shell causes the system to - continue with the normal boot process.</para></listitem> - </varlistentry> - - <varlistentry><term><literal>systemd.log_level=debug systemd.log_target=console</literal></term> - <listitem><para>Make systemd very verbose and send log messages to - the console instead of the journal.</para></listitem> - </varlistentry> - -</variablelist> - -For more parameters recognised by systemd, see -<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para> - -<para>If no login prompts or X11 login screens appear (e.g. due to -hanging dependencies), you can press Alt+ArrowUp. If you’re lucky, -this will start rescue mode (described above). (Also note that since -most units have a 90-second timeout before systemd gives up on them, -the <command>agetty</command> login prompts should appear eventually -unless something is very wrong.)</para> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-maintenance-mode"><title>Maintenance mode</title> - -<para>You can enter rescue mode by running: - -<screen> -$ systemctl rescue</screen> - -This will eventually give you a single-user root shell. Systemd will -stop (almost) all system services. To get out of maintenance mode, -just exit from the rescue shell.</para> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-rollback"><title>Rolling back configuration changes</title> - -<para>After running <command>nixos-rebuild</command> to switch to a -new configuration, you may find that the new configuration doesn’t -work very well. In that case, there are several ways to return to a -previous configuration.</para> - -<para>First, the GRUB boot manager allows you to boot into any -previous configuration that hasn’t been garbage-collected. These -configurations can be found under the GRUB submenu “NixOS - All -configurations”. This is especially useful if the new configuration -fails to boot. After the system has booted, you can make the selected -configuration the default for subsequent boots: - -<screen> -$ /run/current-system/bin/switch-to-configuration boot</screen> - -</para> - -<para>Second, you can switch to the previous configuration in a running -system: - -<screen> -$ nixos-rebuild switch --rollback</screen> - -This is equivalent to running: - -<screen> -$ /nix/var/nix/profiles/system-<replaceable>N</replaceable>-link/bin/switch-to-configuration switch</screen> - -where <replaceable>N</replaceable> is the number of the NixOS system -configuration. To get a list of the available configurations, do: - -<screen> -$ ls -l /nix/var/nix/profiles/system-*-link -<replaceable>...</replaceable> -lrwxrwxrwx 1 root root 78 Aug 12 13:54 /nix/var/nix/profiles/system-268-link -> /nix/store/202b...-nixos-13.07pre4932_5a676e4-4be1055 -</screen> - -</para> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-nix-store-corruption"><title>Nix store corruption</title> - -<para>After a system crash, it’s possible for files in the Nix store -to become corrupted. (For instance, the Ext4 file system has the -tendency to replace un-synced files with zero bytes.) NixOS tries -hard to prevent this from happening: it performs a -<command>sync</command> before switching to a new configuration, and -Nix’s database is fully transactional. If corruption still occurs, -you may be able to fix it automatically.</para> - -<para>If the corruption is in a path in the closure of the NixOS -system configuration, you can fix it by doing - -<screen> -$ nixos-rebuild switch --repair -</screen> - -This will cause Nix to check every path in the closure, and if its -cryptographic hash differs from the hash recorded in Nix’s database, -the path is rebuilt or redownloaded.</para> - -<para>You can also scan the entire Nix store for corrupt paths: - -<screen> -$ nix-store --verify --check-contents --repair -</screen> - -Any corrupt paths will be redownloaded if they’re available in a -binary cache; otherwise, they cannot be repaired.</para> - -</section> - - -<!--===============================================================--> - -<section xml:id="sec-nix-network-issues"><title>Nix network issues</title> - -<para>Nix uses a so-called <emphasis>binary cache</emphasis> to -optimise building a package from source into downloading it as a -pre-built binary. That is, whenever a command like -<command>nixos-rebuild</command> needs a path in the Nix store, Nix -will try to download that path from the Internet rather than build it -from source. The default binary cache is -<uri>http://cache.nixos.org/</uri>. If this cache is unreachable, Nix -operations may take a long time due to HTTP connection timeouts. You -can disable the use of the binary cache by adding <option>--option -use-binary-caches false</option>, e.g. - -<screen> -$ nixos-rebuild switch --option use-binary-caches false -</screen> - -If you have an alternative binary cache at your disposal, you can use -it instead: - -<screen> -$ nixos-rebuild switch --option binary-caches http://my-cache.example.org/ -</screen> - -</para> - -</section> - - -</chapter> diff --git a/nixos/lib/build-vms.nix b/nixos/lib/build-vms.nix index 498c0a37783..50b3b424166 100644 --- a/nixos/lib/build-vms.nix +++ b/nixos/lib/build-vms.nix @@ -48,10 +48,11 @@ rec { let interfacesNumbered = zipTwoLists config.virtualisation.vlans (range 1 255); interfaces = flip map interfacesNumbered ({ first, second }: - nameValuePair "eth${toString second}" - { ipAddress = "192.168.${toString first}.${toString m.second}"; - subnetMask = "255.255.255.0"; - }); + nameValuePair "eth${toString second}" { ip4 = + [ { address = "192.168.${toString first}.${toString m.second}"; + prefixLength = 24; + } ]; + }); in { key = "ip-address"; config = @@ -60,7 +61,7 @@ rec { networking.interfaces = listToAttrs interfaces; networking.primaryIPAddress = - optionalString (interfaces != []) (head interfaces).value.ipAddress; + optionalString (interfaces != []) (head (head interfaces).value.ip4).address; # Put the IP addresses of all VMs in this machine's # /etc/hosts file. If a machine has multiple diff --git a/nixos/lib/make-system-tarball.nix b/nixos/lib/make-system-tarball.nix index 8fed9a34882..3bd891fdbc2 100644 --- a/nixos/lib/make-system-tarball.nix +++ b/nixos/lib/make-system-tarball.nix @@ -15,6 +15,9 @@ # store path whose closure will be copied, and `symlink' is a # symlink to `object' that will be added to the tarball. storeContents ? [] + + # Extra tar arguments +, extraArgs ? "" }: stdenv.mkDerivation { @@ -22,7 +25,7 @@ stdenv.mkDerivation { builder = ./make-system-tarball.sh; buildInputs = [perl xz]; - inherit fileName pathsFromGraph; + inherit fileName pathsFromGraph extraArgs; # !!! should use XML. sources = map (x: x.source) contents; diff --git a/nixos/lib/make-system-tarball.sh b/nixos/lib/make-system-tarball.sh index 096d96ac1c8..2eb668115a6 100644 --- a/nixos/lib/make-system-tarball.sh +++ b/nixos/lib/make-system-tarball.sh @@ -50,7 +50,7 @@ done mkdir -p $out/tarball -tar cvJf $out/tarball/$fileName.tar.xz * +tar cvJf $out/tarball/$fileName.tar.xz * $extraArgs mkdir -p $out/nix-support echo $system > $out/nix-support/system diff --git a/nixos/lib/utils.nix b/nixos/lib/utils.nix index 35c56e8c32b..7b8be2050c1 100644 --- a/nixos/lib/utils.nix +++ b/nixos/lib/utils.nix @@ -5,6 +5,7 @@ rec { # Escape a path according to the systemd rules, e.g. /dev/xyzzy # becomes dev-xyzzy. FIXME: slow. escapeSystemdPath = s: - replaceChars ["/" "-" " "] ["-" "\\x2d" "\\x20"] (substring 1 (stringLength s) s); + replaceChars ["/" "-" " "] ["-" "\\x2d" "\\x20"] + (if hasPrefix "/" s then substring 1 (stringLength s) s else s); } diff --git a/nixos/maintainers/scripts/gce/create-gce.sh b/nixos/maintainers/scripts/gce/create-gce.sh index 8bf36f33c7d..fc476fb6e40 100755 --- a/nixos/maintainers/scripts/gce/create-gce.sh +++ b/nixos/maintainers/scripts/gce/create-gce.sh @@ -1,5 +1,6 @@ #! /bin/sh -e +BUCKET_NAME=${BUCKET_NAME:-nixos} export NIX_PATH=nixpkgs=../../../.. export NIXOS_CONFIG=$(dirname $(readlink -f $0))/../../../modules/virtualisation/google-compute-image.nix export TIMESTAMP=$(date +%Y%m%d%H%M) @@ -8,7 +9,7 @@ nix-build '<nixpkgs/nixos>' \ -A config.system.build.googleComputeImage --argstr system x86_64-linux -o gce --option extra-binary-caches http://hydra.nixos.org -j 10 img=$(echo gce/*.tar.gz) -if ! gsutil ls gs://nixos/$(basename $img); then - gsutil cp $img gs://nixos/$(basename $img) +if ! gsutil ls gs://${BUCKET_NAME}/$(basename $img); then + gsutil cp $img gs://${BUCKET_NAME}/$(basename $img) fi -gcutil addimage $(basename $img .raw.tar.gz | sed 's|\.|-|' | sed 's|_|-|') gs://nixos/$(basename $img) +gcloud compute images create $(basename $img .raw.tar.gz | sed 's|\.|-|' | sed 's|_|-|') --source-uri gs://${BUCKET_NAME}/$(basename $img) diff --git a/nixos/modules/config/fonts/fonts.nix b/nixos/modules/config/fonts/fonts.nix index 49b1e1d42a3..f6060a910a1 100644 --- a/nixos/modules/config/fonts/fonts.nix +++ b/nixos/modules/config/fonts/fonts.nix @@ -11,7 +11,7 @@ with lib; # TODO: find another name for it. fonts = mkOption { type = types.listOf types.path; - example = [ pkgs.dejavu_fonts ]; + example = literalExample "[ pkgs.dejavu_fonts ]"; description = "List of primary font paths."; apply = list: list ++ [ # - the user's current profile diff --git a/nixos/modules/config/gtk-exe-env.nix b/nixos/modules/config/gtk-exe-env.nix new file mode 100644 index 00000000000..b565072e3a7 --- /dev/null +++ b/nixos/modules/config/gtk-exe-env.nix @@ -0,0 +1,41 @@ +{ config, pkgs, lib, ... }: + +{ + imports = [ + ]; + + options = { + gtkPlugins = lib.mkOption { + type = lib.types.listOf lib.types.path; + default = []; + description = '' + Plugin packages for GTK+ such as input methods. + ''; + }; + }; + + config = { + environment.variables = if builtins.length config.gtkPlugins > 0 + then + let + paths = [ pkgs.gtk2 pkgs.gtk3 ] ++ config.gtkPlugins; + env = pkgs.buildEnv { + name = "gtk-exe-env"; + + inherit paths; + + postBuild = lib.concatStringsSep "\n" + (map (d: d.gtkExeEnvPostBuild or "") paths); + + ignoreCollisions = true; + }; + in { + GTK_EXE_PREFIX = builtins.toString env; + GTK_PATH = [ + "${env}/lib/gtk-2.0" + "${env}/lib/gtk-3.0" + ]; + } + else {}; + }; +} diff --git a/nixos/modules/config/networking.nix b/nixos/modules/config/networking.nix index fd1e55f673a..136a5bda745 100644 --- a/nixos/modules/config/networking.nix +++ b/nixos/modules/config/networking.nix @@ -7,6 +7,9 @@ with lib; let cfg = config.networking; + dnsmasqResolve = config.services.dnsmasq.enable && + config.services.dnsmasq.resolveLocalQueries; + hasLocalResolver = config.services.bind.enable || dnsmasqResolve; in @@ -74,9 +77,12 @@ in '' + optionalString cfg.dnsSingleRequest '' # only send one DNS request at a time resolv_conf_options='single-request' - '' + optionalString config.services.bind.enable '' + '' + optionalString hasLocalResolver '' # This hosts runs a full-blown DNS resolver. name_servers='127.0.0.1' + '' + optionalString dnsmasqResolve '' + dnsmasq_conf=/etc/dnsmasq-conf.conf + dnsmasq_resolv=/etc/dnsmasq-resolv.conf ''; }; diff --git a/nixos/modules/config/power-management.nix b/nixos/modules/config/power-management.nix index 17f3ed00b9b..32a7987617a 100644 --- a/nixos/modules/config/power-management.nix +++ b/nixos/modules/config/power-management.nix @@ -35,7 +35,9 @@ in powerUpCommands = mkOption { type = types.lines; default = ""; - example = "${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda"; + example = literalExample '' + "''${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda" + ''; description = '' Commands executed when the machine powers up. That is, @@ -47,7 +49,9 @@ in powerDownCommands = mkOption { type = types.lines; default = ""; - example = "${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda"; + example = literalExample '' + "''${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda" + ''; description = '' Commands executed when the machine powers down. That is, diff --git a/nixos/modules/config/pulseaudio.nix b/nixos/modules/config/pulseaudio.nix index 96593885e5b..fb5715022b7 100644 --- a/nixos/modules/config/pulseaudio.nix +++ b/nixos/modules/config/pulseaudio.nix @@ -10,10 +10,12 @@ let systemWide = cfg.enable && cfg.systemWide; nonSystemWide = cfg.enable && !cfg.systemWide; - uid = config.ids.uids.pulseaudio; - gid = config.ids.gids.pulseaudio; + ids = config.ids; - stateDir = "/run/pulse"; + uid = ids.uids.pulseaudio; + gid = ids.gids.pulseaudio; + + stateDir = "/var/run/pulse"; # Create pulse/client.conf even if PulseAudio is disabled so # that we can disable the autospawn feature in programs that @@ -81,7 +83,7 @@ in { package = mkOption { type = types.package; default = pulseaudioFull; - example = literalExample "pulseaudioFull"; + example = literalExample "pkgs.pulseaudioFull"; description = '' The PulseAudio derivation to use. This can be used to disable features (such as JACK support, Bluetooth) that are enabled in the @@ -138,6 +140,8 @@ in { group = "pulse"; extraGroups = [ "audio" ]; description = "PulseAudio system service user"; + home = stateDir; + createHome = true; }; users.extraGroups.pulse.gid = gid; @@ -147,10 +151,6 @@ in { wantedBy = [ "sound.target" ]; before = [ "sound.target" ]; environment.PULSE_RUNTIME_PATH = stateDir; - preStart = '' - mkdir -p --mode 755 ${stateDir} - chown -R pulse:pulse ${stateDir} - ''; serviceConfig = { ExecStart = "${cfg.package}/bin/pulseaudio -D --log-level=${cfg.daemon.logLevel} --system --use-pid-file -n --file=${cfg.configFile}"; PIDFile = "${stateDir}/pid"; diff --git a/nixos/modules/config/qt-plugin-env.nix b/nixos/modules/config/qt-plugin-env.nix new file mode 100644 index 00000000000..c5986560416 --- /dev/null +++ b/nixos/modules/config/qt-plugin-env.nix @@ -0,0 +1,37 @@ +{ config, pkgs, lib, ... }: + +{ + imports = [ + ]; + + options = { + qtPlugins = lib.mkOption { + type = lib.types.listOf lib.types.path; + default = []; + description = '' + Plugin packages for Qt such as input methods. + ''; + }; + }; + + config = { + environment.variables = if builtins.length config.qtPlugins > 0 + then + let + paths = [ pkgs.qt48 ] ++ config.qtPlugins; + env = pkgs.buildEnv { + name = "qt-plugin-env"; + + inherit paths; + + postBuild = lib.concatStringsSep "\n" + (map (d: d.qtPluginEnvPostBuild or "") paths); + + ignoreCollisions = true; + }; + in { + QT_PLUGIN_PATH = [ (builtins.toString env) ]; + } + else {}; + }; +} diff --git a/nixos/modules/config/shells-environment.nix b/nixos/modules/config/shells-environment.nix index cc079cdc585..2559c53ac16 100644 --- a/nixos/modules/config/shells-environment.nix +++ b/nixos/modules/config/shells-environment.nix @@ -122,7 +122,9 @@ in environment.binsh = mkOption { default = "${config.system.build.binsh}/bin/sh"; - example = "\${pkgs.dash}/bin/dash"; + example = literalExample '' + "''${pkgs.dash}/bin/dash" + ''; type = types.path; description = '' The shell executable that is linked system-wide to diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix index 6b4c38172e9..f3e86bfd201 100644 --- a/nixos/modules/config/system-path.nix +++ b/nixos/modules/config/system-path.nix @@ -63,7 +63,7 @@ in systemPackages = mkOption { type = types.listOf types.path; default = []; - example = "[ pkgs.icecat3 pkgs.thunderbird ]"; + example = literalExample "[ pkgs.firefox pkgs.thunderbird ]"; description = '' The set of packages that appear in /run/current-system/sw. These packages are diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index 5de81a77342..a55593c2bad 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -100,6 +100,36 @@ let description = "The path to the user's shell."; }; + subUidRanges = mkOption { + type = types.listOf types.optionSet; + default = []; + example = [ + { startUid = 1000; count = 1; } + { startUid = 100001; count = 65534; } + ]; + options = [ subordinateUidRange ]; + description = '' + Subordinate user ids that user is allowed to use. + They are set into <filename>/etc/subuid</filename> and are used + by <literal>newuidmap</literal> for user namespaces. + ''; + }; + + subGidRanges = mkOption { + type = types.listOf types.optionSet; + default = []; + example = [ + { startGid = 100; count = 1; } + { startGid = 1001; count = 999; } + ]; + options = [ subordinateGidRange ]; + description = '' + Subordinate group ids that user is allowed to use. + They are set into <filename>/etc/subgid</filename> and are used + by <literal>newgidmap</literal> for user namespaces. + ''; + }; + createHome = mkOption { type = types.bool; default = false; @@ -211,6 +241,36 @@ let }; + subordinateUidRange = { + startUid = mkOption { + type = types.int; + description = '' + Start of the range of subordinate user ids that user is + allowed to use. + ''; + }; + count = mkOption { + type = types.int; + default = 1; + description = ''Count of subordinate user ids''; + }; + }; + + subordinateGidRange = { + startGid = mkOption { + type = types.int; + description = '' + Start of the range of subordinate group ids that user is + allowed to use. + ''; + }; + count = mkOption { + type = types.int; + default = 1; + description = ''Count of subordinate group ids''; + }; + }; + getGroup = gname: let groups = mapAttrsToList (n: g: g) ( @@ -249,22 +309,36 @@ let u.description u.home u.shell ]; + filterNull = a: filter (x: hasAttr a x && getAttr a x != null); + sortOn = a: sort (as1: as2: lessThan (getAttr a as1) (getAttr a as2)); groupFile = pkgs.writeText "group" ( concatStringsSep "\n" (map (g: mkGroupEntry g.name) ( - let f = g: g.gid != null; in - sortOn "gid" (filter f (attrValues cfg.extraGroups)) + sortOn "gid" (filterNull "gid" (attrValues cfg.extraGroups)) )) ); passwdFile = pkgs.writeText "passwd" ( concatStringsSep "\n" (map (u: mkPasswdEntry u.name) ( - let f = u: u.createUser && (u.uid != null); in - sortOn "uid" (filter f (attrValues cfg.extraUsers)) + sortOn "uid" (filterNull "uid" (attrValues cfg.extraUsers)) )) ); + mkSubuidEntry = user: concatStrings ( + map (range: "${user.name}:${toString range.startUid}:${toString range.count}\n") + user.subUidRanges); + + subuidFile = concatStrings (map mkSubuidEntry ( + sortOn "uid" (filterNull "uid" (attrValues cfg.extraUsers)))); + + mkSubgidEntry = user: concatStrings ( + map (range: "${user.name}:${toString range.startGid}:${toString range.count}\n") + user.subGidRanges); + + subgidFile = concatStrings (map mkSubgidEntry ( + sortOn "uid" (filterNull "uid" (attrValues cfg.extraUsers)))); + # If mutableUsers is true, this script adds all users/groups defined in # users.extra{Users,Groups} to /etc/{passwd,group} iff there isn't any # existing user/group with the same name in those files. @@ -404,7 +478,7 @@ in { uid = ids.uids.root; description = "System administrator"; home = "/root"; - shell = cfg.defaultUserShell; + shell = mkDefault cfg.defaultUserShell; group = "root"; extraGroups = [ "grsecurity" ]; hashedPassword = mkDefault config.security.initialRootPassword; @@ -504,6 +578,15 @@ in { # for backwards compatibility system.activationScripts.groups = stringAfter [ "users" ] ""; + environment.etc."subuid" = { + text = subuidFile; + mode = "0644"; + }; + environment.etc."subgid" = { + text = subgidFile; + mode = "0644"; + }; + assertions = [ { assertion = !cfg.enforceIdUniqueness || (uidsAreUnique && gidsAreUnique); message = "uids and gids must be unique!"; diff --git a/nixos/modules/config/vpnc.nix b/nixos/modules/config/vpnc.nix new file mode 100644 index 00000000000..68d755232eb --- /dev/null +++ b/nixos/modules/config/vpnc.nix @@ -0,0 +1,41 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.networking.vpnc; + mkServiceDef = name: value: + { + name = "vpnc/${name}.conf"; + value = { text = value; }; + }; + +in +{ + options = { + networking.vpnc = { + services = mkOption { + type = types.attrsOf types.str; + default = {}; + example = { + test = + '' + IPSec gateway 192.168.1.1 + IPSec ID someID + IPSec secret secretKey + Xauth username name + Xauth password pass + ''; + }; + description = + '' + The names of cisco VPNs and their associated definitions + ''; + }; + }; + }; + + config.environment.etc = mapAttrs' mkServiceDef cfg.services; +} + + diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index d43fa220381..22f31c46080 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -11,7 +11,7 @@ let # The Grub image. grubImage = pkgs.runCommand "grub_eltorito" {} '' - ${pkgs.grub2}/bin/grub-mkimage -O i386-pc -o tmp biosdisk iso9660 help linux linux16 chain png jpeg echo gfxmenu reboot + ${pkgs.grub2}/bin/grub-mkimage -p /boot/grub -O i386-pc -o tmp biosdisk iso9660 help linux linux16 chain png jpeg echo gfxmenu reboot cat ${pkgs.grub2}/lib/grub/*/cdboot.img tmp > $out ''; # */ @@ -113,11 +113,12 @@ in }; isoImage.contents = mkOption { - example = + example = literalExample '' [ { source = pkgs.memtest86 + "/memtest.bin"; target = "boot/memtest.bin"; } - ]; + ] + ''; description = '' This option lists files to be copied to fixed locations in the generated ISO image. @@ -125,7 +126,7 @@ in }; isoImage.storeContents = mkOption { - example = [pkgs.stdenv]; + example = literalExample "[ pkgs.stdenv ]"; description = '' This option lists additional derivations to be included in the Nix store in the generated ISO image. diff --git a/nixos/modules/installer/cd-dvd/system-tarball.nix b/nixos/modules/installer/cd-dvd/system-tarball.nix index eaecbe1381f..c24fe97fba4 100644 --- a/nixos/modules/installer/cd-dvd/system-tarball.nix +++ b/nixos/modules/installer/cd-dvd/system-tarball.nix @@ -15,11 +15,12 @@ in { options = { tarball.contents = mkOption { - example = + example = literalExample '' [ { source = pkgs.memtest86 + "/memtest.bin"; target = "boot/memtest.bin"; } - ]; + ] + ''; description = '' This option lists files to be copied to fixed locations in the generated ISO image. @@ -27,7 +28,7 @@ in }; tarball.storeContents = mkOption { - example = [pkgs.stdenv]; + example = literalExample "[ pkgs.stdenv ]"; description = '' This option lists additional derivations to be included in the Nix store in the generated ISO image. diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl index 66a8152a3a6..c6f499b8250 100644 --- a/nixos/modules/installer/tools/nixos-generate-config.pl +++ b/nixos/modules/installer/tools/nixos-generate-config.pl @@ -20,6 +20,13 @@ sub uniq { return @res; } +sub runCommand { + my ($cmd) = @_; + open FILE, "$cmd 2>&1 |" or die "Failed to execute: $cmd\n"; + my @ret = <FILE>; + close FILE; + return ($?, @ret); +} # Process the command line. my $outDir = "/etc/nixos"; @@ -304,10 +311,13 @@ foreach my $fs (read_file("/proc/self/mountinfo")) { # Maybe this is a bind-mount of a filesystem we saw earlier? if (defined $fsByDev{$fields[2]}) { - my $path = $fields[3]; $path = "" if $path eq "/"; - my $base = $fsByDev{$fields[2]}; - $base = "" if $base eq "/"; - $fileSystems .= <<EOF; + # Make sure this isn't a btrfs subvolume + my ($status, @msg) = runCommand("btrfs subvol show $rootDir$mountPoint"); + if (join("", @msg) =~ /ERROR:/) { + my $path = $fields[3]; $path = "" if $path eq "/"; + my $base = $fsByDev{$fields[2]}; + $base = "" if $base eq "/"; + $fileSystems .= <<EOF; fileSystems.\"$mountPoint\" = { device = \"$base$path\"; fsType = \"none\"; @@ -315,7 +325,8 @@ foreach my $fs (read_file("/proc/self/mountinfo")) { }; EOF - next; + next; + } } $fsByDev{$fields[2]} = $mountPoint; @@ -337,6 +348,30 @@ EOF } } + # Is this a btrfs filesystem? + if ($fsType eq "btrfs") { + my ($status, @id_info) = runCommand("btrfs subvol show $rootDir$mountPoint"); + if ($status != 0 || join("", @msg) =~ /ERROR:/) { + die "Failed to retreive subvolume info for $mountPoint\n"; + } + my @ids = join("", @id_info) =~ m/Object ID:[ \t\n]*([^ \t\n]*)/; + if ($#ids > 0) { + die "Btrfs subvol name for $mountPoint listed multiple times in mount\n" + } elsif ($#ids == 0) { + my ($status, @path_info) = runCommand("btrfs subvol list $rootDir$mountPoint"); + if ($status != 0) { + die "Failed to find $mountPoint subvolume id from btrfs\n"; + } + my @paths = join("", @path_info) =~ m/ID $ids[0] [^\n]* path ([^\n]*)/; + if ($#paths > 0) { + die "Btrfs returned multiple paths for a single subvolume id, mountpoint $mountPoint\n"; + } elsif ($#paths != 0) { + die "Btrfs did not return a path for the subvolume at $mountPoint\n"; + } + push @extraOptions, "subvol=$paths[0]"; + } + } + # Emit the filesystem. $fileSystems .= <<EOF; fileSystems.\"$mountPoint\" = diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh index a55eda1cb8f..bd334c2a3cb 100644 --- a/nixos/modules/installer/tools/nixos-install.sh +++ b/nixos/modules/installer/tools/nixos-install.sh @@ -7,6 +7,9 @@ # * nix-env -p /nix/var/nix/profiles/system -i <nix-expr for the configuration> # * install the boot loader +# Ensure a consistent umask. +umask 0022 + # Re-exec ourselves in a private mount namespace so that our bind # mounts get cleaned up automatically. if [ "$(id -u)" = 0 ]; then @@ -30,6 +33,9 @@ while [ "$#" -gt 0 ]; do absolute_path=$(readlink -m $given_path) extraBuildFlags+=("$i" "/mnt$absolute_path") ;; + --root) + mountPoint="$1"; shift 1 + ;; --show-trace) extraBuildFlags+=("$i") ;; @@ -240,7 +246,7 @@ chroot $mountPoint /nix/var/nix/profiles/system/activate # Ask the user to set a root password. if [ -t 0 ] ; then echo "setting root password..." - chroot $mountPoint passwd + chroot $mountPoint /var/setuid-wrappers/passwd fi diff --git a/nixos/modules/installer/tools/nixos-option.sh b/nixos/modules/installer/tools/nixos-option.sh index edc94d73208..d995787c76f 100644 --- a/nixos/modules/installer/tools/nixos-option.sh +++ b/nixos/modules/installer/tools/nixos-option.sh @@ -11,9 +11,6 @@ usage () { # Process Arguments # ##################### -desc=false -defs=false -value=false xml=false verbose=false @@ -24,14 +21,11 @@ for arg; do if test -z "$argfun"; then case $arg in -*) - longarg="" sarg="$arg" + longarg="" while test "$sarg" != "-"; do case $sarg in --*) longarg=$arg; sarg="--";; - -d*) longarg="$longarg --description";; - -v*) longarg="$longarg --value";; - -l*) longarg="$longarg --lookup";; -*) usage;; esac # remove the first letter option @@ -42,9 +36,6 @@ for arg; do esac for larg in $longarg; do case $larg in - --description) desc=true;; - --value) value=true;; - --lookup) defs=true;; --xml) xml=true;; --verbose) verbose=true;; --help) usage;; @@ -67,16 +58,6 @@ for arg; do fi done -if $xml; then - value=true - desc=true - defs=true -fi - -if ! $defs && ! $desc; then - value=true -fi - if $verbose; then set -x else @@ -95,8 +76,7 @@ evalAttr(){ local prefix="$1" local strict="$2" local suffix="$3" - echo "(import <nixos> {}).$prefix${option:+.$option}${suffix:+.$suffix}" | - evalNix ${strict:+--strict} + echo "(import <nixos> {}).$prefix${option:+.$option}${suffix:+.$suffix}" | evalNix ${strict:+--strict} } evalOpt(){ @@ -189,35 +169,35 @@ EOF fi if test "$(evalOpt "_type" 2> /dev/null)" = '"option"'; then - $value && evalCfg 1 - - if $desc; then - $value && echo; - - if default=$(evalOpt "default" - 2> /dev/null); then - echo "Default: $default" - else - echo "Default: <None>" - fi - if example=$(evalOpt "example" - 2> /dev/null); then - echo "Example: $example" - fi - echo "Description:" - eval printf $(evalOpt "description") + echo "Value:" + evalCfg 1 + + echo + + echo "Default:" + if default=$(evalOpt "default" - 2> /dev/null); then + echo "$default" + else + echo "<None>" + fi + echo + if example=$(evalOpt "example" - 2> /dev/null); then + echo "Example: $example" fi + echo "Description:" + echo + eval printf $(evalOpt "description") - if $defs; then - $desc || $value && echo; + echo $desc; - printPath () { echo " $1"; } + printPath () { echo " $1"; } - echo "Declared by:" - nixMap printPath "$(findSources "declarations")" - echo "" - echo "Defined by:" - nixMap printPath "$(findSources "files")" - echo "" - fi + echo "Declared by:" + nixMap printPath "$(findSources "declarations")" + echo + echo "Defined by:" + nixMap printPath "$(findSources "files")" + echo else # echo 1>&2 "Warning: This value is not an option." diff --git a/nixos/modules/installer/tools/tools.nix b/nixos/modules/installer/tools/tools.nix index 39da2f1f0be..91a30695a7a 100644 --- a/nixos/modules/installer/tools/tools.nix +++ b/nixos/modules/installer/tools/tools.nix @@ -38,6 +38,7 @@ let nixos-generate-config = makeProg { name = "nixos-generate-config"; src = ./nixos-generate-config.pl; + path = [ pkgs.btrfsProgs ]; perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl"; }; diff --git a/nixos/modules/installer/virtualbox-demo.nix b/nixos/modules/installer/virtualbox-demo.nix index f68f8dc40aa..49ec0899610 100644 --- a/nixos/modules/installer/virtualbox-demo.nix +++ b/nixos/modules/installer/virtualbox-demo.nix @@ -10,6 +10,9 @@ with lib; ../profiles/clone-config.nix ]; + # FIXME: UUID detection is currently broken + boot.loader.grub.fsIdentifier = "provided"; + # Allow mounting of shared folders. users.extraUsers.demo.extraGroups = [ "vboxsf" ]; diff --git a/nixos/modules/misc/crashdump.nix b/nixos/modules/misc/crashdump.nix index d68f38bae2f..773b5ac9da3 100644 --- a/nixos/modules/misc/crashdump.nix +++ b/nixos/modules/misc/crashdump.nix @@ -28,7 +28,7 @@ in # We don't want to evaluate all of linuxPackages for the manual # - some of it might not even evaluate correctly. defaultText = "pkgs.linuxPackages"; - example = "pkgs.linuxPackages_2_6_25"; + example = literalExample "pkgs.linuxPackages_2_6_25"; description = '' This will override the boot.kernelPackages, and will add some kernel configuration parameters for the crash dump to work. diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index fa81ff8a839..37531ad1cdf 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -141,6 +141,16 @@ unifi = 131; gdm = 132; dhcpd = 133; + siproxd = 134; + mlmmj = 135; + neo4j = 136; + riemann = 137; + riemanndash = 138; + radvd = 139; + zookeeper = 140; + dnsmasq = 141; + uhub = 142; + yandexdisk=143; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -256,6 +266,11 @@ docker = 131; gdm = 132; tss = 133; + siproxd = 134; + mlmmj = 135; + riemann = 137; + riemanndash = 138; + uhub = 142; # When adding a gid, make sure it doesn't match an existing uid. And don't use gids above 399! diff --git a/nixos/modules/misc/meta.nix b/nixos/modules/misc/meta.nix new file mode 100644 index 00000000000..22622706f2c --- /dev/null +++ b/nixos/modules/misc/meta.nix @@ -0,0 +1,63 @@ +{ config, lib, ... }: + +with lib; + +let + maintainer = mkOptionType { + name = "maintainer"; + check = email: elem email (attrValues lib.maintainers); + merge = loc: defs: listToAttrs (singleton (nameValuePair (last defs).file (last defs).value)); + }; + + listOfMaintainers = types.listOf maintainer // { + # Returns list of + # { "module-file" = [ + # "maintainer1 <first@nixos.org>" + # "maintainer2 <second@nixos.org>" ]; + # } + merge = loc: defs: + zipAttrs + (flatten (imap (n: def: imap (m: def': + maintainer.merge (loc ++ ["[${toString n}-${toString m}]"]) + [{ inherit (def) file; value = def'; }]) def.value) defs)); + }; + + docFile = types.path // { + # Returns tuples of + # { file = "module location"; value = <path/to/doc.xml>; } + merge = loc: defs: defs; + }; +in + +{ + options = { + meta = { + + maintainers = mkOption { + type = listOfMaintainers; + internal = true; + default = []; + example = [ lib.maintainers.all ]; + description = '' + List of maintainers of each module. This option should be defined at + most once per module. + ''; + }; + + doc = mkOption { + type = docFile; + internal = true; + example = "./meta.xml"; + description = '' + Documentation prologe for the set of options of each module. This + option should be defined at most once per module. + ''; + }; + + }; + }; + + config = { + meta.maintainers = singleton lib.maintainers.pierron; + }; +} diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 453899175e0..61a98ca12ff 100644..100755 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -5,6 +5,7 @@ ./config/fonts/fonts.nix ./config/fonts/ghostscript.nix ./config/gnu.nix + ./config/gtk-exe-env.nix ./config/i18n.nix ./config/krb5.nix ./config/ldap.nix @@ -13,12 +14,14 @@ ./config/nsswitch.nix ./config/power-management.nix ./config/pulseaudio.nix + ./config/qt-plugin-env.nix ./config/shells-environment.nix ./config/swap.nix ./config/sysctl.nix ./config/system-environment.nix ./config/system-path.nix ./config/timezone.nix + ./config/vpnc.nix ./config/unix-odbc-drivers.nix ./config/users-groups.nix ./config/zram.nix @@ -43,6 +46,7 @@ ./misc/ids.nix ./misc/lib.nix ./misc/locate.nix + ./misc/meta.nix ./misc/nixpkgs.nix ./misc/passthru.nix ./misc/version.nix @@ -59,8 +63,10 @@ ./programs/shell.nix ./programs/ssh.nix ./programs/ssmtp.nix + ./programs/uim.nix ./programs/venus.nix ./programs/wvdial.nix + ./programs/freetds.nix ./programs/zsh/zsh.nix ./rename.nix ./security/apparmor.nix @@ -100,6 +106,7 @@ ./services/databases/monetdb.nix ./services/databases/mongodb.nix ./services/databases/mysql.nix + ./services/databases/neo4j.nix ./services/databases/openldap.nix ./services/databases/postgresql.nix ./services/databases/redis.nix @@ -142,6 +149,7 @@ ./services/mail/dovecot.nix ./services/mail/freepops.nix ./services/mail/mail.nix + ./services/mail/mlmmj.nix ./services/mail/opensmtpd.nix ./services/mail/postfix.nix ./services/mail/spamassassin.nix @@ -153,20 +161,28 @@ ./services/misc/folding-at-home.nix ./services/misc/gitolite.nix ./services/misc/gpsd.nix + ./services/misc/mesos-master.nix + ./services/misc/mesos-slave.nix ./services/misc/nix-daemon.nix ./services/misc/nix-gc.nix ./services/misc/nixos-manual.nix ./services/misc/nix-ssh-serve.nix + ./services/misc/phd.nix ./services/misc/rippled.nix ./services/misc/rogue.nix + ./services/misc/siproxd.nix ./services/misc/svnserve.nix ./services/misc/synergy.nix + ./services/misc/uhub.nix + ./services/misc/zookeeper.nix ./services/monitoring/apcupsd.nix ./services/monitoring/dd-agent.nix ./services/monitoring/graphite.nix ./services/monitoring/monit.nix ./services/monitoring/munin.nix ./services/monitoring/nagios.nix + ./services/monitoring/riemann.nix + ./services/monitoring/riemann-dash.nix ./services/monitoring/smartd.nix ./services/monitoring/statsd.nix ./services/monitoring/systemhealth.nix @@ -179,7 +195,10 @@ ./services/network-filesystems/openafs-client/default.nix ./services/network-filesystems/rsyncd.nix ./services/network-filesystems/samba.nix + ./services/network-filesystems/diod.nix + ./services/network-filesystems/yandex-disk.nix ./services/networking/amuled.nix + ./services/networking/atftpd.nix ./services/networking/avahi-daemon.nix ./services/networking/bind.nix ./services/networking/bitlbee.nix @@ -217,6 +236,7 @@ ./services/networking/ntpd.nix ./services/networking/oidentd.nix ./services/networking/openfire.nix + ./services/networking/openntpd.nix ./services/networking/openvpn.nix ./services/networking/polipo.nix ./services/networking/prayer.nix @@ -252,6 +272,7 @@ ./services/search/elasticsearch.nix ./services/search/solr.nix ./services/security/clamav.nix + ./services/security/fail2ban.nix ./services/security/fprot.nix ./services/security/frandom.nix ./services/security/haveged.nix @@ -293,6 +314,7 @@ ./services/x11/window-managers/awesome.nix #./services/x11/window-managers/compiz.nix ./services/x11/window-managers/default.nix + ./services/x11/window-managers/fluxbox.nix ./services/x11/window-managers/icewm.nix ./services/x11/window-managers/bspwm.nix ./services/x11/window-managers/metacity.nix @@ -348,6 +370,7 @@ ./virtualisation/docker.nix ./virtualisation/libvirtd.nix #./virtualisation/nova.nix + ./virtualisation/openvswitch.nix ./virtualisation/virtualbox-guest.nix #./virtualisation/xen-dom0.nix ] diff --git a/nixos/modules/profiles/all-hardware.nix b/nixos/modules/profiles/all-hardware.nix index 511c118e2bf..6385ee69500 100644 --- a/nixos/modules/profiles/all-hardware.nix +++ b/nixos/modules/profiles/all-hardware.nix @@ -8,7 +8,7 @@ { # The initrd has to contain any module that might be necessary for - # mounting the CD/DVD. + # supporting the most important parts of HW like drives. boot.initrd.availableKernelModules = [ # SATA/PATA support. "ahci" @@ -43,7 +43,7 @@ "virtio_net" "virtio_pci" "virtio_blk" "virtio_balloon" "virtio_console" # Keyboards - "hid_apple" + "usbhid" "hid_apple" "hid_logitech_dj" "hid_lenovo_tpkbd" "hid_roccat" ]; # Include lots of firmware. diff --git a/nixos/modules/programs/environment.nix b/nixos/modules/programs/environment.nix index e7bde81fb23..6bf98442013 100644 --- a/nixos/modules/programs/environment.nix +++ b/nixos/modules/programs/environment.nix @@ -51,7 +51,7 @@ in STRIGI_PLUGIN_PATH = [ "${i}/lib/strigi/" ]; QT_PLUGIN_PATH = [ "${i}/lib/qt4/plugins" "${i}/lib/kde4/plugins" ]; QTWEBKIT_PLUGIN_PATH = [ "${i}/lib/mozilla/plugins/" ]; - GTK_PATH = [ "${i}/lib/gtk-2.0" ]; + GTK_PATH = [ "${i}/lib/gtk-2.0" "${i}/lib/gtk-3.0" ]; XDG_CONFIG_DIRS = [ "${i}/etc/xdg" ]; XDG_DATA_DIRS = [ "${i}/share" ]; MOZ_PLUGIN_PATH = [ "${i}/lib/mozilla/plugins" ]; diff --git a/nixos/modules/programs/freetds.nix b/nixos/modules/programs/freetds.nix new file mode 100644 index 00000000000..398fd104363 --- /dev/null +++ b/nixos/modules/programs/freetds.nix @@ -0,0 +1,61 @@ +# Global configuration for freetds environment. + +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.environment.freetds; + +in +{ + ###### interface + + options = { + + environment.freetds = mkOption { + type = types.attrsOf types.str; + default = {}; + example = { + MYDATABASE = + '' + host = 10.0.2.100 + port = 1433 + tds version = 7.2 + ''; + }; + description = + '' + Configure freetds database entries. Each attribute denotes + a section within freetds.conf, and the value (a string) is the config + content for that section. When at least one entry is configured + the global environment variables FREETDSCONF, FREETDS and SYBASE + will be configured to allow the programs that use freetds to find the + library and config. + ''; + + }; + + }; + + ###### implementation + + config = mkIf (length (attrNames cfg) > 0) { + + environment.variables.FREETDSCONF = "/etc/freetds.conf"; + environment.variables.FREETDS = "/etc/freetds.conf"; + environment.variables.SYBASE = "${pkgs.freetds}"; + + environment.etc."freetds.conf" = { text = + (concatStrings (mapAttrsToList (name: value: + '' + [${name}] + ${value} + '' + ) cfg)); + }; + + }; + +} diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix index 658b08b3d87..5c2ea07c554 100644 --- a/nixos/modules/programs/shadow.nix +++ b/nixos/modules/programs/shadow.nix @@ -83,7 +83,7 @@ in security.pam.services = { chsh = { rootOK = true; }; chfn = { rootOK = true; }; - su = { rootOK = true; forwardXAuth = true; }; + su = { rootOK = true; forwardXAuth = true; logFailures = true; }; passwd = {}; # Note: useradd, groupadd etc. aren't setuid root, so it # doesn't really matter what the PAM config says as long as it @@ -100,7 +100,9 @@ in chgpasswd = { rootOK = true; }; }; - security.setuidPrograms = [ "passwd" "chfn" "su" "newgrp" ]; + security.setuidPrograms = [ "passwd" "chfn" "su" "newgrp" + "newuidmap" "newgidmap" # new in shadow 4.2.x + ]; }; diff --git a/nixos/modules/programs/uim.nix b/nixos/modules/programs/uim.nix new file mode 100644 index 00000000000..237da3415dc --- /dev/null +++ b/nixos/modules/programs/uim.nix @@ -0,0 +1,29 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + cfg = config.uim; +in +{ + options = { + uim = { + enable = mkOption { + type = types.bool; + default = false; + example = true; + description = "enable UIM input method"; + }; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.uim ]; + gtkPlugins = [ pkgs.uim ]; + qtPlugins = [ pkgs.uim ]; + environment.variables.GTK_IM_MODULE = "uim"; + environment.variables.QT_IM_MODULE = "uim"; + environment.variables.XMODIFIERS = "@im=uim"; + services.xserver.displayManager.sessionCommands = "uim-xim &"; + }; +} diff --git a/nixos/modules/programs/virtualbox.nix b/nixos/modules/programs/virtualbox.nix index e2dd76219eb..fec1a7b61f3 100644 --- a/nixos/modules/programs/virtualbox.nix +++ b/nixos/modules/programs/virtualbox.nix @@ -44,5 +44,5 @@ let virtualbox = config.boot.kernelPackages.virtualbox; in ''; }; - networking.interfaces.vboxnet0 = { ipAddress = "192.168.56.1"; prefixLength = 24; }; + networking.interfaces.vboxnet0.ip4 = [ { address = "192.168.56.1"; prefixLength = 24; } ]; } diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index b1b75a0068d..844a9da0eb4 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -126,12 +126,28 @@ let description = "Whether to show the message of the day."; }; + makeHomeDir = mkOption { + default = false; + type = types.bool; + description = '' + Whether to try to create home directories for users + with <literal>$HOME</literal>s pointing to nonexistent + locations on session login. + ''; + }; + updateWtmp = mkOption { default = false; type = types.bool; description = "Whether to update <filename>/var/log/wtmp</filename>."; }; + logFailures = mkOption { + default = false; + type = types.bool; + description = "Whether to log authentication failures in <filename>/var/log/faillog</filename>."; + }; + text = mkOption { type = types.nullOr types.lines; description = "Contents of the PAM service file."; @@ -159,6 +175,8 @@ let # Authentication management. ${optionalString cfg.rootOK "auth sufficient pam_rootok.so"} + ${optionalString cfg.logFailures + "auth required pam_tally.so"} ${optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth) "auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=~/.ssh/authorized_keys:~/.ssh/authorized_keys2:/etc/ssh/authorized_keys.d/%u"} ${optionalString cfg.usbAuth @@ -192,6 +210,8 @@ let "session ${ if config.boot.isContainer then "optional" else "required" } pam_loginuid.so"} + ${optionalString cfg.makeHomeDir + "session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=/etc/skel umask=0022"} ${optionalString cfg.updateWtmp "session required ${pkgs.pam}/lib/security/pam_lastlog.so silent"} ${optionalString config.users.ldap.enable diff --git a/nixos/modules/security/setuid-wrappers.nix b/nixos/modules/security/setuid-wrappers.nix index 373afffd3fb..22dbdf6a6bf 100644 --- a/nixos/modules/security/setuid-wrappers.nix +++ b/nixos/modules/security/setuid-wrappers.nix @@ -77,7 +77,9 @@ in config = { security.setuidPrograms = - [ "fusermount" "wodim" "cdrdao" "growisofs" ]; + [ "mount.nfs" "mount.nfs4" "mount.cifs" + "fusermount" "umount" + "wodim" "cdrdao" "growisofs" ]; system.activationScripts.setuid = let diff --git a/nixos/modules/services/audio/mopidy.nix b/nixos/modules/services/audio/mopidy.nix index 5b865cf4c1b..a7a7e8ae688 100644 --- a/nixos/modules/services/audio/mopidy.nix +++ b/nixos/modules/services/audio/mopidy.nix @@ -49,7 +49,7 @@ in { extensionPackages = mkOption { default = []; type = types.listOf types.package; - example = [ mopidy-spotify ]; + example = literalExample "[ pkgs.mopidy-spotify ]"; description = '' Mopidy extensions that should be loaded by the service. ''; diff --git a/nixos/modules/services/backup/rsnapshot.nix b/nixos/modules/services/backup/rsnapshot.nix index 48ad7582b7e..091b5cfd4d5 100644 --- a/nixos/modules/services/backup/rsnapshot.nix +++ b/nixos/modules/services/backup/rsnapshot.nix @@ -31,7 +31,7 @@ in cronIntervals = mkOption { default = {}; - example = { "hourly" = "0 * * * *"; "daily" = "50 21 * * *"; }; + example = { hourly = "0 * * * *"; daily = "50 21 * * *"; }; type = types.attrsOf types.string; description = '' Periodicity at which intervals should be run by cron. diff --git a/nixos/modules/services/databases/neo4j.nix b/nixos/modules/services/databases/neo4j.nix new file mode 100644 index 00000000000..2ef49a95166 --- /dev/null +++ b/nixos/modules/services/databases/neo4j.nix @@ -0,0 +1,143 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.neo4j; + + serverConfig = pkgs.writeText "neo4j-server.properties" '' + org.neo4j.server.database.location=${cfg.dataDir}/data/graph.db + org.neo4j.server.webserver.address=${cfg.host} + org.neo4j.server.webserver.port=${toString cfg.port} + ${optionalString cfg.enableHttps '' + org.neo4j.server.webserver.https.enabled=true + org.neo4j.server.webserver.https.port=${toString cfg.httpsPort} + org.neo4j.server.webserver.https.cert.location=${cfg.cert} + org.neo4j.server.webserver.https.key.location=${cfg.key} + org.neo4j.server.webserver.https.keystore.location=${cfg.dataDir}/data/keystore + ''} + org.neo4j.server.webadmin.rrdb.location=${cfg.dataDir}/data/rrd + org.neo4j.server.webadmin.data.uri=/db/data/ + org.neo4j.server.webadmin.management.uri=/db/manage/ + org.neo4j.server.db.tuning.properties=${pkgs.neo4j}/share/neo4j/conf/neo4j.properties + org.neo4j.server.manage.console_engines=shell + ${cfg.extraServerConfig} + ''; + + loggingConfig = pkgs.writeText "logging.properties" cfg.loggingConfig; + + wrapperConfig = pkgs.writeText "neo4j-wrapper.conf" '' + wrapper.java.additional=-Dorg.neo4j.server.properties=${serverConfig} + wrapper.java.additional=-Djava.util.logging.config.file=${loggingConfig} + wrapper.java.additional=-XX:+UseConcMarkSweepGC + wrapper.java.additional=-XX:+CMSClassUnloadingEnabled + wrapper.pidfile=${cfg.dataDir}/neo4j-server.pid + wrapper.name=neo4j + ''; + +in { + + ###### interface + + options.services.neo4j = { + enable = mkOption { + description = "Whether to enable neo4j."; + default = false; + type = types.uniq types.bool; + }; + + host = mkOption { + description = "Neo4j listen address."; + default = "127.0.0.1"; + type = types.str; + }; + + port = mkOption { + description = "Neo4j port to listen for HTTP traffic."; + default = 7474; + type = types.int; + }; + + enableHttps = mkOption { + description = "Enable https for Neo4j."; + default = false; + type = types.bool; + }; + + httpsPort = mkOption { + description = "Neo4j port to listen for HTTPS traffic."; + default = 7473; + type = types.int; + }; + + cert = mkOption { + description = "Neo4j https certificate."; + default = "${cfg.dataDir}/conf/ssl/neo4j.cert"; + type = types.path; + }; + + key = mkOption { + description = "Neo4j https certificate key."; + default = "${cfg.dataDir}/conf/ssl/neo4j.key"; + type = types.path; + }; + + dataDir = mkOption { + description = "Neo4j data directory."; + default = "/var/lib/neo4j"; + type = types.path; + }; + + loggingConfig = mkOption { + description = "Neo4j logging configuration."; + default = '' + handlers=java.util.logging.ConsoleHandler + .level=INFO + org.neo4j.server.level=INFO + + java.util.logging.ConsoleHandler.level=INFO + java.util.logging.ConsoleHandler.formatter=org.neo4j.server.logging.SimpleConsoleFormatter + java.util.logging.ConsoleHandler.filter=org.neo4j.server.logging.NeoLogFilter + ''; + type = types.lines; + }; + + extraServerConfig = mkOption { + description = "Extra configuration for neo4j server."; + default = ""; + type = types.lines; + }; + + }; + + ###### implementation + + config = mkIf cfg.enable { + systemd.services.neo4j = { + description = "Neo4j Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-interfaces.target" ]; + environment = { NEO4J_INSTANCE = cfg.dataDir; }; + serviceConfig = { + ExecStart = "${pkgs.neo4j}/bin/neo4j console"; + User = "neo4j"; + PermissionsStartOnly = true; + }; + preStart = '' + mkdir -m 0700 -p ${cfg.dataDir}/{data/graph.db,conf} + ln -fs ${wrapperConfig} ${cfg.dataDir}/conf/neo4j-wrapper.conf + if [ "$(id -u)" = 0 ]; then chown -R neo4j ${cfg.dataDir}; fi + ''; + }; + + environment.systemPackages = [ pkgs.neo4j ]; + + users.extraUsers = singleton { + name = "neo4j"; + uid = config.ids.uids.neo4j; + description = "Neo4j daemon user"; + home = cfg.dataDir; + }; + }; + +} diff --git a/nixos/modules/services/databases/postgresql.xml b/nixos/modules/services/databases/postgresql.xml new file mode 100644 index 00000000000..e98b431bd60 --- /dev/null +++ b/nixos/modules/services/databases/postgresql.xml @@ -0,0 +1,77 @@ +<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-postgresql"> + +<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> + +<!-- FIXME: more stuff, like maintainer? --> + +<para>PostgreSQL is an advanced, free relational database.<!-- MORE --></para> + +<section><title>Configuring</title> + +<para>To enable PostgreSQL, add the following to your +<filename>configuration.nix</filename>: + +<programlisting> +services.postgresql.enable = true; +services.postgresql.package = pkgs.postgresql93; +</programlisting> + +Note that you are required to specify the desired version of +PostgreSQL (e.g. <literal>pkgs.postgresql93</literal>). Since +upgrading your PostgreSQL version requires a database dump and reload +(see below), NixOS cannot provide a default value for +<option>services.postgresql.package</option> such as the most recent +release of PostgreSQL.</para> + +<!-- +<para>After running <command>nixos-rebuild</command>, you can verify +whether PostgreSQL works by running <command>psql</command>: + +<screen> +$ psql +psql (9.2.9) +Type "help" for help. + +alice=> +</screen> +--> + +<para>By default, PostgreSQL stores its databases in +<filename>/var/db/postgresql</filename>. You can override this using +<option>services.postgresql.dataDir</option>, e.g. + +<programlisting> +services.postgresql.dataDir = "/data/postgresql"; +</programlisting> + +</para> + +</section> + + +<section><title>Upgrading</title> + +<para>FIXME: document dump/upgrade/load cycle.</para> + +</section> + + +<section><title>Options</title> + +<para>FIXME: auto-generated list of module options.</para> + +</section> + + +</chapter> diff --git a/nixos/modules/services/hardware/tcsd.nix b/nixos/modules/services/hardware/tcsd.nix index 26b2c884b8f..d7f6c188feb 100644 --- a/nixos/modules/services/hardware/tcsd.nix +++ b/nixos/modules/services/hardware/tcsd.nix @@ -1,8 +1,8 @@ # tcsd daemon. -{ config, pkgs, ... }: +{ config, pkgs, lib, ... }: -with pkgs.lib; +with lib; let cfg = config.services.tcsd; diff --git a/nixos/modules/services/hardware/thermald.nix b/nixos/modules/services/hardware/thermald.nix new file mode 100644 index 00000000000..5233794a20c --- /dev/null +++ b/nixos/modules/services/hardware/thermald.nix @@ -0,0 +1,28 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.thermald; +in { + ###### interface + options = { + services.thermald = { + enable = mkOption { + default = false; + description = '' + Whether to enable thermald, the temperature management daemon. + ''; + }; + }; + }; + + ###### implementation + config = mkIf cfg.enable { + systemd.services.thermald = { + description = "Thermal Daemon Service"; + wantedBy = [ "multi-user.target" ]; + script = "exec ${pkgs.thermald}/sbin/thermald --no-daemon --dbus-enable"; + }; + }; +} diff --git a/nixos/modules/services/logging/syslog-ng.nix b/nixos/modules/services/logging/syslog-ng.nix index 8b892a33bb7..0b3f0cabb00 100644 --- a/nixos/modules/services/logging/syslog-ng.nix +++ b/nixos/modules/services/logging/syslog-ng.nix @@ -49,7 +49,9 @@ in { extraModulePaths = mkOption { type = types.listOf types.str; default = []; - example = [ "${pkgs.syslogng_incubator}/lib/syslog-ng" ]; + example = literalExample '' + [ "''${pkgs.syslogng_incubator}/lib/syslog-ng" ] + ''; description = '' A list of paths that should be included in syslog-ng's <literal>--module-path</literal> option. They should usually diff --git a/nixos/modules/services/mail/mlmmj.nix b/nixos/modules/services/mail/mlmmj.nix new file mode 100644 index 00000000000..637974f05cd --- /dev/null +++ b/nixos/modules/services/mail/mlmmj.nix @@ -0,0 +1,128 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.mlmmj; + stateDir = "/var/lib/mlmmj"; + spoolDir = "/var/spool/mlmmj"; + listDir = domain: list: "${spoolDir}/${domain}/${list}"; + listCtl = domain: list: "${listDir domain list}/control"; + transport = domain: list: "${domain}--${list}@local.list.mlmmj mlmmj:${domain}/${list}"; + virtual = domain: list: "${list}@${domain} ${domain}--${list}@local.list.mlmmj"; + alias = domain: list: "${list}: \"|${pkgs.mlmmj}/mlmmj-receive -L ${listDir domain list}/\""; + subjectPrefix = list: "[${list}]"; + listAddress = domain: list: "${list}@${domain}"; + customHeaders = list: domain: [ "List-Id: ${list}" "Reply-To: ${list}@${domain}" ]; + footer = domain: list: "To unsubscribe send a mail to ${list}+unsubscribe@${domain}"; + createList = d: l: '' + ${pkgs.coreutils}/bin/mkdir -p ${listCtl d l} + echo ${listAddress d l} > ${listCtl d l}/listadress + echo "${lib.concatStringsSep "\n" (customHeaders d l)}" > ${listCtl d l}/customheaders + echo ${footer d l} > ${listCtl d l}/footer + echo ${subjectPrefix l} > ${listCtl d l}/prefix + ''; +in + +{ + + ###### interface + + options = { + + services.mlmmj = { + + enable = mkOption { + type = types.bool; + default = false; + description = "Enable mlmmj"; + }; + + user = mkOption { + type = types.str; + default = "mlmmj"; + description = "mailinglist local user"; + }; + + group = mkOption { + type = types.str; + default = "mlmmj"; + description = "mailinglist local group"; + }; + + listDomain = mkOption { + type = types.str; + default = "localhost"; + description = "Set the mailing list domain"; + }; + + mailLists = mkOption { + type = types.listOf types.str; + default = []; + description = "The collection of hosted maillists"; + }; + + }; + + }; + + ###### implementation + + config = mkIf cfg.enable { + + users.extraUsers = singleton { + name = cfg.user; + description = "mlmmj user"; + home = stateDir; + createHome = true; + uid = config.ids.uids.mlmmj; + group = cfg.group; + useDefaultShell = true; + }; + + users.extraGroups = singleton { + name = cfg.group; + gid = config.ids.gids.mlmmj; + }; + + services.postfix = { + enable = true; + recipientDelimiter= "+"; + extraMasterConf = '' + mlmmj unix - n n - - pipe flags=ORhu user=mlmmj argv=${pkgs.mlmmj}/bin/mlmmj-recieve -F -L ${spoolDir}/$nextHop + ''; + + extraAliases = concatMapStrings (alias cfg.listDomain) cfg.mailLists; + + extraConfig = '' + transport = hash:${stateDir}/transports + virtual = hash:${stateDir}/virtuals + ''; + }; + + environment.systemPackages = [ pkgs.mlmmj ]; + + system.activationScripts.mlmmj = '' + ${pkgs.coreutils}/bin/mkdir -p ${stateDir} ${spoolDir}/${cfg.listDomain} + ${pkgs.coreutils}/bin/chown -R ${cfg.user}:${cfg.group} ${spoolDir} + ${lib.concatMapStrings (createList cfg.listDomain) cfg.mailLists} + echo ${lib.concatMapStrings (virtual cfg.listDomain) cfg.mailLists} > ${stateDir}/virtuals + echo ${cfg.listDomain} mailman: > ${stateDir}/transports + echo ${lib.concatMapStrings (transport cfg.listDomain) cfg.mailLists} >> ${stateDir}/transports + ''; + + systemd.services."mlmmj-maintd" = { + description = "mlmmj maintenance daemon"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + User = cfg.user; + Group = cfg.group; + ExecStart = "${pkgs.mlmmj}/bin/mlmmj-maintd -F -d ${spoolDir}/${cfg.listDomain}"; + }; + }; + + }; + +} diff --git a/nixos/modules/services/misc/mesos-master.nix b/nixos/modules/services/misc/mesos-master.nix new file mode 100644 index 00000000000..bdf88d427c5 --- /dev/null +++ b/nixos/modules/services/misc/mesos-master.nix @@ -0,0 +1,103 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.mesos.master; + +in { + + options.services.mesos = { + + master = { + enable = mkOption { + description = "Whether to enable the Mesos Master."; + default = false; + type = types.uniq types.bool; + }; + + port = mkOption { + description = "Mesos Master port"; + default = 5050; + type = types.int; + }; + + zk = mkOption { + description = '' + ZooKeeper URL (used for leader election amongst masters). + May be one of: + zk://host1:port1,host2:port2,.../mesos + zk://username:password@host1:port1,host2:port2,.../mesos + ''; + type = types.str; + }; + + workDir = mkOption { + description = "The Mesos work directory."; + default = "/var/lib/mesos/master"; + type = types.str; + }; + + extraCmdLineOptions = mkOption { + description = '' + Extra command line options for Mesos Master. + + See https://mesos.apache.org/documentation/latest/configuration/ + ''; + default = [ "" ]; + type = types.listOf types.string; + example = [ "--credentials=VALUE" ]; + }; + + quorum = mkOption { + description = '' + The size of the quorum of replicas when using 'replicated_log' based + registry. It is imperative to set this value to be a majority of + masters i.e., quorum > (number of masters)/2. + + If 0 will fall back to --registry=in_memory. + ''; + default = 0; + type = types.int; + }; + + logLevel = mkOption { + description = '' + The logging level used. Possible values: + 'INFO', 'WARNING', 'ERROR' + ''; + default = "INFO"; + type = types.str; + }; + + }; + + + }; + + + config = mkIf cfg.enable { + systemd.services.mesos-master = { + description = "Mesos Master"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-interfaces.target" ]; + serviceConfig = { + ExecStart = '' + ${pkgs.mesos}/bin/mesos-master \ + --port=${toString cfg.port} \ + --zk=${cfg.zk} \ + ${if cfg.quorum == 0 then "--registry=in_memory" else "--registry=replicated_log --quorum=${cfg.quorum}"} \ + --work_dir=${cfg.workDir} \ + --logging_level=${cfg.logLevel} \ + ${toString cfg.extraCmdLineOptions} + ''; + PermissionsStartOnly = true; + }; + preStart = '' + mkdir -m 0700 -p ${cfg.workDir} + ''; + }; + }; + +} + diff --git a/nixos/modules/services/misc/mesos-slave.nix b/nixos/modules/services/misc/mesos-slave.nix new file mode 100644 index 00000000000..e9a89816716 --- /dev/null +++ b/nixos/modules/services/misc/mesos-slave.nix @@ -0,0 +1,93 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.mesos.slave; + +in { + + options.services.mesos = { + slave = { + enable = mkOption { + description = "Whether to enable the Mesos Slave."; + default = false; + type = types.uniq types.bool; + }; + + port = mkOption { + description = "Mesos Slave port"; + default = 5051; + type = types.int; + }; + + master = mkOption { + description = '' + May be one of: + zk://host1:port1,host2:port2,.../path + zk://username:password@host1:port1,host2:port2,.../path + ''; + type = types.str; + }; + + withHadoop = mkOption { + description = "Add the HADOOP_HOME to the slave."; + default = false; + type = types.bool; + }; + + workDir = mkOption { + description = "The Mesos work directory."; + default = "/var/lib/mesos/slave"; + type = types.str; + }; + + extraCmdLineOptions = mkOption { + description = '' + Extra command line options for Mesos Slave. + + See https://mesos.apache.org/documentation/latest/configuration/ + ''; + default = [ "" ]; + type = types.listOf types.string; + example = [ "--gc_delay=3days" ]; + }; + + logLevel = mkOption { + description = '' + The logging level used. Possible values: + 'INFO', 'WARNING', 'ERROR' + ''; + default = "INFO"; + type = types.str; + }; + + }; + + }; + + + config = mkIf cfg.enable { + systemd.services.mesos-slave = { + description = "Mesos Slave"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-interfaces.target" ]; + serviceConfig = { + ExecStart = '' + ${pkgs.mesos}/bin/mesos-slave \ + --port=${toString cfg.port} \ + --master=${cfg.master} \ + ${optionalString cfg.withHadoop "--hadoop-home=${pkgs.hadoop}"} \ + --work_dir=${cfg.workDir} \ + --logging_level=${cfg.logLevel} \ + ${toString cfg.extraCmdLineOptions} + ''; + PermissionsStartOnly = true; + }; + preStart = '' + mkdir -m 0700 -p ${cfg.workDir} + ''; + }; + }; + +} \ No newline at end of file diff --git a/nixos/modules/services/misc/nixos-manual.nix b/nixos/modules/services/misc/nixos-manual.nix index 808c5dcbdc6..c0d7885280a 100644 --- a/nixos/modules/services/misc/nixos-manual.nix +++ b/nixos/modules/services/misc/nixos-manual.nix @@ -28,7 +28,7 @@ let options = eval.options; }; - entry = "${manual.manual}/share/doc/nixos/manual.html"; + entry = "${manual.manual}/share/doc/nixos/index.html"; help = pkgs.writeScriptBin "nixos-help" '' diff --git a/nixos/modules/services/misc/phd.nix b/nixos/modules/services/misc/phd.nix new file mode 100644 index 00000000000..e605ce5de16 --- /dev/null +++ b/nixos/modules/services/misc/phd.nix @@ -0,0 +1,52 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.phd; + +in + +{ + + ###### interface + + options = { + + services.phd = { + + enable = mkOption { + default = false; + description = " + Enable daemons for phabricator. + "; + }; + + }; + + }; + + ###### implementation + + config = mkIf cfg.enable { + + systemd.services.phd = { + path = [ pkgs.phabricator pkgs.php pkgs.mercurial pkgs.git pkgs.subversion ]; + + after = [ "httpd.service" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + ExecStart = "${pkgs.phabricator}/phabricator/bin/phd start"; + ExecStop = "${pkgs.phabricator}/phabricator/bin/phd stop"; + User = "wwwrun"; + RestartSec = "30s"; + Restart = "always"; + StartLimitInterval = "1m"; + }; + }; + + }; + +} diff --git a/nixos/modules/services/misc/siproxd.nix b/nixos/modules/services/misc/siproxd.nix new file mode 100644 index 00000000000..9e8fb6c228f --- /dev/null +++ b/nixos/modules/services/misc/siproxd.nix @@ -0,0 +1,180 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.siproxd; + + conf = '' + daemonize = 0 + rtp_proxy_enable = 1 + user = siproxd + if_inbound = ${cfg.ifInbound} + if_outbound = ${cfg.ifOutbound} + sip_listen_port = ${toString cfg.sipListenPort} + rtp_port_low = ${toString cfg.rtpPortLow} + rtp_port_high = ${toString cfg.rtpPortHigh} + rtp_dscp = ${toString cfg.rtpDscp} + sip_dscp = ${toString cfg.sipDscp} + ${optionalString (cfg.hostsAllowReg != []) "hosts_allow_reg = ${concatStringsSep "," cfg.hostsAllowReg}"} + ${optionalString (cfg.hostsAllowSip != []) "hosts_allow_sip = ${concatStringsSep "," cfg.hostsAllowSip}"} + ${optionalString (cfg.hostsDenySip != []) "hosts_deny_sip = ${concatStringsSep "," cfg.hostsDenySip}"} + ${if (cfg.passwordFile != "") then "proxy_auth_pwfile = ${cfg.passwordFile}" else ""} + ${cfg.extraConfig} + ''; + + confFile = builtins.toFile "siproxd.conf" conf; + +in +{ + ##### interface + + options = { + + services.siproxd = { + + enable = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable the Siproxd SIP + proxy/masquerading daemon. + ''; + }; + + ifInbound = mkOption { + type = types.str; + example = "eth0"; + description = "Local network interface"; + }; + + ifOutbound = mkOption { + type = types.str; + example = "ppp0"; + description = "Public network interface"; + }; + + hostsAllowReg = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "192.168.1.0/24" "192.168.2.0/24" ]; + description = '' + Acess control list for incoming SIP registrations. + ''; + }; + + hostsAllowSip = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "123.45.0.0/16" "123.46.0.0/16" ]; + description = '' + Acess control list for incoming SIP traffic. + ''; + }; + + hostsDenySip = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ "10.0.0.0/8" "11.0.0.0/8" ]; + description = '' + Acess control list for denying incoming + SIP registrations and traffic. + ''; + }; + + sipListenPort = mkOption { + type = types.int; + default = 5060; + description = '' + Port to listen for incoming SIP messages. + ''; + }; + + rtpPortLow = mkOption { + type = types.int; + default = 7070; + description = '' + Bottom of UDP port range for incoming and outgoing RTP traffic + ''; + }; + + rtpPortHigh = mkOption { + type = types.int; + default = 7089; + description = '' + Top of UDP port range for incoming and outgoing RTP traffic + ''; + }; + + rtpTimeout = mkOption { + type = types.int; + default = 300; + description = '' + Timeout for an RTP stream. If for the specified + number of seconds no data is relayed on an active + stream, it is considered dead and will be killed. + ''; + }; + + rtpDscp = mkOption { + type = types.int; + default = 46; + description = '' + DSCP (differentiated services) value to be assigned + to RTP packets. Allows QOS aware routers to handle + different types traffic with different priorities. + ''; + }; + + sipDscp = mkOption { + type = types.int; + default = 0; + description = '' + DSCP (differentiated services) value to be assigned + to SIP packets. Allows QOS aware routers to handle + different types traffic with different priorities. + ''; + }; + + passwordFile = mkOption { + type = types.str; + default = ""; + description = '' + Path to per-user password file. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra configuration to add to siproxd configuration. + ''; + }; + + }; + + }; + + ##### implementation + + config = mkIf cfg.enable { + + users.extraUsers = singleton { + name = "siproxyd"; + uid = config.ids.uids.siproxd; + }; + + systemd.services.siproxd = { + description = "SIP proxy/masquerading daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + ExecStart = "${pkgs.siproxd}/sbin/siproxd -c ${confFile}"; + }; + }; + + }; + +} diff --git a/nixos/modules/services/misc/uhub.nix b/nixos/modules/services/misc/uhub.nix new file mode 100644 index 00000000000..15071202b9c --- /dev/null +++ b/nixos/modules/services/misc/uhub.nix @@ -0,0 +1,186 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.uhub; + + uhubPkg = pkgs.uhub.override { tlsSupport = cfg.enableTLS; }; + + pluginConfig = "" + + optionalString cfg.plugins.authSqlite.enable '' + plugin ${uhubPkg.mod_auth_sqlite}/mod_auth_sqlite.so "file=${cfg.plugins.authSqlite.file}" + '' + + optionalString cfg.plugins.logging.enable '' + plugin ${uhubPkg.mod_logging}/mod_logging.so ${if cfg.plugins.logging.syslog then "syslog=true" else "file=${cfg.plugins.logging.file}"} + '' + + optionalString cfg.plugins.welcome.enable '' + plugin ${uhubPkg.mod_welcome}/mod_welcome.so "motd=${pkgs.writeText "motd.txt" cfg.plugins.welcome.motd} rules=${pkgs.writeText "rules.txt" cfg.plugins.welcome.rules}" + '' + + optionalString cfg.plugins.history.enable '' + plugin ${uhubPkg.mod_chat_history}/mod_chat_history.so "history_max=${toString cfg.plugins.history.max} history_default=${toString cfg.plugins.history.default} history_connect=${toString cfg.plugins.history.connect}" + ''; + + uhubConfigFile = pkgs.writeText "uhub.conf" '' + file_acl=${pkgs.writeText "users.conf" cfg.aclConfig} + file_plugins=${pkgs.writeText "plugins.conf" pluginConfig} + server_bind_addr=${cfg.address} + server_port=${toString cfg.port} + ${lib.optionalString cfg.enableTLS "tls_enable=yes"} + ${cfg.hubConfig} + ''; + +in + +{ + options = { + + services.uhub = { + + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the uhub ADC hub."; + }; + + port = mkOption { + type = types.int; + default = 1511; + description = "TCP port to bind the hub to."; + }; + + address = mkOption { + type = types.string; + default = "any"; + description = "Address to bind the hub to."; + }; + + enableTLS = mkOption { + type = types.bool; + default = false; + description = "Whether to enable TLS support."; + }; + + hubConfig = mkOption { + type = types.lines; + default = ""; + description = "Contents of uhub configuration file."; + }; + + aclConfig = mkOption { + type = types.lines; + default = ""; + description = "Contents of user ACL configuration file."; + }; + + plugins = { + + authSqlite = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the Sqlite authentication database plugin"; + }; + file = mkOption { + type = types.string; + example = "/var/db/uhub-users"; + description = "Path to user database. Use the uhub-passwd utility to create the database and add/remove users."; + }; + }; + + logging = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the logging plugin."; + }; + file = mkOption { + type = types.string; + default = ""; + description = "Path of log file."; + }; + syslog = mkOption { + type = types.bool; + default = false; + description = "If true then the system log is used instead of writing to file."; + }; + }; + + welcome = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the welcome plugin."; + }; + motd = mkOption { + default = ""; + type = types.lines; + description = '' + Welcome message displayed to clients after connecting + and with the <literal>!motd</literal> command. + ''; + }; + rules = mkOption { + default = ""; + type = types.lines; + description = '' + Rules message, displayed to clients with the <literal>!rules</literal> command. + ''; + }; + }; + + history = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the history plugin."; + }; + max = mkOption { + type = types.int; + default = 200; + description = "The maximum number of messages to keep in history"; + }; + default = mkOption { + type = types.int; + default = 10; + description = "When !history is provided without arguments, then this default number of messages are returned."; + }; + connect = mkOption { + type = types.int; + default = 5; + description = "The number of chat history messages to send when users connect (0 = do not send any history)."; + }; + }; + + }; + }; + + }; + + config = mkIf cfg.enable { + + users = { + extraUsers = singleton { + name = "uhub"; + uid = config.ids.uids.uhub; + }; + extraGroups = singleton { + name = "uhub"; + gid = config.ids.gids.uhub; + }; + }; + + systemd.services.uhub = { + description = "high performance peer-to-peer hub for the ADC network"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "notify"; + ExecStart = "${uhubPkg}/bin/uhub -c ${uhubConfigFile} -u uhub -g uhub -L"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + }; + }; + }; + +} \ No newline at end of file diff --git a/nixos/modules/services/misc/zookeeper.nix b/nixos/modules/services/misc/zookeeper.nix new file mode 100755 index 00000000000..47675b8876c --- /dev/null +++ b/nixos/modules/services/misc/zookeeper.nix @@ -0,0 +1,145 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.zookeeper; + + zookeeperConfig = '' + dataDir=${cfg.dataDir} + clientPort=${toString cfg.port} + autopurge.purgeInterval=${toString cfg.purgeInterval} + ${cfg.extraConf} + ${cfg.servers} + ''; + + configDir = pkgs.buildEnv { + name = "zookeeper-conf"; + paths = [ + (pkgs.writeTextDir "zoo.cfg" zookeeperConfig) + (pkgs.writeTextDir "log4j.properties" cfg.logging) + ]; + }; + +in { + + options.services.zookeeper = { + enable = mkOption { + description = "Whether to enable Zookeeper."; + default = false; + type = types.uniq types.bool; + }; + + port = mkOption { + description = "Zookeeper Client port."; + default = 2181; + type = types.int; + }; + + id = mkOption { + description = "Zookeeper ID."; + default = 0; + type = types.int; + }; + + purgeInterval = mkOption { + description = '' + The time interval in hours for which the purge task has to be triggered. Set to a positive integer (1 and above) to enable the auto purging. + ''; + default = 1; + type = types.int; + }; + + extraConf = mkOption { + description = "Extra configuration for Zookeeper."; + type = types.lines; + default = '' + initLimit=5 + syncLimit=2 + tickTime=2000 + ''; + }; + + servers = mkOption { + description = "All Zookeeper Servers."; + default = ""; + type = types.lines; + example = '' + server.0=host0:2888:3888 + server.1=host1:2888:3888 + server.2=host2:2888:3888 + ''; + }; + + logging = mkOption { + description = "Zookeeper logging configuration."; + default = '' + zookeeper.root.logger=INFO, CONSOLE + log4j.rootLogger=INFO, CONSOLE + log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender + log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout + log4j.appender.CONSOLE.layout.ConversionPattern=[myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n + ''; + type = types.lines; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/zookeeper"; + description = '' + Data directory for Zookeeper + ''; + }; + + extraCmdLineOptions = mkOption { + description = "Extra command line options for the Zookeeper launcher."; + default = [ "-Dcom.sun.management.jmxremote" "-Dcom.sun.management.jmxremote.local.only=true" ]; + type = types.listOf types.string; + example = [ "-Djava.net.preferIPv4Stack=true" "-Dcom.sun.management.jmxremote" "-Dcom.sun.management.jmxremote.local.only=true" ]; + }; + + preferIPv4 = mkOption { + type = types.bool; + default = true; + description = '' + Add the -Djava.net.preferIPv4Stack=true flag to the Zookeeper server. + ''; + }; + + }; + + + config = mkIf cfg.enable { + systemd.services.zookeeper = { + description = "Zookeeper Daemon"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-interfaces.target" ]; + environment = { ZOOCFGDIR = configDir; }; + serviceConfig = { + ExecStart = '' + ${pkgs.jre}/bin/java \ + -cp "${pkgs.zookeeper}/lib/*:${pkgs.zookeeper}/${pkgs.zookeeper.name}.jar:${configDir}" \ + ${toString cfg.extraCmdLineOptions} \ + -Dzookeeper.datadir.autocreate=false \ + ${optionalString cfg.preferIPv4 "-Djava.net.preferIPv4Stack=true"} \ + org.apache.zookeeper.server.quorum.QuorumPeerMain \ + ${configDir}/zoo.cfg + ''; + User = "zookeeper"; + PermissionsStartOnly = true; + }; + preStart = '' + mkdir -m 0700 -p ${cfg.dataDir} + if [ "$(id -u)" = 0 ]; then chown zookeeper ${cfg.dataDir}; fi + echo "${toString cfg.id}" > ${cfg.dataDir}/myid + ''; + }; + + users.extraUsers = singleton { + name = "zookeeper"; + uid = config.ids.uids.zookeeper; + description = "Zookeeper daemon user"; + home = cfg.dataDir; + }; + }; +} diff --git a/nixos/modules/services/monitoring/riemann-dash.nix b/nixos/modules/services/monitoring/riemann-dash.nix new file mode 100644 index 00000000000..148dc046805 --- /dev/null +++ b/nixos/modules/services/monitoring/riemann-dash.nix @@ -0,0 +1,79 @@ +{ config, pkgs, lib, ... }: + +with pkgs; +with lib; + +let + + cfg = config.services.riemann-dash; + + conf = writeText "config.rb" '' + riemann_base = "${cfg.dataDir}" + config.store[:ws_config] = "#{riemann_base}/config/config.json" + ${cfg.config} + ''; + + launcher = writeScriptBin "riemann-dash" '' + #!/bin/sh + exec ${rubyLibs.riemann_dash}/bin/riemann-dash ${conf} + ''; + +in { + + options = { + + services.riemann-dash = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable the riemann-dash dashboard daemon. + ''; + }; + config = mkOption { + type = types.lines; + description = '' + Contents added to the end of the riemann-dash configuration file. + ''; + }; + dataDir = mkOption { + type = types.str; + default = "/var/riemann-dash"; + description = '' + Location of the riemann-base dir. The dashboard configuration file is + is stored to this directory. The directory is created automatically on + service start, and owner is set to the riemanndash user. + ''; + }; + }; + + }; + + config = mkIf cfg.enable { + + users.extraGroups.riemanndash.gid = config.ids.gids.riemanndash; + + users.extraUsers.riemanndash = { + description = "riemann-dash daemon user"; + uid = config.ids.uids.riemanndash; + group = "riemanndash"; + }; + + systemd.services.riemann-dash = { + wantedBy = [ "multi-user.target" ]; + wants = [ "riemann.service" ]; + after = [ "riemann.service" ]; + preStart = '' + mkdir -p ${cfg.dataDir}/config + chown -R riemanndash:riemanndash ${cfg.dataDir} + ''; + serviceConfig = { + User = "riemanndash"; + ExecStart = "${launcher}/bin/riemann-dash"; + PermissionsStartOnly = true; + }; + }; + + }; + +} diff --git a/nixos/modules/services/monitoring/riemann.nix b/nixos/modules/services/monitoring/riemann.nix new file mode 100644 index 00000000000..a1935c29a04 --- /dev/null +++ b/nixos/modules/services/monitoring/riemann.nix @@ -0,0 +1,77 @@ +{ config, pkgs, lib, ... }: + +with pkgs; +with lib; + +let + + cfg = config.services.riemann; + + classpath = concatStringsSep ":" ( + cfg.extraClasspathEntries ++ [ "${riemann}/share/java/riemann.jar" ] + ); + + launcher = writeScriptBin "riemann" '' + #!/bin/sh + exec ${openjdk}/bin/java ${concatStringsSep "\n" cfg.extraJavaOpts} \ + -cp ${classpath} \ + riemann.bin ${writeText "riemann.config" cfg.config} + ''; + +in { + + options = { + + services.riemann = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable the Riemann network monitoring daemon. + ''; + }; + config = mkOption { + type = types.lines; + description = '' + Contents of the Riemann configuration file. + ''; + }; + extraClasspathEntries = mkOption { + type = with types; listOf str; + default = []; + description = '' + Extra entries added to the Java classpath when running Riemann. + ''; + }; + extraJavaOpts = mkOption { + type = with types; listOf str; + default = []; + description = '' + Extra Java options used when launching Riemann. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + + users.extraGroups.riemann.gid = config.ids.gids.riemann; + + users.extraUsers.riemann = { + description = "riemann daemon user"; + uid = config.ids.uids.riemann; + group = "riemann"; + }; + + systemd.services.riemann = { + wantedBy = [ "multi-user.target" ]; + path = [ inetutils ]; + serviceConfig = { + User = "riemann"; + ExecStart = "${launcher}/bin/riemann"; + }; + }; + + }; + +} diff --git a/nixos/modules/services/monitoring/smartd.nix b/nixos/modules/services/monitoring/smartd.nix index 250035fe447..803bd9e9a65 100644 --- a/nixos/modules/services/monitoring/smartd.nix +++ b/nixos/modules/services/monitoring/smartd.nix @@ -62,7 +62,7 @@ in enable = mkOption { default = false; type = types.bool; - example = "true"; + example = true; description = '' Run smartd from the smartmontools package. Note that e-mail notifications will not be enabled unless you configure the list of diff --git a/nixos/modules/services/network-filesystems/diod.nix b/nixos/modules/services/network-filesystems/diod.nix new file mode 100644 index 00000000000..1ab5f52d438 --- /dev/null +++ b/nixos/modules/services/network-filesystems/diod.nix @@ -0,0 +1,159 @@ +{ config, lib, pkgs, ... }: +with lib; +let + cfg = config.services.diod; + + diodBool = b: if b then "1" else "0"; + + diodConfig = pkgs.writeText "diod.conf" '' + allsquash = ${diodBool cfg.allsquash} + auth_required = ${diodBool cfg.authRequired} + exportall = ${diodBool cfg.exportall} + exportopts = "${concatStringsSep "," cfg.exportopts}" + exports = { ${concatStringsSep ", " (map (s: ''"${s}"'' ) cfg.exports)} } + listen = { ${concatStringsSep ", " (map (s: ''"${s}"'' ) cfg.listen)} } + logdest = "${cfg.logdest}" + nwthreads = ${toString cfg.nwthreads} + squashuser = "${cfg.squashuser}" + statfs_passthru = ${diodBool cfg.statfsPassthru} + userdb = ${diodBool cfg.userdb} + ${cfg.extraConfig} + ''; +in +{ + options = { + services.diod = { + enable = mkOption { + type = types.bool; + default = false; + description = "Whether to enable the diod 9P file server."; + }; + + listen = mkOption { + type = types.listOf types.str; + default = [ ]; + description = '' + [ "IP:PORT" [,"IP:PORT",...] ] + List the interfaces and ports that diod should listen on. + ''; + }; + + exports = mkOption { + type = types.listOf types.path; + default = []; + description = '' + List the file systems that clients will be allowed to mount. All paths should + be fully qualified. The exports table can include two types of element: + a string element (as above), + or an alternate table element form { path="/path", opts="ro" }. + In the alternate form, the (optional) opts attribute is a comma-separated list + of export options. The two table element forms can be mixed in the exports + table. Note that although diod will not traverse file system boundaries for a + given mount due to inode uniqueness constraints, subdirectories of a file + system can be separately exported. + ''; + }; + + exportall = mkOption { + type = types.bool; + default = true; + description = '' + Export all file systems listed in /proc/mounts. If new file systems are mounted + after diod has started, they will become immediately mountable. If there is a + duplicate entry for a file system in the exports list, any options listed in + the exports entry will apply. + ''; + }; + + exportopts = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Establish a default set of export options. These are overridden, not appended + to, by opts attributes in an "exports" entry. + ''; + }; + + nwthreads = mkOption { + type = types.int; + default = 16; + description = '' + Sets the (fixed) number of worker threads created to handle 9P + requests for a unique aname. + ''; + }; + + authRequired = mkOption { + type = types.bool; + default = false; + description = '' + Allow clients to connect without authentication, i.e. without a valid MUNGE credential. + ''; + }; + + userdb = mkOption { + type = types.bool; + default = false; + description = '' + This option disables password/group lookups. It allows any uid to attach and + assumes gid=uid, and supplementary groups contain only the primary gid. + ''; + }; + + allsquash = mkOption { + type = types.bool; + default = true; + description = '' + Remap all users to "nobody". The attaching user need not be present in the + password file. + ''; + }; + + squashuser = mkOption { + type = types.str; + default = "nobody"; + description = '' + Change the squash user. The squash user must be present in the password file. + ''; + }; + + logdest = mkOption { + type = types.str; + default = "syslog:daemon:err"; + description = '' + Set the destination for logging. + The value has the form of "syslog:facility:level" or "filename". + ''; + }; + + + statfsPassthru = mkOption { + type = types.bool; + default = false; + description = '' + This option configures statfs to return the host file system's type + rather than V9FS_MAGIC. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = "Extra configuration options for diod.conf."; + }; + }; + }; + + config = mkIf config.services.diod.enable { + environment.systemPackages = [ pkgs.diod ]; + + systemd.services.diod = { + description = "diod 9P file server"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + ExecStart = "${pkgs.diod}/sbin/diod -c ${diodConfig}"; + }; + }; + }; +} diff --git a/nixos/modules/services/network-filesystems/nfsd.nix b/nixos/modules/services/network-filesystems/nfsd.nix index 2217fec3b0f..57d56cd7287 100644 --- a/nixos/modules/services/network-filesystems/nfsd.nix +++ b/nixos/modules/services/network-filesystems/nfsd.nix @@ -56,6 +56,14 @@ in default = false; description = "Whether to create the mount points in the exports file at startup time."; }; + + mountdPort = mkOption { + default = null; + example = 4002; + description = '' + Use fixed port for rpc.mountd, usefull if server is behind firewall. + ''; + }; }; }; @@ -138,7 +146,10 @@ in restartTriggers = [ exports ]; serviceConfig.Type = "forking"; - serviceConfig.ExecStart = "@${pkgs.nfsUtils}/sbin/rpc.mountd rpc.mountd"; + serviceConfig.ExecStart = '' + @${pkgs.nfsUtils}/sbin/rpc.mountd rpc.mountd \ + ${if cfg.mountdPort != null then "-p ${toString cfg.mountdPort}" else ""} + ''; serviceConfig.Restart = "always"; }; diff --git a/nixos/modules/services/network-filesystems/yandex-disk.nix b/nixos/modules/services/network-filesystems/yandex-disk.nix new file mode 100644 index 00000000000..df9626d17c9 --- /dev/null +++ b/nixos/modules/services/network-filesystems/yandex-disk.nix @@ -0,0 +1,104 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.yandex-disk; + + dir = "/var/lib/yandex-disk"; + + u = if cfg.user != null then cfg.user else "yandexdisk"; + +in + +{ + + ###### interface + + options = { + + services.yandex-disk = { + + enable = mkOption { + default = false; + description = " + Whether to enable Yandex-disk client. See https://disk.yandex.ru/ + "; + }; + + username = mkOption { + default = ""; + type = types.string; + description = '' + Your yandex.com login name. + ''; + }; + + password = mkOption { + default = ""; + type = types.string; + description = '' + Your yandex.com password. Warning: it will be world-readable in /nix/store. + ''; + }; + + user = mkOption { + default = null; + description = '' + The user the yandex-disk daemon should run as. + ''; + }; + + directory = mkOption { + default = "/home/Yandex.Disk"; + description = "The directory to use for Yandex.Disk storage"; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + users.extraUsers = mkIf (cfg.user == null) [ { + name = u; + uid = config.ids.uids.yandexdisk; + group = "nogroup"; + home = dir; + } ]; + + systemd.services.yandex-disk = { + description = "Yandex-disk server"; + + after = [ "network.target" ]; + + wantedBy = [ "multi-user.target" ]; + + # FIXME: have to specify ${directory} here as well + unitConfig.RequiresMountsFor = dir; + + script = '' + mkdir -p -m 700 ${dir} + chown ${u} ${dir} + + if ! test -d "${cfg.directory}" ; then + mkdir -p -m 755 ${cfg.directory} || + exit 1 + fi + + ${pkgs.su}/bin/su -s ${pkgs.stdenv.shell} ${u} \ + -c '${pkgs.yandex-disk}/bin/yandex-disk token -p ${cfg.password} ${cfg.username} ${dir}/token' + + ${pkgs.su}/bin/su -s ${pkgs.stdenv.shell} ${u} \ + -c '${pkgs.yandex-disk}/bin/yandex-disk start --no-daemon -a ${dir}/token -d ${cfg.directory}' + ''; + + }; + }; + +} + diff --git a/nixos/modules/services/networking/atftpd.nix b/nixos/modules/services/networking/atftpd.nix new file mode 100644 index 00000000000..ab9f8650f0f --- /dev/null +++ b/nixos/modules/services/networking/atftpd.nix @@ -0,0 +1,51 @@ +# NixOS module for atftpd TFTP server + +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.atftpd; + +in + +{ + + options = { + + services.atftpd = { + + enable = mkOption { + default = false; + type = types.uniq types.bool; + description = '' + Whenever to enable the atftpd TFTP server. + ''; + }; + + root = mkOption { + default = "/var/empty"; + type = types.uniq types.string; + description = '' + Document root directory for the atftpd. + ''; + }; + + }; + + }; + + config = mkIf cfg.enable { + + systemd.services.atftpd = { + description = "atftpd TFTP server"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + # runs as nobody + serviceConfig.ExecStart = "${pkgs.atftp}/sbin/atftpd --daemon --no-fork --bind-address 0.0.0.0 ${cfg.root}"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/cjdns.nix b/nixos/modules/services/networking/cjdns.nix index 9306ffd5a18..0519172db91 100644 --- a/nixos/modules/services/networking/cjdns.nix +++ b/nixos/modules/services/networking/cjdns.nix @@ -1,13 +1,3 @@ -# You may notice the commented out sections in this file, -# it would be great to configure cjdns from nix, but cjdns -# reads its configuration from stdin, including the private -# key and admin password, all nested in a JSON structure. -# -# Until a good method of storing the keys outside the nix -# store and mixing them back into a string is devised -# (without too much shell hackery), a skeleton of the -# configuration building lies commented out. - { config, lib, pkgs, ... }: with lib; @@ -16,41 +6,35 @@ let cfg = config.services.cjdns; - /* - # can't keep keys and passwords in the nix store, - # but don't want to deal with this stdin quagmire. - - cjdrouteConf = '' { - "admin": {"bind": "${cfg.admin.bind}", "password": "\${CJDNS_ADMIN}" }, - "privateKey": "\${CJDNS_KEY}", - - "interfaces": { - '' - - + optionalString (cfg.interfaces.udp.bind.address != null) '' - "UDPInterface": [ { - "bind": "${cfg.interfaces.udp.bind.address}:"'' - ${if cfg.interfaces.upd.bind.port != null - then ${toString cfg.interfaces.udp.bind.port} - else ${RANDOM} - fi) - + '' } ]'' - - + (if cfg.interfaces.eth.bind != null then '' - "ETHInterface": [ { - "bind": "${cfg.interfaces.eth.bind}", - "beacon": ${toString cfg.interfaces.eth.beacon} - } ] - '' fi ) - + '' - }, - "router": { "interface": { "type": "TUNInterface" }, }, - "security": [ { "setuser": "nobody" } ] - } - ''; - - cjdrouteConfFile = pkgs.writeText "cjdroute.conf" cjdrouteConf - */ + # would be nice to merge 'cfg' with a //, + # but the json nesting is wacky. + cjdrouteConf = builtins.toJSON ( { + admin = { + bind = cfg.admin.bind; + password = "@CJDNS_ADMIN_PASSWORD@"; + }; + authorizedPasswords = map (p: { password = p; }) cfg.authorizedPasswords; + interfaces = { + ETHInterface = if (cfg.ETHInterface.bind != "") then [ cfg.ETHInterface ] else [ ]; + UDPInterface = if (cfg.UDPInterface.bind != "") then [ cfg.UDPInterface ] else [ ]; + }; + + privateKey = "@CJDNS_PRIVATE_KEY@"; + + resetAfterInactivitySeconds = 100; + + router = { + interface = { type = "TUNInterface"; }; + ipTunnel = { + allowedConnections = []; + outgoingConnections = []; + }; + }; + + security = [ { exemptAngel = 1; setuser = "nobody"; } ]; + + }); + in { @@ -62,146 +46,180 @@ in type = types.bool; default = false; description = '' - Enable this option to start a instance of the - cjdns network encryption and and routing engine. - Configuration will be read from <literal>confFile</literal>. + Whether to enable the cjdns network encryption + and routing engine. A file at /etc/cjdns.keys will + be created if it does not exist to contain a random + secret key that your IPv6 address will be derived from. ''; }; - confFile = mkOption { - default = "/etc/cjdroute.conf"; - description = '' - Configuration file to pipe to cjdroute. + authorizedPasswords = mkOption { + type = types.listOf types.str; + default = [ ]; + example = [ + "snyrfgkqsc98qh1y4s5hbu0j57xw5s0" + "z9md3t4p45mfrjzdjurxn4wuj0d8swv" + "49275fut6tmzu354pq70sr5b95qq0vj" + ]; + description = '' + Any remote cjdns nodes that offer these passwords on + connection will be allowed to route through this node. ''; }; - - /* + admin = { bind = mkOption { + type = types.string; default = "127.0.0.1:11234"; description = '' Bind the administration port to this address and port. ''; }; + }; - passwordFile = mkOption { - example = "/root/cjdns.adminPassword"; - description = '' - File containing a password to the administration port. + UDPInterface = { + bind = mkOption { + type = types.string; + default = ""; + example = "192.168.1.32:43211"; + description = '' + Address and port to bind UDP tunnels to. + ''; + }; + connectTo = mkOption { + type = types.attrsOf ( types.submodule ( + { options, ... }: + { options = { + # TODO make host an option, and add it to networking.extraHosts + password = mkOption { + type = types.str; + description = "Authorized password to the opposite end of the tunnel."; + }; + publicKey = mkOption { + type = types.str; + description = "Public key at the opposite end of the tunnel."; + }; + }; + } + )); + default = { }; + example = { + "192.168.1.1:27313" = { + password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM"; + publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k"; + }; + }; + description = '' + Credentials for making UDP tunnels. ''; }; }; - keyFile = mkOption { - type = types.str; - example = "/root/cjdns.key"; - description = '' - Path to a file containing a cjdns private key on a single line. - ''; - }; - - passwordsFile = mkOption { - type = types.str; - default = null; - example = "/root/cjdns.authorizedPasswords"; - description = '' - A file containing a list of json dictionaries with passwords. - For example: - {"password": "s8xf5z7znl4jt05g922n3wpk75wkypk"}, - { "name": "nice guy", - "password": "xhthk1mglz8tpjrbbvdlhyc092rhpx5"}, - {"password": "3qfxyhmrht7uwzq29pmhbdm9w4bnc8w"} + ETHInterface = { + bind = mkOption { + default = ""; + example = "eth0"; + description = '' + Bind to this device for native ethernet operation. ''; - }; - - interfaces = { - udp = { - bind = { - address = mkOption { - default = "0.0.0.0"; - description = '' - Address to bind UDP tunnels to; disable by setting to null; - ''; - }; - port = mkOption { - type = types.int; - default = null; - description = '' - Port to bind UDP tunnels to. - A port will be choosen at random if this is not set. - This option is required to act as the server end of - a tunnel. - ''; - }; - }; - }; + }; - eth = { - bind = mkOption { - default = null; - example = "eth0"; - description = '' - Bind to this device and operate with native wire format. - ''; - }; - - beacon = mkOption { - default = 2; - description = '' - Auto-connect to other cjdns nodes on the same network. - Options: - 0 -- Disabled. - - 1 -- Accept beacons, this will cause cjdns to accept incoming - beacon messages and try connecting to the sender. - - 2 -- Accept and send beacons, this will cause cjdns to broadcast - messages on the local network which contain a randomly - generated per-session password, other nodes which have this - set to 1 or 2 will hear the beacon messages and connect - automatically. - ''; - }; - - connectTo = mkOption { - type = types.listOf types.str; - default = []; - description = '' - Credentials for connecting look similar to UDP credientials - except they begin with the mac address, for example: - "01:02:03:04:05:06":{"password":"a","publicKey":"b"} - ''; - }; + beacon = mkOption { + type = types.int; + default = 2; + description = '' + Auto-connect to other cjdns nodes on the same network. + Options: + 0: Disabled. + 1: Accept beacons, this will cause cjdns to accept incoming + beacon messages and try connecting to the sender. + 2: Accept and send beacons, this will cause cjdns to broadcast + messages on the local network which contain a randomly + generated per-session password, other nodes which have this + set to 1 or 2 will hear the beacon messages and connect + automatically. + ''; }; + + connectTo = mkOption { + type = types.attrsOf ( types.submodule ( + { options, ... }: + { options = { + password = mkOption { + type = types.str; + description = "Authorized password to the opposite end of the tunnel."; + }; + publicKey = mkOption { + type = types.str; + description = "Public key at the opposite end of the tunnel."; + }; + }; + } + )); + default = { }; + example = { + "01:02:03:04:05:06" = { + password = "5kG15EfpdcKNX3f2GSQ0H1HC7yIfxoCoImnO5FHM"; + publicKey = "371zpkgs8ss387tmr81q04mp0hg1skb51hw34vk1cq644mjqhup0.k"; + }; + }; + description = '' + Credentials for connecting look similar to UDP credientials + except they begin with the mac address. + ''; + }; }; - */ + }; + }; config = mkIf config.services.cjdns.enable { boot.kernelModules = [ "tun" ]; - /* - networking.firewall.allowedUDPPorts = mkIf (cfg.udp.bind.port != null) [ - cfg.udp.bind.port - ]; - */ + # networking.firewall.allowedUDPPorts = ... systemd.services.cjdns = { description = "encrypted networking for everybody"; wantedBy = [ "multi-user.target" ]; - wants = [ "network.target" ]; - before = [ "network.target" ]; - path = [ pkgs.cjdns ]; + after = [ "network-interfaces.target" ]; + + script = '' + source /etc/cjdns.keys + echo '${cjdrouteConf}' | sed \ + -e "s/@CJDNS_ADMIN_PASSWORD@/$CJDNS_ADMIN_PASSWORD/g" \ + -e "s/@CJDNS_PRIVATE_KEY@/$CJDNS_PRIVATE_KEY/g" \ + | ${pkgs.cjdns}/sbin/cjdroute + ''; serviceConfig = { Type = "forking"; - ExecStart = '' - ${pkgs.stdenv.shell} -c "${pkgs.cjdns}/sbin/cjdroute < ${cfg.confFile}" - ''; Restart = "on-failure"; }; }; + + system.activationScripts.cjdns = '' + grep -q "CJDNS_PRIVATE_KEY=" /etc/cjdns.keys || \ + echo "CJDNS_PRIVATE_KEY=$(${pkgs.cjdns}/sbin/makekey)" \ + >> /etc/cjdns.keys + + grep -q "CJDNS_ADMIN_PASSWORD=" /etc/cjdns.keys || \ + echo "CJDNS_ADMIN_PASSWORD=$(${pkgs.coreutils}/bin/head -c 96 /dev/urandom | ${pkgs.coreutils}/bin/tr -dc A-Za-z0-9)" \ + >> /etc/cjdns.keys + + chmod 600 /etc/cjdns.keys + ''; + + assertions = [ + { assertion = ( cfg.ETHInterface.bind != "" || cfg.UDPInterface.bind != "" ); + message = "Neither cjdns.ETHInterface.bind nor cjdns.UDPInterface.bind defined."; + } + { assertion = config.networking.enableIPv6; + message = "networking.enableIPv6 must be enabled for CJDNS to work"; + } + ]; + }; -} + +} \ No newline at end of file diff --git a/nixos/modules/services/networking/copy-com.nix b/nixos/modules/services/networking/copy-com.nix new file mode 100644 index 00000000000..36bd29109b8 --- /dev/null +++ b/nixos/modules/services/networking/copy-com.nix @@ -0,0 +1,53 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.copy-com; + +in + +{ + options = { + + services.copy-com = { + + enable = mkOption { + default = false; + description = " + Enable the copy.com client. + + The first time copy.com is run, it needs to be configured. Before enabling run + copy_console manually. + "; + }; + + user = mkOption { + description = "The user for which copy should run."; + }; + + debug = mkOption { + default = false; + description = "Output more."; + }; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.postfix ]; + + systemd.services."copy-com-${cfg.user}" = { + description = "Copy.com Client"; + after = [ "network.target" "local-fs.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkgs.copy-com}/bin/copy_console ${if cfg.debug then "-consoleOutput -debugToConsole=dirwatch,path-watch,csm_path,csm -debug -console" else ""}"; + User = "${cfg.user}"; + }; + + }; + }; + +} + diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix index 5a353fc0942..084ac69e8d5 100644 --- a/nixos/modules/services/networking/dhcpcd.nix +++ b/nixos/modules/services/networking/dhcpcd.nix @@ -6,10 +6,13 @@ let dhcpcd = if !config.boot.isContainer then pkgs.dhcpcd else pkgs.dhcpcd.override { udev = null; }; + cfg = config.networking.dhcpcd; + # Don't start dhcpcd on explicitly configured interfaces or on - # interfaces that are part of a bridge. + # interfaces that are part of a bridge, bond or sit device. ignoredInterfaces = - map (i: i.name) (filter (i: i.ipAddress != null) (attrValues config.networking.interfaces)) + map (i: i.name) (filter (i: i.ip4 != [ ] || i.ipAddress != null) (attrValues config.networking.interfaces)) + ++ mapAttrsToList (i: _: i) config.networking.sits ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges)) ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bonds)) ++ config.networking.dhcpcd.denyInterfaces; @@ -35,9 +38,12 @@ let # Ignore peth* devices; on Xen, they're renamed physical # Ethernet cards used for bridging. Likewise for vif* and tap* # (Xen) and virbr* and vnet* (libvirt). - denyinterfaces ${toString ignoredInterfaces} lo peth* vif* tap* tun* virbr* vnet* vboxnet* + denyinterfaces ${toString ignoredInterfaces} lo peth* vif* tap* tun* virbr* vnet* vboxnet* sit* + + # Use the list of allowed interfaces if specified + ${optionalString (cfg.allowInterfaces != null) "allowinterfaces ${toString cfg.allowInterfaces}"} - ${config.networking.dhcpcd.extraConfig} + ${cfg.extraConfig} ''; # Hook for emitting ip-up/ip-down events. @@ -58,7 +64,7 @@ let # ${config.systemd.package}/bin/systemctl start ip-down.target #fi - ${config.networking.dhcpcd.runHook} + ${cfg.runHook} ''; in @@ -69,6 +75,18 @@ in options = { + networking.dhcpcd.persistent = mkOption { + type = types.bool; + default = false; + description = '' + Whenever to leave interfaces configured on dhcpcd daemon + shutdown. Set to true if you have your root or store mounted + over the network or this machine accepts SSH connections + through DHCP interfaces and clients should be notified when + it shuts down. + ''; + }; + networking.dhcpcd.denyInterfaces = mkOption { type = types.listOf types.str; default = []; @@ -80,6 +98,17 @@ in ''; }; + networking.dhcpcd.allowInterfaces = mkOption { + type = types.nullOr (types.listOf types.str); + default = null; + description = '' + Enable the DHCP client for any interface whose name matches + any of the shell glob patterns in this list. Any interface not + explicitly matched by this pattern will be denied. This pattern only + applies when non-null. + ''; + }; + networking.dhcpcd.extraConfig = mkOption { type = types.lines; default = ""; @@ -122,7 +151,7 @@ in serviceConfig = { Type = "forking"; PIDFile = "/run/dhcpcd.pid"; - ExecStart = "@${dhcpcd}/sbin/dhcpcd dhcpcd --quiet --config ${dhcpcdConf}"; + ExecStart = "@${dhcpcd}/sbin/dhcpcd dhcpcd --quiet ${optionalString cfg.persistent "--persistent"} --config ${dhcpcdConf}"; ExecReload = "${dhcpcd}/sbin/dhcpcd --rebind"; Restart = "always"; }; diff --git a/nixos/modules/services/networking/dnsmasq.nix b/nixos/modules/services/networking/dnsmasq.nix index 8e38b9d017a..5c68dd89fb1 100644 --- a/nixos/modules/services/networking/dnsmasq.nix +++ b/nixos/modules/services/networking/dnsmasq.nix @@ -6,9 +6,14 @@ let cfg = config.services.dnsmasq; dnsmasq = pkgs.dnsmasq; - serversParam = concatMapStrings (s: "-S ${s} ") cfg.servers; - dnsmasqConf = pkgs.writeText "dnsmasq.conf" '' + ${optionalString cfg.resolveLocalQueries '' + conf-file=/etc/dnsmasq-conf.conf + resolv-file=/etc/dnsmasq-resolv.conf + ''} + ${flip concatMapStrings cfg.servers (server: '' + server=${server} + '')} ${cfg.extraConfig} ''; @@ -29,11 +34,19 @@ in ''; }; + resolveLocalQueries = mkOption { + default = true; + description = '' + Whether dnsmasq should resolve local queries (i.e. add 127.0.0.1 to + /etc/resolv.conf) + ''; + }; + servers = mkOption { default = []; example = [ "8.8.8.8" "8.8.4.4" ]; description = '' - The parameter to dnsmasq -S. + The DNS servers which dnsmasq should query. ''; }; @@ -55,16 +68,35 @@ in config = mkIf config.services.dnsmasq.enable { - jobs.dnsmasq = - { description = "dnsmasq daemon"; + networking.nameservers = + optional cfg.resolveLocalQueries "127.0.0.1"; - startOn = "ip-up"; + services.dbus.packages = [ dnsmasq ]; - daemonType = "daemon"; - - exec = "${dnsmasq}/bin/dnsmasq -R ${serversParam} -o -C ${dnsmasqConf}"; + users.extraUsers = singleton + { name = "dnsmasq"; + uid = config.ids.uids.dnsmasq; + description = "Dnsmasq daemon user"; + home = "/var/empty"; }; + systemd.services.dnsmasq = { + description = "dnsmasq daemon"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + path = [ dnsmasq ]; + preStart = '' + touch /etc/dnsmasq-{conf,resolv}.conf + dnsmasq --test + ''; + serviceConfig = { + Type = "dbus"; + BusName = "uk.org.thekelleys.dnsmasq"; + ExecStart = "${dnsmasq}/bin/dnsmasq -k --enable-dbus --user=dnsmasq -C ${dnsmasqConf}"; + ExecReload = "${dnsmasq}/bin/kill -HUP $MAINPID"; + }; + }; + }; } diff --git a/nixos/modules/services/networking/ircd-hybrid/default.nix b/nixos/modules/services/networking/ircd-hybrid/default.nix index a3d5b71740f..2c397f94d23 100644 --- a/nixos/modules/services/networking/ircd-hybrid/default.nix +++ b/nixos/modules/services/networking/ircd-hybrid/default.nix @@ -66,7 +66,7 @@ in rsaKey = mkOption { default = null; - example = /root/certificates/irc.key; + example = literalExample "/root/certificates/irc.key"; description = " IRCD server RSA key. "; @@ -74,7 +74,7 @@ in certificate = mkOption { default = null; - example = /root/certificates/irc.pem; + example = literalExample "/root/certificates/irc.pem"; description = " IRCD server SSL certificate. There are some limitations - read manual. "; diff --git a/nixos/modules/services/networking/nat.nix b/nixos/modules/services/networking/nat.nix index e8d9d00cc0a..4a4c06503c2 100644 --- a/nixos/modules/services/networking/nat.nix +++ b/nixos/modules/services/networking/nat.nix @@ -75,6 +75,31 @@ in ''; }; + networking.nat.forwardPorts = mkOption { + type = types.listOf types.optionSet; + default = []; + example = [ { sourcePort = 8080; destination = "10.0.0.1:80"; } ]; + options = { + sourcePort = mkOption { + type = types.int; + example = 8080; + description = "Source port of the external interface"; + }; + + destination = mkOption { + type = types.str; + example = "10.0.0.1:80"; + description = "Forward tcp connection to destination ip:port"; + }; + }; + + description = + '' + List of forwarded ports from the external interface to + internal destinations by using DNAT. + ''; + }; + }; @@ -118,6 +143,14 @@ in -s '${range}' -o ${cfg.externalInterface} ${dest} '') cfg.internalIPs} + # NAT from external ports to internal ports. + ${concatMapStrings (fwd: '' + iptables -w -t nat -A PREROUTING \ + -i ${cfg.externalInterface} -p tcp \ + --dport ${builtins.toString fwd.sourcePort} \ + -j DNAT --to-destination ${fwd.destination} + '') cfg.forwardPorts} + echo 1 > /proc/sys/net/ipv4/ip_forward ''; diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix index db8cb122871..cacd52f130f 100644 --- a/nixos/modules/services/networking/nsd.nix +++ b/nixos/modules/services/networking/nsd.nix @@ -456,156 +456,131 @@ in }; - ratelimit = mkOption { - type = types.submodule ( - { options, ... }: - { options = { - - enable = mkOption { - type = types.bool; - default = false; - description = '' - Enable ratelimit capabilities. - ''; - }; - - size = mkOption { - type = types.int; - default = 1000000; - description = '' - Size of the hashtable. More buckets use more memory but lower - the chance of hash hash collisions. - ''; - }; + ratelimit = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable ratelimit capabilities. + ''; + }; - ratelimit = mkOption { - type = types.int; - default = 200; - description = '' - Max qps allowed from any query source. - 0 means unlimited. With an verbosity of 2 blocked and - unblocked subnets will be logged. - ''; - }; + size = mkOption { + type = types.int; + default = 1000000; + description = '' + Size of the hashtable. More buckets use more memory but lower + the chance of hash hash collisions. + ''; + }; - whitelistRatelimit = mkOption { - type = types.int; - default = 2000; - description = '' - Max qps allowed from whitelisted sources. - 0 means unlimited. Set the rrl-whitelist option for specific - queries to apply this limit instead of the default to them. - ''; - }; + ratelimit = mkOption { + type = types.int; + default = 200; + description = '' + Max qps allowed from any query source. + 0 means unlimited. With an verbosity of 2 blocked and + unblocked subnets will be logged. + ''; + }; - slip = mkOption { - type = types.nullOr types.int; - default = null; - description = '' - Number of packets that get discarded before replying a SLIP response. - 0 disables SLIP responses. 1 will make every response a SLIP response. - ''; - }; + whitelistRatelimit = mkOption { + type = types.int; + default = 2000; + description = '' + Max qps allowed from whitelisted sources. + 0 means unlimited. Set the rrl-whitelist option for specific + queries to apply this limit instead of the default to them. + ''; + }; - ipv4PrefixLength = mkOption { - type = types.nullOr types.int; - default = null; - description = '' - IPv4 prefix length. Addresses are grouped by netblock. - ''; - }; + slip = mkOption { + type = types.nullOr types.int; + default = null; + description = '' + Number of packets that get discarded before replying a SLIP response. + 0 disables SLIP responses. 1 will make every response a SLIP response. + ''; + }; - ipv6PrefixLength = mkOption { - type = types.nullOr types.int; - default = null; - description = '' - IPv6 prefix length. Addresses are grouped by netblock. - ''; - }; + ipv4PrefixLength = mkOption { + type = types.nullOr types.int; + default = null; + description = '' + IPv4 prefix length. Addresses are grouped by netblock. + ''; + }; - }; - }); - default = { + ipv6PrefixLength = mkOption { + type = types.nullOr types.int; + default = null; + description = '' + IPv6 prefix length. Addresses are grouped by netblock. + ''; }; - example = {}; - description = '' - ''; }; - remoteControl = mkOption { - type = types.submodule ( - { config, options, ... }: - { options = { - - enable = mkOption { - type = types.bool; - default = false; - description = '' - Wheter to enable remote control via nsd-control(8). - ''; - }; - - interfaces = mkOption { - type = types.listOf types.str; - default = [ "127.0.0.1" "::1" ]; - description = '' - Which interfaces NSD should bind to for remote control. - ''; - }; - - port = mkOption { - type = types.int; - default = 8952; - description = '' - Port number for remote control operations (uses TLS over TCP). - ''; - }; + remoteControl = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Wheter to enable remote control via nsd-control(8). + ''; + }; - serverKeyFile = mkOption { - type = types.path; - default = "/etc/nsd/nsd_server.key"; - description = '' - Path to the server private key, which is used by the server - but not by nsd-control. This file is generated by nsd-control-setup. - ''; - }; + interfaces = mkOption { + type = types.listOf types.str; + default = [ "127.0.0.1" "::1" ]; + description = '' + Which interfaces NSD should bind to for remote control. + ''; + }; - serverCertFile = mkOption { - type = types.path; - default = "/etc/nsd/nsd_server.pem"; - description = '' - Path to the server self signed certificate, which is used by the server - but and by nsd-control. This file is generated by nsd-control-setup. - ''; - }; + port = mkOption { + type = types.int; + default = 8952; + description = '' + Port number for remote control operations (uses TLS over TCP). + ''; + }; - controlKeyFile = mkOption { - type = types.path; - default = "/etc/nsd/nsd_control.key"; - description = '' - Path to the client private key, which is used by nsd-control - but not by the server. This file is generated by nsd-control-setup. - ''; - }; + serverKeyFile = mkOption { + type = types.path; + default = "/etc/nsd/nsd_server.key"; + description = '' + Path to the server private key, which is used by the server + but not by nsd-control. This file is generated by nsd-control-setup. + ''; + }; - controlCertFile = mkOption { - type = types.path; - default = "/etc/nsd/nsd_control.pem"; - description = '' - Path to the client certificate signed with the server certificate. - This file is used by nsd-control and generated by nsd-control-setup. - ''; - }; + serverCertFile = mkOption { + type = types.path; + default = "/etc/nsd/nsd_server.pem"; + description = '' + Path to the server self signed certificate, which is used by the server + but and by nsd-control. This file is generated by nsd-control-setup. + ''; + }; - }; + controlKeyFile = mkOption { + type = types.path; + default = "/etc/nsd/nsd_control.key"; + description = '' + Path to the client private key, which is used by nsd-control + but not by the server. This file is generated by nsd-control-setup. + ''; + }; - }); - default = { + controlCertFile = mkOption { + type = types.path; + default = "/etc/nsd/nsd_control.pem"; + description = '' + Path to the client certificate signed with the server certificate. + This file is used by nsd-control and generated by nsd-control-setup. + ''; }; - example = {}; - description = '' - ''; }; diff --git a/nixos/modules/services/networking/openntpd.nix b/nixos/modules/services/networking/openntpd.nix new file mode 100644 index 00000000000..bd8a7a04a2a --- /dev/null +++ b/nixos/modules/services/networking/openntpd.nix @@ -0,0 +1,49 @@ +{ pkgs, lib, config, options, ... }: + +with lib; + +let + cfg = config.services.openntpd; + + package = pkgs.openntpd.override { + privsepUser = "ntp"; + privsepPath = "/var/empty"; + }; + + cfgFile = pkgs.writeText "openntpd.conf" '' + ${concatStringsSep "\n" (map (s: "server ${s}") cfg.servers)} + ''; +in +{ + ###### interface + + options.services.openntpd = { + enable = mkEnableOption "OpenNTP time synchronization server"; + + servers = mkOption { + default = config.services.ntp.servers; + type = types.listOf types.str; + inherit (options.services.ntp.servers) description; + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + services.ntp.enable = mkForce false; + + users.extraUsers = singleton { + name = "ntp"; + uid = config.ids.uids.ntp; + description = "OpenNTP daemon user"; + home = "/var/empty"; + }; + + systemd.services.openntpd = { + description = "OpenNTP Server"; + wantedBy = [ "ip-up.target" ]; + partOf = [ "ip-up.target" ]; + serviceConfig.ExecStart = "${package}/sbin/ntpd -d -f ${cfgFile}"; + }; + }; +} diff --git a/nixos/modules/services/networking/privoxy.nix b/nixos/modules/services/networking/privoxy.nix index 950112b2dab..94beb78ef5a 100644 --- a/nixos/modules/services/networking/privoxy.nix +++ b/nixos/modules/services/networking/privoxy.nix @@ -6,19 +6,18 @@ let inherit (pkgs) privoxy; - stateDir = "/var/spool/privoxy"; - privoxyUser = "privoxy"; - privoxyFlags = "--no-daemon --user ${privoxyUser} ${privoxyCfg}"; - - privoxyCfg = pkgs.writeText "privoxy.conf" '' - listen-address ${config.services.privoxy.listenAddress} - logdir ${config.services.privoxy.logDir} - confdir ${privoxy}/etc - filterfile default.filter + cfg = config.services.privoxy; - ${config.services.privoxy.extraConfig} + confFile = pkgs.writeText "privoxy.conf" '' + user-manual ${privoxy}/share/doc/privoxy/user-manual + confdir ${privoxy}/etc/ + listen-address ${cfg.listenAddress} + enable-edit-actions ${if (cfg.enableEditActions == true) then "1" else "0"} + ${concatMapStrings (f: "actionsfile ${f}\n") cfg.actionsFiles} + ${concatMapStrings (f: "filterfile ${f}\n") cfg.filterFiles} + ${cfg.extraConfig} ''; in @@ -32,27 +31,51 @@ in services.privoxy = { enable = mkOption { + type = types.bool; default = false; description = '' - Whether to run the machine as a HTTP proxy server. + Whether to enable the Privoxy non-caching filtering proxy. ''; }; listenAddress = mkOption { + type = types.str; default = "127.0.0.1:8118"; description = '' Address the proxy server is listening to. ''; }; - logDir = mkOption { - default = "/var/log/privoxy" ; + actionsFiles = mkOption { + type = types.listOf types.str; + example = [ "match-all.action" "default.action" "/etc/privoxy/user.action" ]; + default = [ "match-all.action" "default.action" ]; + description = '' + List of paths to Privoxy action files. + These paths may either be absolute or relative to the privoxy configuration directory. + ''; + }; + + filterFiles = mkOption { + type = types.listOf types.str; + example = [ "default.filter" "/etc/privoxy/user.filter" ]; + default = [ "default.filter" ]; + description = '' + List of paths to Privoxy filter files. + These paths may either be absolute or relative to the privoxy configuration directory. + ''; + }; + + enableEditActions = mkOption { + type = types.bool; + default = false; description = '' - Location for privoxy log files. + Whether or not the web-based actions file editor may be used. ''; }; extraConfig = mkOption { + type = types.lines; default = "" ; description = '' Extra configuration. Contents will be added verbatim to the configuration file. @@ -62,33 +85,22 @@ in }; - ###### implementation - config = mkIf config.services.privoxy.enable { + config = mkIf cfg.enable { - environment.systemPackages = [ privoxy ]; - users.extraUsers = singleton { name = privoxyUser; uid = config.ids.uids.privoxy; description = "Privoxy daemon user"; - home = stateDir; }; - jobs.privoxy = - { name = "privoxy"; - - startOn = "startup"; - - preStart = - '' - mkdir -m 0755 -p ${stateDir} - chown ${privoxyUser} ${stateDir} - ''; - - exec = "${privoxy}/sbin/privoxy ${privoxyFlags}"; - }; + systemd.services.privoxy = { + description = "Filtering web proxy"; + after = [ "network.target" "nss-lookup.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig.ExecStart = "${privoxy}/sbin/privoxy --no-daemon --user ${privoxyUser} ${confFile}"; + }; }; diff --git a/nixos/modules/services/networking/radvd.nix b/nixos/modules/services/networking/radvd.nix index 08762c9c837..0199502163a 100644 --- a/nixos/modules/services/networking/radvd.nix +++ b/nixos/modules/services/networking/radvd.nix @@ -52,24 +52,32 @@ in config = mkIf cfg.enable { - environment.systemPackages = [ pkgs.radvd ]; + users.extraUsers.radvd = + { uid = config.ids.uids.radvd; + description = "Router Advertisement Daemon User"; + }; - jobs.radvd = + systemd.services.radvd = { description = "IPv6 Router Advertisement Daemon"; - startOn = "started network-interfaces"; + wantedBy = [ "multi-user.target" ]; + + after = [ "network.target" ]; - preStart = - '' - # !!! Radvd only works if IPv6 forwarding is enabled. But - # this should probably be done somewhere else (and not - # necessarily for all interfaces). - echo 1 > /proc/sys/net/ipv6/conf/all/forwarding - ''; + path = [ pkgs.radvd ]; - exec = "${pkgs.radvd}/sbin/radvd -m syslog -s -C ${confFile}"; + preStart = '' + mkdir -m 755 -p /run/radvd + chown radvd /run/radvd + ''; - daemonType = "fork"; + serviceConfig = + { ExecStart = "@${pkgs.radvd}/sbin/radvd radvd" + + " -p /run/radvd/radvd.pid -m syslog -u radvd -C ${confFile}"; + Restart = "always"; + Type = "forking"; + PIDFile = "/run/radvd/radvd.pid"; + }; }; }; diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index e4b29a0b909..379dec2e92c 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -144,6 +144,36 @@ in ''; }; + listenAddresses = mkOption { + type = types.listOf types.optionSet; + default = []; + example = [ { addr = "192.168.3.1"; port = 22; } { addr = "0.0.0.0"; port = 64022; } ]; + description = '' + List of addresses and ports to listen on (ListenAddress directive + in config). If port is not specified for address sshd will listen + on all ports specified by <literal>ports</literal> option. + NOTE: this will override default listening on all local addresses and port 22. + NOTE: setting this option won't automatically enable given ports + in firewall configuration. + ''; + options = { + addr = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Host, IPv4 or IPv6 address to listen to. + ''; + }; + port = mkOption { + type = types.nullOr types.int; + default = null; + description = '' + Port to listen to. + ''; + }; + }; + }; + passwordAuthentication = mkOption { type = types.bool; default = true; @@ -349,6 +379,10 @@ in Port ${toString port} '') cfg.ports} + ${concatMapStrings ({ port, addr }: '' + ListenAddress ${addr}${if port != null then ":" + toString port else ""} + '') cfg.listenAddresses} + ${optionalString cfgc.setXAuthLocation '' XAuthLocation ${pkgs.xorg.xauth}/bin/xauth ''} @@ -383,6 +417,10 @@ in assertion = (data.publicKey == null && data.publicKeyFile != null) || (data.publicKey != null && data.publicKeyFile == null); message = "knownHost ${name} must contain either a publicKey or publicKeyFile"; + }) + ++ flip map cfg.listenAddresses ({ addr, port }: { + assertion = addr != null; + message = "addr must be specified in each listenAddresses entry"; }); }; diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix index 415ff13bdda..73b10c1d561 100644 --- a/nixos/modules/services/networking/unbound.nix +++ b/nixos/modules/services/networking/unbound.nix @@ -6,8 +6,6 @@ let cfg = config.services.unbound; - username = "unbound"; - stateDir = "/var/lib/unbound"; access = concatMapStrings (x: " access-control: ${x} allow\n") cfg.allowedAccess; @@ -21,21 +19,13 @@ let confFile = pkgs.writeText "unbound.conf" '' server: directory: "${stateDir}" - username: ${username} - # make sure unbound can access entropy from inside the chroot. - # e.g. on linux the use these commands (on BSD, devfs(8) is used): - # mount --bind -n /dev/random /etc/unbound/dev/random - # and mount --bind -n /dev/log /etc/unbound/dev/log + username: unbound chroot: "${stateDir}" - # logfile: "${stateDir}/unbound.log" #uncomment to use logfile. - pidfile: "${stateDir}/unbound.pid" - verbosity: 1 # uncomment and increase to get more logging. + pidfile: "" ${interfaces} ${access} - - ${forward} - ${cfg.extraConfig} + ${forward} ''; in @@ -82,7 +72,7 @@ in environment.systemPackages = [ pkgs.unbound ]; users.extraUsers = singleton { - name = username; + name = "unbound"; uid = config.ids.uids.unbound; description = "unbound daemon user"; home = stateDir; @@ -96,8 +86,18 @@ in wants = [" nss-lookup.target" ]; wantedBy = [ "multi-user.target" ]; - path = [ pkgs.unbound ]; - serviceConfig.ExecStart = "${pkgs.unbound}/sbin/unbound -d -c ${confFile}"; + preStart = '' + mkdir -m 0755 -p ${stateDir}/dev/ + cp ${confFile} ${stateDir}/unbound.conf + chown unbound ${stateDir} + touch ${stateDir}/dev/random + ${pkgs.utillinux}/bin/mount --bind -n /dev/random ${stateDir}/dev/random + ''; + + serviceConfig = { + ExecStart = "${pkgs.unbound}/sbin/unbound -d -c ${stateDir}/unbound.conf"; + ExecStopPost="${pkgs.utillinux}/bin/umount ${stateDir}/dev/random"; + }; }; }; diff --git a/nixos/modules/services/networking/znc.nix b/nixos/modules/services/networking/znc.nix index 4d53cd0750f..9b26b2b3244 100644 --- a/nixos/modules/services/networking/znc.nix +++ b/nixos/modules/services/networking/znc.nix @@ -25,85 +25,6 @@ let paths = cfg.modulePackages; }; - confOptions = { ... }: { - options = { - modules = mkOption { - type = types.listOf types.string; - default = [ "partyline" "webadmin" "adminlog" "log" ]; - example = [ "partyline" "webadmin" "adminlog" "log" ]; - description = '' - A list of modules to include in the `znc.conf` file. - ''; - }; - - userModules = mkOption { - type = types.listOf types.string; - default = [ ]; - example = [ "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 to use when generating the `znc.conf` file. - This is the user name used by the user logging into the ZNC web admin. - ''; - }; - - nick = mkOption { - default = "znc-user"; - example = "john"; - type = types.string; - description = '' - The IRC nick to use when generating the `znc.conf` file. - ''; - }; - - passBlock = mkOption { - default = defaultPassBlock; - example = "Must be the block generated by the `znc --makepass` command."; - type = types.string; - description = '' - The pass block to use when generating the `znc.conf` file. - This is the password used by the user logging into the ZNC web admin. - This is the block generated by the `znc --makepass` command. - !!! If not specified, please change this after starting the service. !!! - ''; - }; - - port = mkOption { - default = 5000; - example = 5000; - type = types.int; - description = '' - Specifies the port on which to listen. - ''; - }; - - useSSL = mkOption { - default = true; - example = true; - type = types.bool; - description = '' - Indicates whether the ZNC server should use SSL when listening on the specified port. - ''; - }; - - extraZncConf = mkOption { - default = ""; - type = types.lines; - description = '' - Extra config to `znc.conf` file - ''; - }; - }; - }; - # Keep znc.conf in nix store, then symlink or copy into `dataDir`, depending on `mutable`. mkZncConf = confOpts: '' // Also check http://en.znc.in/wiki/Configuration @@ -211,24 +132,97 @@ in ''; }; - confOptions = mkOption { - default = {}; - example = { - modules = [ "log" ]; - userName = "john"; - nick = "johntron"; + /* TODO: add to the documentation of the current module: + + Values to use when creating a `znc.conf` file. + + confOptions = { + modules = [ "log" ]; + userName = "john"; + nick = "johntron"; + }; + */ + confOptions = { + modules = mkOption { + type = types.listOf types.string; + default = [ "partyline" "webadmin" "adminlog" "log" ]; + example = [ "partyline" "webadmin" "adminlog" "log" ]; + description = '' + A list of modules to include in the `znc.conf` file. + ''; + }; + + userModules = mkOption { + type = types.listOf types.string; + default = [ ]; + example = [ "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 to use when generating the `znc.conf` file. + This is the user name used by the user logging into the ZNC web admin. + ''; + }; + + nick = mkOption { + default = "znc-user"; + example = "john"; + type = types.string; + description = '' + The IRC nick to use when generating the `znc.conf` file. + ''; + }; + + passBlock = mkOption { + default = defaultPassBlock; + example = "Must be the block generated by the `znc --makepass` command."; + type = types.string; + description = '' + The pass block to use when generating the `znc.conf` file. + This is the password used by the user logging into the ZNC web admin. + This is the block generated by the `znc --makepass` command. + !!! If not specified, please change this after starting the service. !!! + ''; + }; + + port = mkOption { + default = 5000; + example = 5000; + type = types.int; + description = '' + Specifies the port on which to listen. + ''; + }; + + useSSL = mkOption { + default = true; + example = true; + type = types.bool; + description = '' + Indicates whether the ZNC server should use SSL when listening on the specified port. + ''; + }; + + extraZncConf = mkOption { + default = ""; + type = types.lines; + description = '' + Extra config to `znc.conf` file + ''; }; - type = types.optionSet; - description = '' - Values to use when creating a `znc.conf` file. - ''; - options = confOptions; }; modulePackages = mkOption { type = types.listOf types.package; default = [ ]; - example = [ pkgs.zncModules.fish pkgs.zncModules.push ]; + example = literalExample "[ pkgs.zncModules.fish pkgs.zncModules.push ]"; description = '' A list of global znc module packages to add to znc. ''; @@ -280,20 +274,16 @@ in # If mutable, regenerate conf file every time. ${optionalString (!cfg.mutable) '' - ${pkgs.coreutils}/echo "znc is set to be system-managed. Now deleting old znc.conf file to be regenerated." - ${pkgs.coreutils}/rm -f ${cfg.dataDir}/configs/znc.conf + ${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." - ${if (!cfg.mutable) - then "${pkgs.coreutils}/bin/ln --force -s ${zncConfFile} ${cfg.dataDir}/.znc/configs/znc.conf" - else '' - ${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 - ''} + ${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 diff --git a/nixos/modules/services/printing/cupsd.nix b/nixos/modules/services/printing/cupsd.nix index d229c610669..8a8085cad28 100644 --- a/nixos/modules/services/printing/cupsd.nix +++ b/nixos/modules/services/printing/cupsd.nix @@ -35,7 +35,7 @@ let bindir = pkgs.buildEnv { name = "cups-progs"; paths = cfg.drivers; - pathsToLink = [ "/lib/cups" "/share/cups" "/bin" ]; + pathsToLink = [ "/lib/cups" "/share/cups" "/bin" "/etc/cups" ]; postBuild = cfg.bindirCmds; }; @@ -89,6 +89,20 @@ in ''; }; + clientConf = mkOption { + type = types.lines; + default = ""; + example = + '' + ServerName server.example.com + Encryption Never + ''; + description = '' + The contents of the client configuration. + (<filename>client.conf</filename>) + ''; + }; + drivers = mkOption { type = types.listOf types.path; example = literalExample "[ pkgs.splix ]"; @@ -124,6 +138,14 @@ in environment.systemPackages = [ cups ]; + environment.variables.CUPS_SERVERROOT = "/etc/cups"; + + environment.etc = [ + { source = pkgs.writeText "client.conf" cfg.clientConf; + target = "cups/client.conf"; + } + ]; + services.dbus.packages = [ cups ]; # Cups uses libusb to talk to printers, and does not use the diff --git a/nixos/modules/services/security/clamav.nix b/nixos/modules/services/security/clamav.nix index 057891a6047..a4d54301fc1 100644 --- a/nixos/modules/services/security/clamav.nix +++ b/nixos/modules/services/security/clamav.nix @@ -71,10 +71,10 @@ in mkdir -m 0755 -p ${stateDir} chown ${clamavUser}:${clamavGroup} ${stateDir} ''; - exec = "${pkgs.clamav}/bin/freshclam --config-file=${pkgs.writeText "freshclam.conf" cfg.updater.config}"; + exec = "${pkgs.clamav}/bin/freshclam --daemon --config-file=${pkgs.writeText "freshclam.conf" cfg.updater.config}"; }; }; }; -} \ No newline at end of file +} diff --git a/nixos/modules/services/ttys/agetty.nix b/nixos/modules/services/ttys/agetty.nix index df21ebbd974..3958be33df2 100644 --- a/nixos/modules/services/ttys/agetty.nix +++ b/nixos/modules/services/ttys/agetty.nix @@ -66,6 +66,13 @@ with lib; restartIfChanged = false; }; + systemd.services."console-getty" = + { serviceConfig.ExecStart = "@${pkgs.utillinux}/sbin/agetty agetty --noclear --login-program ${pkgs.shadow}/bin/login --keep-baud console 115200,38400,9600 $TERM"; + serviceConfig.Restart = "always"; + restartIfChanged = false; + enable = mkDefault config.boot.isContainer; + }; + environment.etc = singleton { # Friendly greeting on the virtual consoles. source = pkgs.writeText "issue" '' diff --git a/nixos/modules/services/web-servers/apache-httpd/default.nix b/nixos/modules/services/web-servers/apache-httpd/default.nix index 78f3cf2b7e4..9ac28373dac 100644 --- a/nixos/modules/services/web-servers/apache-httpd/default.nix +++ b/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -130,7 +130,7 @@ let ''; - loggingConf = '' + loggingConf = (if mainCfg.logFormat != "none" then '' ErrorLog ${mainCfg.logDir}/error_log LogLevel notice @@ -141,7 +141,9 @@ let LogFormat "%{User-agent}i" agent CustomLog ${mainCfg.logDir}/access_log ${mainCfg.logFormat} - ''; + '' else '' + ErrorLog /dev/null + ''); browserHacks = '' @@ -421,7 +423,7 @@ in package = mkOption { type = types.package; default = pkgs.apacheHttpd.override { mpm = mainCfg.multiProcessingModule; }; - example = "pkgs.apacheHttpd_2_4"; + example = literalExample "pkgs.apacheHttpd_2_4"; description = '' Overridable attribute of the Apache HTTP Server package to use. ''; diff --git a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix index aa9aec87f0c..bb066aa6c47 100644 --- a/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix +++ b/nixos/modules/services/web-servers/apache-httpd/mediawiki.nix @@ -133,6 +133,7 @@ in RewriteEngine On RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d + ${concatMapStringsSep "\n" (u: "RewriteCond %{REQUEST_URI} !^${u.urlPath}") serverInfo.vhostConfig.servedDirs} RewriteRule ${if config.enableUploads then "!^/images" else "^.*\$" diff --git a/nixos/modules/services/web-servers/apache-httpd/phabricator.nix b/nixos/modules/services/web-servers/apache-httpd/phabricator.nix index c7a9bdf68c5..e4e3aac8d41 100644 --- a/nixos/modules/services/web-servers/apache-httpd/phabricator.nix +++ b/nixos/modules/services/web-servers/apache-httpd/phabricator.nix @@ -1,35 +1,30 @@ { config, lib, pkgs, ... }: + +with lib; + let - phabricatorRoot = pkgs.stdenv.mkDerivation rec { - version = "2014-05-12"; - name = "phabricator-${version}"; - srcLibphutil = pkgs.fetchgit { - url = git://github.com/facebook/libphutil.git; - rev = "2f3b5a1cf6ea464a0250d4b1c653a795a90d2716"; - sha256 = "9598cec400984dc149162f1e648814a54ea0cd34fcd529973dc83f5486fdd9fd"; - }; - srcArcanist = pkgs.fetchgit { - url = git://github.com/facebook/arcanist.git; - rev = "54c377448db8dbc40f0ca86d43c837d30e493485"; - sha256 = "086db3c0d1154fbad23e7c6def31fd913384ee20247b329515838b669c3028e0"; - }; - srcPhabricator = pkgs.fetchgit { - url = git://github.com/facebook/phabricator.git; - rev = "1644ef185ecf1e9fca3eb6b16351ef46b19d110f"; - sha256 = "e1135e4ba76d53f48aad4161563035414ed7e878f39a8a34a875a01b41b2a084"; - }; - - buildCommand = '' - mkdir -p $out - cp -R ${srcLibphutil} $out/libphutil - cp -R ${srcArcanist} $out/arcanist - cp -R ${srcPhabricator} $out/phabricator - ''; - }; + phabricatorRoot = pkgs.phabricator; in { + enablePHP = true; extraApacheModules = [ "mod_rewrite" ]; DocumentRoot = "${phabricatorRoot}/phabricator/webroot"; + + options = { + git = mkOption { + default = true; + description = "Enable git repositories."; + }; + mercurial = mkOption { + default = true; + description = "Enable mercurial repositories."; + }; + subversion = mkOption { + default = true; + description = "Enable subversion repositories."; + }; + }; + extraConfig = '' DocumentRoot ${phabricatorRoot}/phabricator/webroot @@ -38,4 +33,18 @@ in { RewriteRule ^/favicon.ico - [L,QSA] RewriteRule ^(.*)$ /index.php?__path__=$1 [B,L,QSA] ''; + + extraServerPath = [ + "${pkgs.which}" + "${pkgs.diffutils}" + ] ++ + (if config.mercurial then ["${pkgs.mercurial}"] else []) ++ + (if config.subversion then ["${pkgs.subversion}"] else []) ++ + (if config.git then ["${pkgs.git}"] else []); + + startupScript = pkgs.writeScript "activatePhabricator" '' + mkdir -p /var/repo + chown wwwrun /var/repo + ''; + } diff --git a/nixos/modules/services/web-servers/tomcat.nix b/nixos/modules/services/web-servers/tomcat.nix index c2f464014ae..2af249a8e96 100644 --- a/nixos/modules/services/web-servers/tomcat.nix +++ b/nixos/modules/services/web-servers/tomcat.nix @@ -5,7 +5,7 @@ with lib; let cfg = config.services.tomcat; - tomcat = pkgs.tomcat6; + tomcat = pkgs.tomcat7; in { diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix index 06bcb6dbb8b..049c96c54e7 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -37,7 +37,7 @@ in { services.xserver.desktopManager.gnome3.sessionPath = mkOption { default = []; - example = "[ pkgs.gnome3.gpaste ]"; + example = literalExample "[ pkgs.gnome3.gpaste ]"; description = "Additional list of packages to be added to the session search path. Useful for gnome shell extensions or gsettings-conditionated autostart."; apply = list: list ++ [ gnome3.gnome_shell ]; @@ -51,7 +51,7 @@ in { environment.gnome3.excludePackages = mkOption { default = []; - example = "[ pkgs.gnome3.totem ]"; + example = literalExample "[ pkgs.gnome3.totem ]"; type = types.listOf types.package; description = "Which packages gnome should exclude from the default environment"; }; diff --git a/nixos/modules/services/x11/desktop-managers/kde4.nix b/nixos/modules/services/x11/desktop-managers/kde4.nix index f74dd7e0444..669ddbd904f 100644 --- a/nixos/modules/services/x11/desktop-managers/kde4.nix +++ b/nixos/modules/services/x11/desktop-managers/kde4.nix @@ -65,7 +65,7 @@ in environment.kdePackages = mkOption { default = []; - example = "[ pkgs.kde4.kdesdk ]"; + example = literalExample "[ pkgs.kde4.kdesdk ]"; type = types.listOf types.package; description = "This option is obsolete. Please use <option>environment.systemPackages</option> instead."; }; diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix index 3bf18bd58c8..6e61576f501 100644 --- a/nixos/modules/services/x11/display-managers/default.nix +++ b/nixos/modules/services/x11/display-managers/default.nix @@ -251,14 +251,16 @@ in execCmd = mkOption { type = types.str; - example = "${pkgs.slim}/bin/slim"; + example = literalExample '' + "''${pkgs.slim}/bin/slim" + ''; description = "Command to start the display manager."; }; environment = mkOption { type = types.attrsOf types.unspecified; default = {}; - example = { SLIM_CFGFILE = /etc/slim.conf; }; + example = { SLIM_CFGFILE = "/etc/slim.conf"; }; description = "Additional environment variables needed by the display manager."; }; diff --git a/nixos/modules/services/x11/display-managers/slim.nix b/nixos/modules/services/x11/display-managers/slim.nix index 9ee4e0dc7cb..c7fbfa85e33 100644 --- a/nixos/modules/services/x11/display-managers/slim.nix +++ b/nixos/modules/services/x11/display-managers/slim.nix @@ -19,6 +19,7 @@ let reboot_cmd ${config.systemd.package}/sbin/shutdown -r now ${optionalString (cfg.defaultUser != null) ("default_user " + cfg.defaultUser)} ${optionalString cfg.autoLogin "auto_login yes"} + ${cfg.extraConfig} ''; # Unpack the SLiM theme, or use the default. @@ -89,6 +90,15 @@ in ''; }; + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra configuration options for SLiM login manager. Do not + add options that can be configured directly. + ''; + }; + }; }; diff --git a/nixos/modules/services/x11/window-managers/fluxbox.nix b/nixos/modules/services/x11/window-managers/fluxbox.nix new file mode 100644 index 00000000000..4748ce99ccf --- /dev/null +++ b/nixos/modules/services/x11/window-managers/fluxbox.nix @@ -0,0 +1,28 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.xserver.windowManager.fluxbox; +in +{ + ###### interface + options = { + services.xserver.windowManager.fluxbox.enable = mkOption { + default = false; + description = "Enable the Fluxbox window manager."; + }; + }; + + ###### implementation + config = mkIf cfg.enable { + services.xserver.windowManager.session = singleton { + name = "fluxbox"; + start = '' + ${pkgs.fluxbox}/bin/startfluxbox & + waitPID=$! + ''; + }; + environment.systemPackages = [ pkgs.fluxbox ]; + }; +} diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix index 5f3e8003b45..21eaf6bb6b7 100644 --- a/nixos/modules/services/x11/xserver.nix +++ b/nixos/modules/services/x11/xserver.nix @@ -151,7 +151,7 @@ in modules = mkOption { type = types.listOf types.path; default = []; - example = [ pkgs.xf86_input_wacom ]; + example = literalExample "[ pkgs.xf86_input_wacom ]"; description = "Packages to be added to the module search path of the X server."; }; @@ -201,7 +201,7 @@ in vaapiDrivers = mkOption { type = types.listOf types.path; default = [ ]; - example = "[ pkgs.vaapiIntel pkgs.vaapiVdpau ]"; + example = literalExample "[ pkgs.vaapiIntel pkgs.vaapiVdpau ]"; description = '' Packages providing libva acceleration drivers. ''; diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix index 9beb7fabce1..79b173a6ead 100644 --- a/nixos/modules/system/boot/kernel.nix +++ b/nixos/modules/system/boot/kernel.nix @@ -195,6 +195,7 @@ in "xhci_hcd" "usbhid" "hid_generic" + "hid_apple" "hid_logitech_dj" "hid_lenovo_tpkbd" "hid_roccat" # Unix domain sockets (needed by udev). "unix" diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix index 0cc060db8f9..bc9a155ac95 100644 --- a/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixos/modules/system/boot/loader/grub/grub.nix @@ -6,7 +6,8 @@ let cfg = config.boot.loader.grub; - realGrub = if cfg.version == 1 then pkgs.grub else pkgs.grub2; + realGrub = if cfg.version == 1 then pkgs.grub + else pkgs.grub2.override { zfsSupport = cfg.zfsSupport; }; grub = # Don't include GRUB if we're only generating a GRUB menu (e.g., @@ -25,11 +26,12 @@ let inherit (cfg) version extraConfig extraPerEntryConfig extraEntries extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels timeout - default devices explicitBootRoot; + default devices fsIdentifier; path = (makeSearchPath "bin" [ - pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils + pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.findutils pkgs.diffutils pkgs.btrfsProgs + pkgs.utillinux ]) + ":" + (makeSearchPath "sbin" [ - pkgs.mdadm + pkgs.mdadm pkgs.utillinux ]); }); @@ -209,12 +211,26 @@ in ''; }; - explicitBootRoot = mkOption { - default = ""; - type = types.str; + fsIdentifier = mkOption { + default = "uuid"; + type = types.addCheck types.str + (type: type == "uuid" || type == "label" || type == "provided"); description = '' - The relative path of /boot within the parent volume. Leave empty - if /boot is not a btrfs subvolume. + Determines how grub will identify devices when generating the + configuration file. A value of uuid / label signifies that grub + will always resolve the uuid or label of the device before using + it in the configuration. A value of provided means that grub will + use the device name as show in <command>df</command> or + <command>mount</command>. Note, zfs zpools / datasets are ignored + and will always be mounted using their labels. + ''; + }; + + zfsSupport = mkOption { + default = false; + type = types.bool; + description = '' + Whether grub should be build against libzfs. ''; }; @@ -260,6 +276,9 @@ in ${pkgs.coreutils}/bin/cp -pf "${v}" "/boot/${n}" '') config.boot.loader.grub.extraFiles); + assertions = [{ assertion = !cfg.zfsSupport || cfg.version == 2; + message = "Only grub version 2 provides zfs support";}]; + }) ]; diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl index c3aa8518b8b..2dad8b36db3 100644 --- a/nixos/modules/system/boot/loader/grub/install-grub.pl +++ b/nixos/modules/system/boot/loader/grub/install-grub.pl @@ -1,5 +1,6 @@ use strict; use warnings; +use Class::Struct; use XML::LibXML; use File::Basename; use File::Path; @@ -27,6 +28,14 @@ sub writeFile { close FILE or die; } +sub runCommand { + my ($cmd) = @_; + open FILE, "$cmd 2>/dev/null |" or die "Failed to execute: $cmd\n"; + my @ret = <FILE>; + close FILE; + return ($?, @ret); +} + my $grub = get("grub"); my $grubVersion = int(get("version")); my $extraConfig = get("extraConfig"); @@ -39,7 +48,7 @@ my $configurationLimit = int(get("configurationLimit")); my $copyKernels = get("copyKernels") eq "true"; my $timeout = int(get("timeout")); my $defaultEntry = int(get("default")); -my $explicitBootRoot = get("explicitBootRoot"); +my $fsIdentifier = get("fsIdentifier"); $ENV{'PATH'} = get("path"); die "unsupported GRUB version\n" if $grubVersion != 1 && $grubVersion != 2; @@ -48,24 +57,114 @@ print STDERR "updating GRUB $grubVersion menu...\n"; mkpath("/boot/grub", 0, 0700); - # Discover whether /boot is on the same filesystem as / and # /nix/store. If not, then all kernels and initrds must be copied to -# /boot, and all paths in the GRUB config file must be relative to the -# root of the /boot filesystem. `$bootRoot' is the path to be -# prepended to paths under /boot. -my $bootRoot = "/boot"; -if (stat("/")->dev != stat("/boot")->dev) { - $bootRoot = ""; - $copyKernels = 1; -} elsif (stat("/boot")->dev != stat("/nix/store")->dev) { +# /boot. +if (stat("/boot")->dev != stat("/nix/store")->dev) { $copyKernels = 1; } -if ($explicitBootRoot ne "") { - $bootRoot = $explicitBootRoot; +# Discover information about the location of /boot +struct(Fs => { + device => '$', + type => '$', + mount => '$', +}); +sub GetFs { + my ($dir) = @_; + my ($status, @dfOut) = runCommand("df -T $dir"); + if ($status != 0 || $#dfOut != 1) { + die "Failed to retrieve output about $dir from `df`"; + } + my @boot = split(/[ \n\t]+/, $dfOut[1]); + return Fs->new(device => $boot[0], type => $boot[1], mount => $boot[6]); } - +struct (Grub => { + path => '$', + search => '$', +}); +my $driveid = 1; +sub GrubFs { + my ($dir) = @_; + my $fs = GetFs($dir); + my $path = "/" . substr($dir, length($fs->mount)); + my $search = ""; + + if ($grubVersion > 1) { + # ZFS is completely separate logic as zpools are always identified by a label + # or custom UUID + if ($fs->type eq 'zfs') { + my $sid = index($fs->device, '/'); + + if ($sid < 0) { + $search = '--label ' . $fs->device; + $path = '/@' . $path; + } else { + $search = '--label ' . substr($fs->device, 0, $sid); + $path = '/' . substr($fs->device, $sid) . '/@' . $path; + } + } else { + my %types = ('uuid' => '--fs-uuid', 'label' => '--label'); + + if ($fsIdentifier eq 'provided') { + # If the provided dev is identifying the partition using a label or uuid, + # we should get the label / uuid and do a proper search + my @matches = $fs->device =~ m/\/dev\/disk\/by-(label|uuid)\/(.*)/; + if ($#matches > 1) { + die "Too many matched devices" + } elsif ($#matches == 1) { + $search = "$types{$matches[0]} $matches[1]" + } + } else { + # Determine the identifying type + $search = $types{$fsIdentifier} . ' '; + + # Based on the type pull in the identifier from the system + my ($status, @devInfo) = runCommand("blkid -o export @{[$fs->device]}"); + if ($status != 0) { + die "Failed to get blkid info for @{[$fs->mount]} on @{[$fs->device]}"; + } + my @matches = join("", @devInfo) =~ m/@{[uc $fsIdentifier]}=([^\n]*)/; + if ($#matches != 0) { + die "Couldn't find a $types{$fsIdentifier} for @{[$fs->device]}\n" + } + $search .= $matches[0]; + } + + # BTRFS is a special case in that we need to fix the referrenced path based on subvolumes + if ($fs->type eq 'btrfs') { + my ($status, @id_info) = runCommand("btrfs subvol show @{[$fs->mount]}"); + if ($status != 0) { + die "Failed to retrieve subvolume info for @{[$fs->mount]}\n"; + } + my @ids = join("", @id_info) =~ m/Object ID:[ \t\n]*([^ \t\n]*)/; + if ($#ids > 0) { + die "Btrfs subvol name for @{[$fs->device]} listed multiple times in mount\n" + } elsif ($#ids == 0) { + my ($status, @path_info) = runCommand("btrfs subvol list @{[$fs->mount]}"); + if ($status != 0) { + die "Failed to find @{[$fs->mount]} subvolume id from btrfs\n"; + } + my @paths = join("", @path_info) =~ m/ID $ids[0] [^\n]* path ([^\n]*)/; + if ($#paths > 0) { + die "Btrfs returned multiple paths for a single subvolume id, mountpoint @{[$fs->mount]}\n"; + } elsif ($#paths != 0) { + die "Btrfs did not return a path for the subvolume at @{[$fs->mount]}\n"; + } + $path = "/$paths[0]$path"; + } + } + } + if (not $search eq "") { + $search = "search --set=drive$driveid " . $search; + $path = "(\$drive$driveid)$path"; + $driveid += 1; + } + } + return Grub->new(path => $path, search => $search); +} +my $grubBoot = GrubFs("/boot"); +my $grubStore = GrubFs("/nix/store"); # Generate the header. my $conf .= "# Automatically generated. DO NOT EDIT THIS FILE!\n"; @@ -77,12 +176,17 @@ if ($grubVersion == 1) { "; if ($splashImage) { copy $splashImage, "/boot/background.xpm.gz" or die "cannot copy $splashImage to /boot\n"; - $conf .= "splashimage $bootRoot/background.xpm.gz\n"; + $conf .= "splashimage " . $grubBoot->path . "/background.xpm.gz\n"; } } else { + if ($copyKernels == 0) { + $conf .= " + " . $grubStore->search; + } $conf .= " + " . $grubBoot->search . " if [ -s \$prefix/grubenv ]; then load_env fi @@ -103,7 +207,7 @@ else { set timeout=$timeout fi - if loadfont $bootRoot/grub/fonts/unicode.pf2; then + if loadfont " . $grubBoot->path . "/grub/fonts/unicode.pf2; then set gfxmode=640x480 insmod gfxterm insmod vbe @@ -117,7 +221,7 @@ else { copy $splashImage, "/boot/background.png" or die "cannot copy $splashImage to /boot\n"; $conf .= " insmod png - if background_image $bootRoot/background.png; then + if background_image " . $grubBoot->path . "/background.png; then set color_normal=white/black set color_highlight=black/white else @@ -139,7 +243,7 @@ mkpath("/boot/kernels", 0, 0755) if $copyKernels; sub copyToKernelsDir { my ($path) = @_; - return $path unless $copyKernels; + return $grubStore->path . substr($path, length("/nix/store")) unless $copyKernels; $path =~ /\/nix\/store\/(.*)/ or die; my $name = $1; $name =~ s/\//-/g; my $dst = "/boot/kernels/$name"; @@ -152,7 +256,7 @@ sub copyToKernelsDir { rename $tmp, $dst or die "cannot rename $tmp to $dst\n"; } $copied{$dst} = 1; - return "$bootRoot/kernels/$name"; + return $grubBoot->path . "/kernels/$name"; } sub addEntry { @@ -179,6 +283,10 @@ sub addEntry { $conf .= " " . ($xen ? "module" : "initrd") . " $initrd\n\n"; } else { $conf .= "menuentry \"$name\" {\n"; + $conf .= $grubBoot->search . "\n"; + if ($copyKernels == 0) { + $conf .= $grubStore->search . "\n"; + } $conf .= " $extraPerEntryConfig\n" if $extraPerEntryConfig; $conf .= " multiboot $xen $xenParams\n" if $xen; $conf .= " " . ($xen ? "module" : "linux") . " $kernel $kernelParams\n"; @@ -196,7 +304,7 @@ addEntry("NixOS - Default", $defaultConfig); $conf .= "$extraEntries\n" unless $extraEntriesBeforeNixOS; # extraEntries could refer to @bootRoot@, which we have to substitute -$conf =~ s/\@bootRoot\@/$bootRoot/g; +$conf =~ s/\@bootRoot\@/$grubBoot->path/g; # Emit submenus for all system profiles. sub addProfile { diff --git a/nixos/modules/system/boot/loader/gummiboot/gummiboot.nix b/nixos/modules/system/boot/loader/gummiboot/gummiboot.nix index e7a481e90a7..003f72b37f9 100644 --- a/nixos/modules/system/boot/loader/gummiboot/gummiboot.nix +++ b/nixos/modules/system/boot/loader/gummiboot/gummiboot.nix @@ -16,7 +16,7 @@ let nix = config.nix.package; - inherit (cfg) timeout; + timeout = if cfg.timeout != null then cfg.timeout else ""; inherit (efi) efiSysMountPoint canTouchEfiVariables; }; diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix index c923cc49c44..70ff1d588a3 100644 --- a/nixos/modules/system/boot/luksroot.nix +++ b/nixos/modules/system/boot/luksroot.nix @@ -342,40 +342,39 @@ in description = "Path where the ramfs used to update the LUKS key will be mounted in stage-1"; }; - storage = mkOption { - type = types.optionSet; - description = "Options related to the storing the salt"; - - options = { - device = mkOption { - default = /dev/sda1; - type = types.path; - description = '' - An unencrypted device that will temporarily be mounted in stage-1. - Must contain the current salt to create the challenge for this LUKS device. - ''; - }; - - fsType = mkOption { - default = "vfat"; - type = types.string; - description = "The filesystem of the unencrypted device"; - }; - - mountPoint = mkOption { - default = "/crypt-storage"; - type = types.string; - description = "Path where the unencrypted device will be mounted in stage-1"; - }; - - path = mkOption { - default = "/crypt-storage/default"; - type = types.string; - description = '' - Absolute path of the salt on the unencrypted device with - that device's root directory as "/". - ''; - }; + /* TODO: Add to the documentation of the current module: + + Options related to the storing the salt. + */ + storage = { + device = mkOption { + default = "/dev/sda1"; + type = types.path; + description = '' + An unencrypted device that will temporarily be mounted in stage-1. + Must contain the current salt to create the challenge for this LUKS device. + ''; + }; + + fsType = mkOption { + default = "vfat"; + type = types.string; + description = "The filesystem of the unencrypted device"; + }; + + mountPoint = mkOption { + default = "/crypt-storage"; + type = types.string; + description = "Path where the unencrypted device will be mounted in stage-1"; + }; + + path = mkOption { + default = "/crypt-storage/default"; + type = types.string; + description = '' + Absolute path of the salt on the unencrypted device with + that device's root directory as "/". + ''; }; }; }; diff --git a/nixos/modules/system/boot/modprobe.nix b/nixos/modules/system/boot/modprobe.nix index 652eb046f50..eaf8cf1ecd6 100644 --- a/nixos/modules/system/boot/modprobe.nix +++ b/nixos/modules/system/boot/modprobe.nix @@ -77,6 +77,11 @@ with lib; '')} ${config.boot.extraModprobeConfig} ''; + environment.etc."modprobe.d/usb-load-ehci-first.conf".text = + '' + softdep uhci_hcd pre: ehci_hcd + softdep ohci_hcd pre: ehci_hcd + ''; environment.systemPackages = [ config.system.sbin.modprobe pkgs.kmod ]; diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index 6a069c5d054..426da778f43 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -199,6 +199,18 @@ let { object = pkgs.writeText "mdadm.conf" config.boot.initrd.mdadmConf; symlink = "/etc/mdadm.conf"; } + { object = pkgs.stdenv.mkDerivation { + name = "initrd-kmod-blacklist-ubuntu"; + builder = pkgs.writeText "builder.sh" '' + source $stdenv/setup + target=$out + + ${pkgs.perl}/bin/perl -0pe 's/## file: iwlwifi.conf(.+?)##/##/s;' $src > $out + ''; + src = "${pkgs.kmod-blacklist-ubuntu}/modprobe.conf"; + }; + symlink = "/etc/modprobe.d/ubuntu.conf"; + } ]; }; diff --git a/nixos/modules/system/boot/stage-2-init.sh b/nixos/modules/system/boot/stage-2-init.sh index fcefdfa88a3..6fff776f858 100644 --- a/nixos/modules/system/boot/stage-2-init.sh +++ b/nixos/modules/system/boot/stage-2-init.sh @@ -29,7 +29,9 @@ setPath "@path@" # Normally, stage 1 mounts the root filesystem read/writable. # However, in some environments, stage 2 is executed directly, and the # root is read-only. So make it writable here. -mount -n -o remount,rw none / +if [ "$container" != systemd-nspawn ]; then + mount -n -o remount,rw none / +fi # Likewise, stage 1 mounts /proc, /dev and /sys, so if we don't have a diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 455c40693b0..e353e9246b0 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -744,7 +744,7 @@ in # Make all journals readable to users in the wheel and adm # groups, in addition to those in the systemd-journal group. # Users can always read their own journals. - ${pkgs.acl}/bin/setfacl -nm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal + ${pkgs.acl}/bin/setfacl -nm g:wheel:rx,d:g:wheel:rx,g:adm:rx,d:g:adm:rx /var/log/journal || true ''; # Target for ‘charon send-keys’ to hook into. diff --git a/nixos/modules/tasks/cpu-freq.nix b/nixos/modules/tasks/cpu-freq.nix index a8c63c13428..70bbee8474e 100644 --- a/nixos/modules/tasks/cpu-freq.nix +++ b/nixos/modules/tasks/cpu-freq.nix @@ -30,9 +30,7 @@ in config = mkIf (!config.boot.isContainer && config.powerManagement.cpuFreqGovernor != null) { - boot.kernelModules = [ "acpi-cpufreq" "speedstep-lib" "pcc-cpufreq" - "cpufreq_${cfg.cpuFreqGovernor}" - ]; + boot.kernelModules = [ "cpufreq_${cfg.cpuFreqGovernor}" ]; environment.systemPackages = [ cpupower ]; diff --git a/nixos/modules/tasks/filesystems/nfs.nix b/nixos/modules/tasks/filesystems/nfs.nix index e8c3d8ab56d..c902b9e0790 100644 --- a/nixos/modules/tasks/filesystems/nfs.nix +++ b/nixos/modules/tasks/filesystems/nfs.nix @@ -24,13 +24,37 @@ let Method = nsswitch ''; + cfg = config.services.nfs; + in { + ###### interface + + options = { + + services.nfs = { + statdPort = mkOption { + default = null; + example = 4000; + description = '' + Use fixed port for rpc.statd, usefull if NFS server is behind firewall. + ''; + }; + lockdPort = mkOption { + default = null; + example = 4001; + description = '' + Use fixed port for NFS lock manager kernel module (lockd/nlockmgr), + usefull if NFS server is behind firewall. + ''; + }; + }; + }; ###### implementation - config = mkIf (any (fs: fs == "nfs" || fs == "nfs4") config.boot.supportedFilesystems) { + config = mkIf (any (fs: fs == "nfs" || fs == "nfs4") config.boot.supportedFilesystems) ({ services.rpcbind.enable = true; @@ -60,7 +84,10 @@ in ''; serviceConfig.Type = "forking"; - serviceConfig.ExecStart = "@${pkgs.nfsUtils}/sbin/rpc.statd rpc.statd --no-notify"; + serviceConfig.ExecStart = '' + @${pkgs.nfsUtils}/sbin/rpc.statd rpc.statd --no-notify \ + ${if cfg.statdPort != null then "-p ${toString statdPort}" else ""} + ''; serviceConfig.Restart = "always"; }; @@ -90,5 +117,9 @@ in serviceConfig.Restart = "always"; }; - }; + } // mkIf (cfg.lockdPort != null) { + boot.extraModprobeConfig = '' + options lockd nlm_udpport=${toString cfg.lockdPort} nlm_tcpport=${toString cfg.lockdPort} + ''; + }); } diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix index d7deb44c407..1c4bbc16b49 100644 --- a/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixos/modules/tasks/filesystems/zfs.nix @@ -133,7 +133,7 @@ in }; boot.initrd = mkIf inInitrd { - kernelModules = [ "spl" "zfs" ] ; + kernelModules = [ "spl" "zfs" ]; extraUtilsCommands = '' cp -v ${zfsPkg}/sbin/zfs $out/bin @@ -148,6 +148,10 @@ in ''; }; + boot.loader.grub = mkIf inInitrd { + zfsSupport = true; + }; + systemd.services."zpool-import" = { description = "Import zpools"; after = [ "systemd-udev-settle.service" ]; diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index 991f9f26145..868039177d8 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -1,14 +1,40 @@ -{ config, lib, pkgs, ... }: +{ config, lib, pkgs, utils, ... }: with lib; +with utils; let cfg = config.networking; interfaces = attrValues cfg.interfaces; hasVirtuals = any (i: i.virtual) interfaces; + hasSits = cfg.sits != { }; hasBonds = cfg.bonds != { }; + # We must escape interfaces due to the systemd interpretation + subsystemDevice = interface: + "sys-subsystem-net-devices-${escapeSystemdPath interface}.device"; + + addrOpts = v: + assert v == 4 || v == 6; + { + address = mkOption { + type = types.str; + description = '' + IPv${toString v} address of the interface. Leave empty to configure the + interface using DHCP. + ''; + }; + + prefixLength = mkOption { + type = types.addCheck types.int (n: n >= 0 && n <= (if v == 4 then 32 else 128)); + description = '' + Subnet mask of the interface, specified as the number of + bits in the prefix (<literal>${if v == 4 then "24" else "64"}</literal>). + ''; + }; + }; + interfaceOpts = { name, ... }: { options = { @@ -19,10 +45,36 @@ let description = "Name of the interface."; }; + ip4 = mkOption { + default = [ ]; + example = [ + { address = "10.0.0.1"; prefixLength = 16; } + { address = "192.168.1.1"; prefixLength = 24; } + ]; + type = types.listOf types.optionSet; + options = addrOpts 4; + description = '' + List of IPv4 addresses that will be statically assigned to the interface. + ''; + }; + + ip6 = mkOption { + default = [ ]; + example = [ + { address = "fdfd:b3f0:482::1"; prefixLength = 48; } + { address = "2001:1470:fffd:2098::e006"; prefixLength = 64; } + ]; + type = types.listOf types.optionSet; + options = addrOpts 6; + description = '' + List of IPv6 addresses that will be statically assigned to the interface. + ''; + }; + ipAddress = mkOption { default = null; example = "10.0.0.1"; - type = types.nullOr (types.str); + type = types.nullOr types.str; description = '' IP address of the interface. Leave empty to configure the interface using DHCP. @@ -40,20 +92,16 @@ let }; subnetMask = mkOption { - default = ""; - example = "255.255.255.0"; - type = types.str; + default = null; description = '' - Subnet mask of the interface, specified as a bitmask. - This is deprecated; use <option>prefixLength</option> - instead. + Defunct, supply the prefix length instead. ''; }; ipv6Address = mkOption { default = null; example = "2001:1470:fffd:2098::e006"; - type = types.nullOr types.string; + type = types.nullOr types.str; description = '' IPv6 address of the interface. Leave empty to configure the interface using NDP. @@ -95,8 +143,6 @@ let Whether this interface is virtual and should be created by tunctl. This is mainly useful for creating bridges between a host a virtual network such as VPN or a virtual machine. - - Defaults to tap device, unless interface contains "tun" in its name. ''; }; @@ -108,6 +154,15 @@ let ''; }; + virtualType = mkOption { + default = null; + type = types.nullOr (types.addCheck types.str (v: v == "tun" || v == "tap")); + description = '' + The explicit type of interface to create. Accepts tun or tap strings. + Also accepts null to implicitly detect the type of device. + ''; + }; + proxyARP = mkOption { default = false; type = types.bool; @@ -223,10 +278,10 @@ in networking.interfaces = mkOption { default = {}; example = - { eth0 = { - ipAddress = "131.211.84.78"; - subnetMask = "255.255.255.128"; - }; + { eth0.ip4 = [ { + address = "131.211.84.78"; + prefixLength = 25; + } ]; }; description = '' The configuration for each network interface. If @@ -321,6 +376,66 @@ in }; }; + networking.sits = mkOption { + type = types.attrsOf types.optionSet; + default = { }; + example = { + hurricane = { + remote = "10.0.0.1"; + local = "10.0.0.22"; + ttl = 255; + }; + msipv6 = { + remote = "192.168.0.1"; + dev = "enp3s0"; + ttl = 127; + }; + }; + description = '' + This option allows you to define 6-to-4 interfaces which should be automatically created. + ''; + options = { + + remote = mkOption { + type = types.nullOr types.str; + default = null; + example = "10.0.0.1"; + description = '' + The address of the remote endpoint to forward traffic over. + ''; + }; + + local = mkOption { + type = types.nullOr types.str; + default = null; + example = "10.0.0.22"; + description = '' + The address of the local endpoint which the remote + side should send packets to. + ''; + }; + + ttl = mkOption { + type = types.nullOr types.int; + default = null; + example = 255; + description = '' + The time-to-live of the connection to the remote tunnel endpoint. + ''; + }; + + dev = mkOption { + type = types.nullOr types.str; + default = null; + example = "enp4s0f0"; + description = '' + The underlying network device on which the tunnel resides. + ''; + }; + + }; + }; + networking.vlans = mkOption { default = { }; example = { @@ -377,9 +492,16 @@ in config = { + assertions = + flip map interfaces (i: { + assertion = i.subnetMask == null; + message = "The networking.interfaces.${i.name}.subnetMask option is defunct. Use prefixLength instead."; + }); + boot.kernelModules = [ ] ++ optional cfg.enableIPv6 "ipv6" ++ optional hasVirtuals "tun" + ++ optional hasSits "sit" ++ optional hasBonds "bonding"; boot.extraModprobeConfig = @@ -472,16 +594,22 @@ in # network device, so it only gets started after the interface # has appeared, and it's stopped when the interface # disappears. - configureInterface = i: nameValuePair "${i.name}-cfg" - (let mask = - if i.prefixLength != null then toString i.prefixLength else - if i.subnetMask != "" then i.subnetMask else "32"; - staticIPv6 = cfg.enableIPv6 && i.ipv6Address != null; + configureInterface = i: + let + ips = i.ip4 ++ optionals cfg.enableIPv6 i.ip6 + ++ optional (i.ipAddress != null) { + address = i.ipAddress; + prefixLength = i.prefixLength; + } ++ optional (cfg.enableIPv6 && i.ipv6Address != null) { + address = i.ipv6Address; + prefixLength = i.ipv6PrefixLength; + }; in + nameValuePair "${i.name}-cfg" { description = "Configuration of ${i.name}"; wantedBy = [ "network-interfaces.target" ]; - bindsTo = [ "sys-subsystem-net-devices-${i.name}.device" ]; - after = [ "sys-subsystem-net-devices-${i.name}.device" ]; + bindsTo = [ (subsystemDevice i.name) ]; + after = [ (subsystemDevice i.name) ]; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; path = [ pkgs.iproute pkgs.gawk ]; @@ -500,36 +628,32 @@ in echo "setting MTU to ${toString i.mtu}..." ip link set "${i.name}" mtu "${toString i.mtu}" '' - + optionalString (i.ipAddress != null) + + # Ip Setup + + '' - cur=$(ip -4 -o a show dev "${i.name}" | awk '{print $4}') - # Only do a flush/add if it's necessary. This is + curIps=$(ip -o a show dev "${i.name}" | awk '{print $4}') + # Only do an add if it's necessary. This is # useful when the Nix store is accessed via this # interface (e.g. in a QEMU VM test). - if [ "$cur" != "${i.ipAddress}/${mask}" ]; then - echo "configuring interface..." - ip -4 addr flush dev "${i.name}" - ip -4 addr add "${i.ipAddress}/${mask}" dev "${i.name}" - restart_network_setup=true - else - echo "skipping configuring interface" - fi '' - + optionalString (staticIPv6) + + flip concatMapStrings (ips) (ip: + let + address = "${ip.address}/${toString ip.prefixLength}"; + in '' - # Only do a flush/add if it's necessary. This is - # useful when the Nix store is accessed via this - # interface (e.g. in a QEMU VM test). - if ! ip -6 -o a show dev "${i.name}" | grep "${i.ipv6Address}/${toString i.ipv6prefixLength}"; then - echo "configuring interface..." - ip -6 addr flush dev "${i.name}" - ip -6 addr add "${i.ipv6Address}/${toString i.ipv6prefixLength}" dev "${i.name}" - restart_network_setup=true - else - echo "skipping configuring interface" + echo "checking ip ${address}..." + if ! echo "$curIps" | grep "${address}" >/dev/null 2>&1; then + if out=$(ip addr add "${address}" dev "${i.name}" 2>&1); then + echo "added ip ${address}..." + restart_network_setup=true + elif ! echo "$out" | grep "File exists" >/dev/null 2>&1; then + echo "failed to add ${address}" + exit 1 + fi fi - '' - + optionalString (i.ipAddress != null || staticIPv6) + '') + + optionalString (ips != [ ]) '' if [ restart_network_setup = true ]; then # Ensure that the default gateway remains set. @@ -546,28 +670,47 @@ in '' echo 1 > /proc/sys/net/ipv6/conf/${i.name}/proxy_ndp ''; - }); + preStop = + '' + echo "releasing configured ip's..." + '' + + flip concatMapStrings (ips) (ip: + let + address = "${ip.address}/${toString ip.prefixLength}"; + in + '' + echo -n "Deleting ${address}..." + ip addr del "${address}" dev "${i.name}" >/dev/null 2>&1 || echo -n " Failed" + echo "" + ''); + }; - createTunDevice = i: nameValuePair "${i.name}" + createTunDevice = i: nameValuePair "${i.name}-netdev" { description = "Virtual Network Interface ${i.name}"; requires = [ "dev-net-tun.device" ]; after = [ "dev-net-tun.device" ]; - wantedBy = [ "network.target" ]; - requiredBy = [ "sys-subsystem-net-devices-${i.name}.device" ]; - serviceConfig = - { Type = "oneshot"; - RemainAfterExit = true; - ExecStart = "${pkgs.tunctl}/bin/tunctl -t '${i.name}' -u '${i.virtualOwner}'"; - ExecStop = "${pkgs.tunctl}/bin/tunctl -d '${i.name}'"; - }; + wantedBy = [ "network.target" (subsystemDevice i.name) ]; + path = [ pkgs.iproute ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + script = '' + ip tuntap add dev "${i.name}" \ + ${optionalString (i.virtualType != null) "mode ${i.virtualType}"} \ + user "${i.virtualOwner}" + ''; + postStop = '' + ip link del ${i.name} + ''; }; - createBridgeDevice = n: v: - let - deps = map (i: "sys-subsystem-net-devices-${i}.device") v.interfaces; + createBridgeDevice = n: v: nameValuePair "${n}-netdev" + (let + deps = map subsystemDevice v.interfaces; in { description = "Bridge Interface ${n}"; - wantedBy = [ "network.target" "sys-subsystem-net-devices-${n}.device" ]; + wantedBy = [ "network.target" (subsystemDevice n) ]; bindsTo = deps; after = deps; serviceConfig.Type = "oneshot"; @@ -600,14 +743,14 @@ in ip link set "${n}" down brctl delbr "${n}" ''; - }; + }); - createBondDevice = n: v: - let - deps = map (i: "sys-subsystem-net-devices-${i}.device") v.interfaces; + createBondDevice = n: v: nameValuePair "${n}-netdev" + (let + deps = map subsystemDevice v.interfaces; in { description = "Bond Interface ${n}"; - wantedBy = [ "network.target" "sys-subsystem-net-devices-${n}.device" ]; + wantedBy = [ "network.target" (subsystemDevice n) ]; bindsTo = deps; after = deps; serviceConfig.Type = "oneshot"; @@ -639,14 +782,40 @@ in ifenslave -d "${n}" ip link delete "${n}" ''; - }; + }); - createVlanDevice = n: v: - let - deps = [ "sys-subsystem-net-devices-${v.interface}.device" ]; + createSitDevice = n: v: nameValuePair "${n}-netdev" + (let + deps = optional (v.dev != null) (subsystemDevice v.dev); + in + { description = "6-to-4 Tunnel Interface ${n}"; + wantedBy = [ "network.target" (subsystemDevice n) ]; + bindsTo = deps; + after = deps; + serviceConfig.Type = "oneshot"; + serviceConfig.RemainAfterExit = true; + path = [ pkgs.iproute ]; + script = '' + # Remove Dead Interfaces + ip link show "${n}" >/dev/null 2>&1 && ip link delete "${n}" + ip link add "${n}" type sit \ + ${optionalString (v.remote != null) "remote \"${v.remote}\""} \ + ${optionalString (v.local != null) "local \"${v.local}\""} \ + ${optionalString (v.ttl != null) "ttl ${toString v.ttl}"} \ + ${optionalString (v.dev != null) "dev \"${v.dev}\""} + ip link set "${n}" up + ''; + postStop = '' + ip link delete "${n}" + ''; + }); + + createVlanDevice = n: v: nameValuePair "${n}-netdev" + (let + deps = [ (subsystemDevice v.interface) ]; in { description = "Vlan Interface ${n}"; - wantedBy = [ "network.target" "sys-subsystem-net-devices-${n}.device" ]; + wantedBy = [ "network.target" (subsystemDevice n) ]; bindsTo = deps; after = deps; serviceConfig.Type = "oneshot"; @@ -661,14 +830,15 @@ in postStop = '' ip link delete "${n}" ''; - }; + }); in listToAttrs ( map configureInterface interfaces ++ map createTunDevice (filter (i: i.virtual) interfaces)) - // mapAttrs createBridgeDevice cfg.bridges - // mapAttrs createBondDevice cfg.bonds - // mapAttrs createVlanDevice cfg.vlans + // mapAttrs' createBridgeDevice cfg.bridges + // mapAttrs' createBondDevice cfg.bonds + // mapAttrs' createSitDevice cfg.sits + // mapAttrs' createVlanDevice cfg.vlans // { "network-setup" = networkSetup; }; # Set the host and domain names in the activation script. Don't diff --git a/nixos/modules/tasks/trackpoint.nix b/nixos/modules/tasks/trackpoint.nix index d1c6f8ac156..5d1bb631b54 100644 --- a/nixos/modules/tasks/trackpoint.nix +++ b/nixos/modules/tasks/trackpoint.nix @@ -36,6 +36,14 @@ with lib; configures 97. ''; }; + + emulateWheel = mkOption { + default = false; + type = types.bool; + description = '' + Enable scrolling while holding the middle mouse button. + ''; + }; }; @@ -44,17 +52,33 @@ with lib; ###### implementation - config = mkIf config.hardware.trackpoint.enable { - - services.udev.extraRules = - '' - ACTION=="add|change", SUBSYSTEM=="input", ATTR{name}=="TPPS/2 IBM TrackPoint", ATTR{device/speed}="${toString config.hardware.trackpoint.speed}", ATTR{device/sensitivity}="${toString config.hardware.trackpoint.sensitivity}" - ''; - - system.activationScripts.trackpoint = + config = mkMerge [ + (mkIf config.hardware.trackpoint.enable { + services.udev.extraRules = '' - ${config.systemd.package}/bin/udevadm trigger --attr-match=name="TPPS/2 IBM TrackPoint" + ACTION=="add|change", SUBSYSTEM=="input", ATTR{name}=="TPPS/2 IBM TrackPoint", ATTR{device/speed}="${toString config.hardware.trackpoint.speed}", ATTR{device/sensitivity}="${toString config.hardware.trackpoint.sensitivity}" ''; - }; + system.activationScripts.trackpoint = + '' + ${config.systemd.package}/bin/udevadm trigger --attr-match=name="TPPS/2 IBM TrackPoint" + ''; + }) + + (mkIf config.hardware.trackpoint.emulateWheel { + services.xserver.config = + '' + Section "InputClass" + Identifier "Trackpoint Wheel Emulation" + MatchProduct "TPPS/2 IBM TrackPoint|DualPoint Stick|Synaptics Inc. Composite TouchPad / TrackPoint|ThinkPad USB Keyboard with TrackPoint|USB Trackpoint pointing device|Composite TouchPad / TrackPoint" + MatchDevicePath "/dev/input/event*" + Option "EmulateWheel" "true" + Option "EmulateWheelButton" "2" + Option "Emulate3Buttons" "false" + Option "XAxisMapping" "6 7" + Option "YAxisMapping" "4 5" + EndSection + ''; + }) + ]; } diff --git a/nixos/modules/virtualisation/container-config.nix b/nixos/modules/virtualisation/container-config.nix index b81f97f2b4e..a7e8953827a 100644 --- a/nixos/modules/virtualisation/container-config.nix +++ b/nixos/modules/virtualisation/container-config.nix @@ -18,76 +18,7 @@ with lib; # Shut up warnings about not having a boot loader. system.build.installBootLoader = "${pkgs.coreutils}/bin/true"; - # Provide a root login prompt on /var/lib/root-login.socket that - # doesn't ask for a password. This socket can only be used by root - # on the host. - systemd.sockets.root-login = - { description = "Root Login Socket"; - wantedBy = [ "sockets.target" ]; - socketConfig = - { ListenStream = "/var/lib/root-login.socket"; - SocketMode = "0600"; - Accept = true; - }; - }; - - systemd.services."root-login@" = - { description = "Root Login %i"; - environment.TERM = "linux"; - serviceConfig = - { Type = "simple"; - StandardInput = "socket"; - ExecStart = "${pkgs.socat}/bin/socat -t0 - \"exec:${pkgs.shadow}/bin/login -f root,pty,setsid,setpgid,stderr,ctty\""; - TimeoutStopSec = 1; # FIXME - }; - restartIfChanged = false; - }; - - # Provide a daemon on /var/lib/run-command.socket that reads a - # command from stdin and executes it. - systemd.sockets.run-command = - { description = "Run Command Socket"; - wantedBy = [ "sockets.target" ]; - socketConfig = - { ListenStream = "/var/lib/run-command.socket"; - SocketMode = "0600"; # only root can connect - Accept = true; - }; - }; - - systemd.services."run-command@" = - { description = "Run Command %i"; - environment.TERM = "linux"; - serviceConfig = - { Type = "simple"; - StandardInput = "socket"; - TimeoutStopSec = 1; # FIXME - }; - script = - '' - #! ${pkgs.stdenv.shell} -e - source /etc/bashrc - read c - eval "command=($c)" - exec "''${command[@]}" - ''; - restartIfChanged = false; - }; - - systemd.services.container-startup-done = - { description = "Container Startup Notification"; - wantedBy = [ "multi-user.target" ]; - after = [ "multi-user.target" ]; - script = - '' - if [ -p /var/lib/startup-done ]; then - echo done > /var/lib/startup-done - fi - ''; - serviceConfig.Type = "oneshot"; - serviceConfig.RemainAfterExit = true; - restartIfChanged = false; - }; + systemd.services.systemd-remount-fs.enable = false; }; diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix index 7f545a9d303..d62340f2c79 100644 --- a/nixos/modules/virtualisation/containers.nix +++ b/nixos/modules/virtualisation/containers.nix @@ -10,7 +10,7 @@ let isExecutable = true; src = ./nixos-container.pl; perl = "${pkgs.perl}/bin/perl -I${pkgs.perlPackages.FileSlurp}/lib/perl5/site_perl"; - inherit (pkgs) socat; + inherit (pkgs) utillinux; }; # The container's init script, a small wrapper around the regular @@ -32,7 +32,10 @@ let fi fi - exec "$1" + # Start the regular stage 1 script, passing the bind-mounted + # notification socket from the host to allow the container + # systemd to signal readiness to the host systemd. + NOTIFY_SOCKET=/var/lib/private/host-notify exec "$1" ''; system = config.nixpkgs.system; @@ -168,17 +171,18 @@ in preStart = '' - mkdir -p -m 0755 $root/var/lib + # Clean up existing machined registration and interfaces. + machinectl terminate "$INSTANCE" 2> /dev/null || true - # Create a named pipe to get a signal when the container - # has finished booting. - rm -f $root/var/lib/startup-done - mkfifo -m 0600 $root/var/lib/startup-done + if [ "$PRIVATE_NETWORK" = 1 ]; then + ip link del dev "ve-$INSTANCE" 2> /dev/null || true + fi ''; script = '' mkdir -p -m 0755 "$root/etc" "$root/var/lib" + mkdir -p -m 0700 "$root/var/lib/private" if ! [ -e "$root/etc/os-release" ]; then touch "$root/etc/os-release" fi @@ -205,12 +209,16 @@ in fi ''} + # Run systemd-nspawn without startup notification (we'll + # wait for the container systemd to signal readiness). + EXIT_ON_REBOOT=1 NOTIFY_SOCKET= \ exec ${config.systemd.package}/bin/systemd-nspawn \ --keep-unit \ -M "$INSTANCE" -D "$root" $extraFlags \ --bind-ro=/nix/store \ --bind-ro=/nix/var/nix/db \ --bind-ro=/nix/var/nix/daemon-socket \ + --bind=/run/systemd/notify:/var/lib/private/host-notify \ --bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles" \ --bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots" \ --setenv PRIVATE_NETWORK="$PRIVATE_NETWORK" \ @@ -222,12 +230,6 @@ in postStart = '' - # This blocks until the container-startup-done service - # writes something to this pipe. FIXME: it also hangs - # until the start timeout expires if systemd-nspawn exits. - read x < $root/var/lib/startup-done - rm -f $root/var/lib/startup-done - if [ "$PRIVATE_NETWORK" = 1 ]; then ifaceHost=ve-$INSTANCE ip link set dev $ifaceHost up @@ -242,23 +244,41 @@ in preStop = '' - machinectl poweroff "$INSTANCE" + machinectl poweroff "$INSTANCE" || true ''; restartIfChanged = false; #reloadIfChanged = true; # FIXME - serviceConfig.ExecReload = pkgs.writeScript "reload-container" - '' - #! ${pkgs.stdenv.shell} -e - SYSTEM_PATH=/nix/var/nix/profiles/system - echo $SYSTEM_PATH/bin/switch-to-configuration test | \ - ${pkgs.socat}/bin/socat unix:$root/var/lib/run-command.socket - - ''; + serviceConfig = { + ExecReload = pkgs.writeScript "reload-container" + '' + #! ${pkgs.stdenv.shell} -e + ${nixos-container}/bin/nixos-container run "$INSTANCE" -- \ + bash --login -c "/nix/var/nix/profiles/system/bin/switch-to-configuration test" + ''; - serviceConfig.SyslogIdentifier = "container %i"; + SyslogIdentifier = "container %i"; - serviceConfig.EnvironmentFile = "-/etc/containers/%i.conf"; + EnvironmentFile = "-/etc/containers/%i.conf"; + + Type = "notify"; + + NotifyAccess = "all"; + + # Note that on reboot, systemd-nspawn returns 10, so this + # unit will be restarted. On poweroff, it returns 0, so the + # unit won't be restarted. + Restart = "on-failure"; + + # 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 + # (at least if we want remaining processes to be killed + # after the timeout). So send an ignored signal. + KillMode = "mixed"; + KillSignal = "WINCH"; + }; }; # Generate a configuration file in /etc/containers for each @@ -292,5 +312,30 @@ in environment.systemPackages = [ nixos-container ]; + # Start containers at boot time. + systemd.services.all-containers = + { description = "All Containers"; + + wantedBy = [ "multi-user.target" ]; + + unitConfig.ConditionDirectoryNotEmpty = "/etc/containers"; + + serviceConfig.Type = "oneshot"; + + script = + '' + res=0 + shopt -s nullglob + for i in /etc/containers/*.conf; do + AUTO_START= + source "$i" + if [ "$AUTO_START" = 1 ]; then + systemctl start "container@$(basename "$i" .conf).service" || res=1 + fi + done + exit $res + ''; # */ + }; + }; } diff --git a/nixos/modules/virtualisation/docker-image.nix b/nixos/modules/virtualisation/docker-image.nix new file mode 100644 index 00000000000..13b861dc988 --- /dev/null +++ b/nixos/modules/virtualisation/docker-image.nix @@ -0,0 +1,67 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + pkgs2storeContents = l : map (x: { object = x; symlink = "none"; }) l; + +in { + # Create the tarball + system.build.dockerImage = import ../../lib/make-system-tarball.nix { + inherit (pkgs) stdenv perl xz pathsFromGraph; + + contents = []; + extraArgs = "--owner=0"; + storeContents = [ + { object = config.system.build.toplevel + "/init"; + symlink = "/bin/init"; + } + ] ++ (pkgs2storeContents [ pkgs.stdenv ]); + }; + + boot.postBootCommands = + '' + # After booting, register the contents of the Nix store in the Nix + # database. + if [ -f /nix-path-registration ]; then + ${config.nix.package}/bin/nix-store --load-db < /nix-path-registration && + rm /nix-path-registration + fi + + # nixos-rebuild also requires a "system" profile and an + # /etc/NIXOS tag. + touch /etc/NIXOS + ${config.nix.package}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system + + # Set virtualisation to docker + echo "docker" > /run/systemd/container + ''; + + + # docker image config + require = [ + ../installer/cd-dvd/channel.nix + ../profiles/minimal.nix + ../profiles/clone-config.nix + ]; + + boot.isContainer = true; + + # Iptables do not work in docker + networking.firewall.enable = false; + + services.openssh.enable = true; + + # Socket activated ssh presents problem in docker + services.openssh.startWhenNeeded = false; + + # Allow the user to login as root without password + security.initialRootPassword = ""; + + # Some more help text. + services.mingetty.helpLine = + '' + + Log in as "root" with an empty password. + ''; +} diff --git a/nixos/modules/virtualisation/docker.nix b/nixos/modules/virtualisation/docker.nix index a0aa6135326..1ce066cdc73 100644 --- a/nixos/modules/virtualisation/docker.nix +++ b/nixos/modules/virtualisation/docker.nix @@ -59,6 +59,7 @@ in config = mkIf cfg.enable (mkMerge [ { environment.systemPackages = [ pkgs.docker ]; + users.extraGroups.docker.gid = config.ids.gids.docker; } (mkIf cfg.socketActivation { diff --git a/nixos/modules/virtualisation/libvirtd.nix b/nixos/modules/virtualisation/libvirtd.nix index d7d700d8841..318460f4c2c 100644 --- a/nixos/modules/virtualisation/libvirtd.nix +++ b/nixos/modules/virtualisation/libvirtd.nix @@ -7,6 +7,7 @@ with lib; let cfg = config.virtualisation.libvirtd; + vswitch = config.virtualisation.vswitch; configFile = pkgs.writeText "libvirtd.conf" '' unix_sock_group = "libvirtd" unix_sock_rw_perms = "0770" @@ -56,6 +57,20 @@ in ''; }; + virtualisation.libvirtd.onShutdown = + mkOption { + type = types.enum ["shutdown" "suspend" ]; + default = "suspend"; + description = + '' + When shutting down / restarting the host what method should + be used to gracefully halt the guests. Setting to "shutdown" + will cause an ACPI shutdown of each guest. "suspend" will + attempt to save the state of the guests ready to restore on boot. + ''; + }; + + }; @@ -73,12 +88,17 @@ in { description = "Libvirt Virtual Machine Management Daemon"; wantedBy = [ "multi-user.target" ]; - after = [ "systemd-udev-settle.service" ]; + after = [ "systemd-udev-settle.service" ] + ++ optional vswitch.enable "vswitchd.service"; - path = - [ pkgs.bridge_utils pkgs.dmidecode pkgs.dnsmasq + path = [ + pkgs.bridge_utils + pkgs.dmidecode + pkgs.dnsmasq pkgs.ebtables - ] ++ optional cfg.enableKVM pkgs.qemu_kvm; + ] + ++ optional cfg.enableKVM pkgs.qemu_kvm + ++ optional vswitch.enable vswitch.package; preStart = '' @@ -152,7 +172,12 @@ in ${pkgs.libvirt}/etc/rc.d/init.d/libvirt-guests start || true ''; - postStop = "${pkgs.libvirt}/etc/rc.d/init.d/libvirt-guests stop"; + postStop = + '' + export PATH=${pkgs.gettext}/bin:$PATH + export ON_SHUTDOWN=${cfg.onShutdown} + ${pkgs.libvirt}/etc/rc.d/init.d/libvirt-guests stop + ''; serviceConfig.Type = "oneshot"; serviceConfig.RemainAfterExit = true; diff --git a/nixos/modules/virtualisation/nixos-container.pl b/nixos/modules/virtualisation/nixos-container.pl index c6a5ecde9e3..7403a42f0f1 100644 --- a/nixos/modules/virtualisation/nixos-container.pl +++ b/nixos/modules/virtualisation/nixos-container.pl @@ -7,7 +7,7 @@ use File::Slurp; use Fcntl ':flock'; use Getopt::Long qw(:config gnu_getopt); -my $socat = '@socat@/bin/socat'; +my $nsenter = "@utillinux@/bin/nsenter"; # Ensure a consistent umask. umask 0022; @@ -17,25 +17,30 @@ umask 0022; sub showHelp { print <<EOF; Usage: nixos-container list - nixos-container create <container-name> [--config <string>] [--ensure-unique-name] + nixos-container create <container-name> [--system-path <path>] [--config <string>] [--ensure-unique-name] [--auto-start] nixos-container destroy <container-name> nixos-container start <container-name> nixos-container stop <container-name> + nixos-container status <container-name> nixos-container login <container-name> nixos-container root-login <container-name> nixos-container run <container-name> -- args... - nixos-container set-root-password <container-name> <password> nixos-container show-ip <container-name> + nixos-container show-host-key <container-name> EOF exit 0; } +my $systemPath; my $ensureUniqueName = 0; +my $autoStart = 0; my $extraConfig; GetOptions( "help" => sub { showHelp() }, "ensure-unique-name" => \$ensureUniqueName, + "auto-start" => \$autoStart, + "system-path=s" => \$systemPath, "config=s" => \$extraConfig ) or exit 1; @@ -122,17 +127,13 @@ if ($action eq "create") { push @conf, "PRIVATE_NETWORK=1\n"; push @conf, "HOST_ADDRESS=$hostAddress\n"; push @conf, "LOCAL_ADDRESS=$localAddress\n"; + push @conf, "AUTO_START=$autoStart\n"; write_file($confFile, \@conf); close($lock); print STDERR "host IP is $hostAddress, container IP is $localAddress\n"; - mkpath("$root/etc/nixos", 0, 0755); - - my $nixosConfigFile = "$root/etc/nixos/configuration.nix"; - writeNixOSConfig $nixosConfigFile; - # The per-container directory is restricted to prevent users on # the host from messing with guest users who happen to have the # same uid. @@ -141,10 +142,21 @@ if ($action eq "create") { $profileDir = "$profileDir/$containerName"; mkpath($profileDir, 0, 0755); - system("nix-env", "-p", "$profileDir/system", - "-I", "nixos-config=$nixosConfigFile", "-f", "<nixpkgs/nixos>", - "--set", "-A", "system") == 0 - or die "$0: failed to build initial container configuration\n"; + # Build/set the initial configuration. + if (defined $systemPath) { + system("nix-env", "-p", "$profileDir/system", "--set", $systemPath) == 0 + or die "$0: failed to set initial container configuration\n"; + } else { + mkpath("$root/etc/nixos", 0, 0755); + + my $nixosConfigFile = "$root/etc/nixos/configuration.nix"; + writeNixOSConfig $nixosConfigFile; + + system("nix-env", "-p", "$profileDir/system", + "-I", "nixos-config=$nixosConfigFile", "-f", "<nixpkgs/nixos>", + "--set", "-A", "system") == 0 + or die "$0: failed to build initial container configuration\n"; + } print "$containerName\n" if $ensureUniqueName; exit 0; @@ -155,7 +167,11 @@ my $profileDir = "/nix/var/nix/profiles/per-container/$containerName"; my $gcRootsDir = "/nix/var/nix/gcroots/per-container/$containerName"; my $confFile = "/etc/containers/$containerName.conf"; if (!-e $confFile) { - exit 0 if $action eq "destroy"; + if ($action eq "destroy") { + exit 0; + } elsif ($action eq "status") { + print "gone\n"; + } die "$0: container ‘$containerName’ does not exist\n" ; } @@ -169,6 +185,22 @@ sub stopContainer { or die "$0: failed to stop container\n"; } +# Return the PID of the init process of the container. +sub getLeader { + my $s = `machinectl show "$containerName" -p Leader`; + chomp $s; + $s =~ /^Leader=(\d+)$/ or die "unable to get container's main PID\n"; + return int($1); +} + +# Run a command in the container. +sub runInContainer { + my @args = @_; + my $leader = getLeader; + exec($nsenter, "-t", $leader, "-m", "-u", "-i", "-n", "-p", "--", @args); + die "cannot run ‘nsenter’: $!\n"; +} + if ($action eq "destroy") { die "$0: cannot destroy declarative container (remove it from your configuration.nix instead)\n" unless POSIX::access($confFile, &POSIX::W_OK); @@ -190,6 +222,10 @@ elsif ($action eq "stop") { stopContainer; } +elsif ($action eq "status") { + print isContainerRunning() ? "up" : "down", "\n"; +} + elsif ($action eq "update") { my $nixosConfigFile = "$root/etc/nixos/configuration.nix"; @@ -214,28 +250,14 @@ elsif ($action eq "login") { } elsif ($action eq "root-login") { - exec($socat, "unix:$root/var/lib/root-login.socket", "-,echo=0,raw"); + runInContainer("su", "root", "-l"); } elsif ($action eq "run") { shift @ARGV; shift @ARGV; - my $pid = open(SOCAT, "|-", $socat, "-t0", "-", "unix:$root/var/lib/run-command.socket") or die "$0: cannot start $socat: $!\n"; - print SOCAT join(' ', map { "'$_'" } @ARGV), "\n"; - flush SOCAT; - waitpid($pid, 0); - close(SOCAT); -} - -elsif ($action eq "set-root-password") { - # FIXME: don't get password from the command line. - my $password = $ARGV[2] or die "$0: no password given\n"; - my $pid = open(SOCAT, "|-", $socat, "-t0", "-", "unix:$root/var/lib/run-command.socket") or die "$0: cannot start $socat: $!\n"; - print SOCAT "passwd\n"; - print SOCAT "$password\n"; - print SOCAT "$password\n"; - flush SOCAT; - waitpid($pid, 0); - close(SOCAT); + # Escape command. + my $s = join(' ', map { s/'/'\\''/g; "'$_'" } @ARGV); + runInContainer("su", "root", "-l", "-c", "exec " . $s); } elsif ($action eq "show-ip") { @@ -244,6 +266,12 @@ elsif ($action eq "show-ip") { print "$1\n"; } +elsif ($action eq "show-host-key") { + my $fn = "$root/etc/ssh/ssh_host_ecdsa_key.pub"; + exit 1 if ! -f $fn; + print read_file($fn); +} + else { die "$0: unknown action ‘$action’\n"; } diff --git a/nixos/modules/virtualisation/openvswitch.nix b/nixos/modules/virtualisation/openvswitch.nix new file mode 100644 index 00000000000..c1579d94657 --- /dev/null +++ b/nixos/modules/virtualisation/openvswitch.nix @@ -0,0 +1,117 @@ +# Systemd services for openvswitch + +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.virtualisation.vswitch; + +in + +{ + + options = { + + virtualisation.vswitch.enable = mkOption { + type = types.bool; + default = false; + description = + '' + Enable Open vSwitch. A configuration + daemon (ovs-server) will be started. + ''; + }; + + + virtualisation.vswitch.package = mkOption { + type = types.package; + default = pkgs.openvswitch; + description = + '' + Open vSwitch package to use. + ''; + }; + + }; + + config = mkIf cfg.enable (let + + # Where the communication sockets live + runDir = "/var/run/openvswitch"; + + # Where the config database live (can't be in nix-store) + stateDir = "/var/db/openvswitch"; + + # The path to the an initialized version of the database + db = pkgs.stdenv.mkDerivation { + name = "vswitch.db"; + unpackPhase = "true"; + buildPhase = "true"; + buildInputs = with pkgs; [ + cfg.package + ]; + installPhase = + '' + ensureDir $out/ + ''; + }; + + in { + + environment.systemPackages = [ cfg.package ]; + + boot.kernelModules = [ "tun" "openvswitch" ]; + + boot.extraModulePackages = [ cfg.package ]; + + systemd.services.ovsdb = { + description = "Open_vSwitch Database Server"; + wantedBy = [ "multi-user.target" ]; + after = [ "systemd-udev-settle.service" ]; + wants = [ "vswitchd.service" ]; + path = [ cfg.package ]; + restartTriggers = [ db cfg.package ]; + # Create the config database + preStart = + '' + mkdir -p ${runDir} + mkdir -p /var/db/openvswitch + chmod +w /var/db/openvswitch + if [[ ! -e /var/db/openvswitch/conf.db ]]; then + ${cfg.package}/bin/ovsdb-tool create \ + "/var/db/openvswitch/conf.db" \ + "${cfg.package}/share/openvswitch/vswitch.ovsschema" + fi + chmod -R +w /var/db/openvswitch + ''; + serviceConfig.ExecStart = + '' + ${cfg.package}/bin/ovsdb-server \ + --remote=punix:${runDir}/db.sock \ + --private-key=db:Open_vSwitch,SSL,private_key \ + --certificate=db:Open_vSwitch,SSL,certificate \ + --bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert \ + --unixctl=ovsdb.ctl.sock \ + /var/db/openvswitch/conf.db + ''; + serviceConfig.Restart = "always"; + serviceConfig.RestartSec = 3; + postStart = + '' + ${cfg.package}/bin/ovs-vsctl --timeout 3 --retry --no-wait init + ''; + + }; + + systemd.services.vswitchd = { + description = "Open_vSwitch Daemon"; + bindsTo = [ "ovsdb.service" ]; + after = [ "ovsdb.service" ]; + path = [ cfg.package ]; + serviceConfig.ExecStart = ''${cfg.package}/bin/ovs-vswitchd''; + }; + + }); + +} diff --git a/nixos/release-combined.nix b/nixos/release-combined.nix index dae3b9210a8..0c72bae35bb 100644 --- a/nixos/release-combined.nix +++ b/nixos/release-combined.nix @@ -52,6 +52,11 @@ in rec { (all nixos.tests.installer.lvm) (all nixos.tests.installer.separateBoot) (all nixos.tests.installer.simple) + (all nixos.tests.installer.simpleLabels) + (all nixos.tests.installer.simpleProvided) + (all nixos.tests.installer.btrfsSimple) + (all nixos.tests.installer.btrfsSubvols) + (all nixos.tests.installer.btrfsSubvolDefault) (all nixos.tests.ipv6) (all nixos.tests.kde4) (all nixos.tests.login) diff --git a/nixos/release.nix b/nixos/release.nix index ed413d3e928..d4e1a3737e3 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -78,6 +78,16 @@ let }; + makeClosure = module: forAllSystems (system: (import ./lib/eval-config.nix { + inherit system; + modules = [ module ] ++ lib.singleton + ({ config, lib, ... }: + { fileSystems."/".device = lib.mkDefault "/dev/sda1"; + boot.loader.grub.device = lib.mkDefault "/dev/sda"; + }); + }).config.system.build.toplevel); + + in rec { channel = @@ -218,6 +228,11 @@ in rec { tests.installer.rebuildCD = forAllSystems (system: (import tests/installer.nix { inherit system; }).rebuildCD.test); tests.installer.separateBoot = forAllSystems (system: (import tests/installer.nix { inherit system; }).separateBoot.test); tests.installer.simple = forAllSystems (system: (import tests/installer.nix { inherit system; }).simple.test); + tests.installer.simpleLabels = forAllSystems (system: (import tests/installer.nix { inherit system; }).simpleLabels.test); + tests.installer.simpleProvided = forAllSystems (system: (import tests/installer.nix { inherit system; }).simpleProvided.test); + tests.installer.btrfsSimple = forAllSystems (system: (import tests/installer.nix { inherit system; }).btrfsSimple.test); + tests.installer.btrfsSubvols = forAllSystems (system: (import tests/installer.nix { inherit system; }).btrfsSubvols.test); + tests.installer.btrfsSubvolDefault = forAllSystems (system: (import tests/installer.nix { inherit system; }).btrfsSubvolDefault.test); tests.influxdb = callTest tests/influxdb.nix {}; tests.ipv6 = callTest tests/ipv6.nix {}; tests.jenkins = callTest tests/jenkins.nix {}; @@ -242,4 +257,46 @@ in rec { tests.udisks2 = callTest tests/udisks2.nix {}; tests.xfce = callTest tests/xfce.nix {}; + + /* Build a bunch of typical closures so that Hydra can keep track of + the evolution of closure sizes. */ + + closures = { + + smallContainer = makeClosure ({ pkgs, ... }: + { boot.isContainer = true; + services.openssh.enable = true; + }); + + tinyContainer = makeClosure ({ pkgs, ... }: + { boot.isContainer = true; + imports = [ modules/profiles/minimal.nix ]; + }); + + ec2 = makeClosure ({ pkgs, ... }: + { imports = [ modules/virtualisation/amazon-image.nix ]; + }); + + kde = makeClosure ({ pkgs, ... }: + { services.xserver.enable = true; + services.xserver.displayManager.kdm.enable = true; + services.xserver.desktopManager.kde4.enable = true; + }); + + xfce = makeClosure ({ pkgs, ... }: + { services.xserver.enable = true; + services.xserver.desktopManager.xfce.enable = true; + }); + + # Linux/Apache/PostgreSQL/PHP stack. + lapp = makeClosure ({ pkgs, ... }: + { services.httpd.enable = true; + services.httpd.adminAddr = "foo@example.org"; + services.postgresql.enable = true; + services.postgresql.package = pkgs.postgresql93; + environment.systemPackages = [ pkgs.php ]; + }); + + }; + } diff --git a/nixos/tests/bittorrent.nix b/nixos/tests/bittorrent.nix index 002e012f65f..b12a861f723 100644 --- a/nixos/tests/bittorrent.nix +++ b/nixos/tests/bittorrent.nix @@ -16,7 +16,7 @@ let miniupnpdConf = nodes: pkgs.writeText "miniupnpd.conf" '' ext_ifname=eth1 - listening_ip=${nodes.router.config.networking.interfaces.eth2.ipAddress}/24 + listening_ip=${(pkgs.lib.head nodes.router.config.networking.interfaces.eth2.ip4).address}/24 allow 1024-65535 192.168.2.0/24 1024-65535 ''; @@ -53,7 +53,7 @@ in { environment.systemPackages = [ pkgs.transmission ]; virtualisation.vlans = [ 2 ]; networking.defaultGateway = - nodes.router.config.networking.interfaces.eth2.ipAddress; + (pkgs.lib.head nodes.router.config.networking.interfaces.eth2.ip4).address; networking.firewall.enable = false; }; @@ -81,7 +81,7 @@ in # Create the torrent. $tracker->succeed("mkdir /tmp/data"); $tracker->succeed("cp ${file} /tmp/data/test.tar.bz2"); - $tracker->succeed("transmission-create /tmp/data/test.tar.bz2 -t http://${nodes.tracker.config.networking.interfaces.eth1.ipAddress}:6969/announce -o /tmp/test.torrent"); + $tracker->succeed("transmission-create /tmp/data/test.tar.bz2 -t http://${(pkgs.lib.head nodes.tracker.config.networking.interfaces.eth1.ip4).address}:6969/announce -o /tmp/test.torrent"); $tracker->succeed("chmod 644 /tmp/test.torrent"); # Start the tracker. !!! use a less crappy tracker diff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix index d3bbe7a8bd5..66ab2567e19 100644 --- a/nixos/tests/installer.nix +++ b/nixos/tests/installer.nix @@ -35,8 +35,8 @@ let # The configuration to install. - makeConfig = { testChannel, useEFI, grubVersion, grubDevice }: pkgs.writeText "configuration.nix" - '' + makeConfig = { testChannel, useEFI, grubVersion, grubDevice, grubIdentifier }: + pkgs.writeText "configuration.nix" '' { config, pkgs, modulesPath, ... }: { imports = @@ -54,6 +54,7 @@ let ''} boot.loader.grub.device = "${grubDevice}"; boot.loader.grub.extraConfig = "serial; terminal_output.serial"; + boot.loader.grub.fsIdentifier = "${grubIdentifier}"; ''} environment.systemPackages = [ ${optionalString testChannel "pkgs.rlwrap"} ]; @@ -93,12 +94,12 @@ let # disk, and then reboot from the hard disk. It's parameterized with # a test script fragment `createPartitions', which must create # partitions and filesystems. - testScriptFun = { createPartitions, testChannel, useEFI, grubVersion, grubDevice }: + testScriptFun = { createPartitions, testChannel, useEFI, grubVersion, grubDevice, grubIdentifier }: let # FIXME: OVMF doesn't boot from virtio http://www.mail-archive.com/edk2-devel@lists.sourceforge.net/msg01501.html iface = if useEFI || grubVersion == 1 then "scsi" else "virtio"; qemuFlags = - (if iso.system == "x86_64-linux" then "-m 512 " else "-m 384 ") + + (if iso.system == "x86_64-linux" then "-m 768 " else "-m 512 ") + (optionalString (iso.system == "x86_64-linux") "-cpu kvm64 ") + (optionalString useEFI ''-L ${efiBios} -hda ''${\(Cwd::abs_path('harddisk'))} ''); hdFlags = optionalString (!useEFI) @@ -161,7 +162,7 @@ let $machine->succeed("cat /mnt/etc/nixos/hardware-configuration.nix >&2"); $machine->copyFileFromHost( - "${ makeConfig { inherit testChannel useEFI grubVersion grubDevice; } }", + "${ makeConfig { inherit testChannel useEFI grubVersion grubDevice grubIdentifier; } }", "/mnt/etc/nixos/configuration.nix"); # Perform the installation. @@ -216,13 +217,13 @@ let makeInstallerTest = name: - { createPartitions, testChannel ? false, useEFI ? false, grubVersion ? 2, grubDevice ? "/dev/vda" }: + { createPartitions, testChannel ? false, useEFI ? false, grubVersion ? 2, grubDevice ? "/dev/vda", grubIdentifier ? "uuid" }: makeTest { inherit iso; name = "installer-" + name; nodes = if testChannel then { inherit webserver; } else { }; testScript = testScriptFun { - inherit createPartitions testChannel useEFI grubVersion grubDevice; + inherit createPartitions testChannel useEFI grubVersion grubDevice grubIdentifier; }; }; @@ -394,4 +395,103 @@ in { $machine->shutdown; ''; }; + + # Test using labels to identify volumes in grub + simpleLabels = makeInstallerTest "simpleLabels" { + createPartitions = '' + $machine->succeed( + "sgdisk -Z /dev/vda", + "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda", + "mkswap /dev/vda2 -L swap", + "swapon -L swap", + "mkfs.ext4 -L root /dev/vda3", + "mount LABEL=root /mnt", + ); + ''; + grubIdentifier = "label"; + }; + + # Test using the provided disk name within grub + # TODO: Fix udev so the symlinks are unneeded in /dev/disks + simpleProvided = makeInstallerTest "simpleProvided" { + createPartitions = '' + my $UUID = "\$(blkid -s UUID -o value /dev/vda2)"; + $machine->succeed( + "sgdisk -Z /dev/vda", + "sgdisk -n 1:0:+1M -n 2:0:+100M -n 3:0:+1G -N 4 -t 1:ef02 -t 2:8300 -t 3:8200 -t 4:8300 -c 2:boot -c 4:root /dev/vda", + "mkswap /dev/vda3 -L swap", + "swapon -L swap", + "mkfs.ext4 -L boot /dev/vda2", + "mkfs.ext4 -L root /dev/vda4", + ); + $machine->execute("ln -s ../../vda2 /dev/disk/by-uuid/$UUID"); + $machine->execute("ln -s ../../vda4 /dev/disk/by-label/root"); + $machine->succeed( + "mount /dev/disk/by-label/root /mnt", + "mkdir /mnt/boot", + "mount /dev/disk/by-uuid/$UUID /mnt/boot" + ); + ''; + grubIdentifier = "provided"; + }; + + # Simple btrfs grub testing + btrfsSimple = makeInstallerTest "btrfsSimple" { + createPartitions = '' + $machine->succeed( + "sgdisk -Z /dev/vda", + "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda", + "mkswap /dev/vda2 -L swap", + "swapon -L swap", + "mkfs.btrfs -L root /dev/vda3", + "mount LABEL=root /mnt", + ); + ''; + }; + + # Test to see if we can detect /boot and /nix on subvolumes + btrfsSubvols = makeInstallerTest "btrfsSubvols" { + createPartitions = '' + $machine->succeed( + "sgdisk -Z /dev/vda", + "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda", + "mkswap /dev/vda2 -L swap", + "swapon -L swap", + "mkfs.btrfs -L root /dev/vda3", + "btrfs device scan", + "mount LABEL=root /mnt", + "btrfs subvol create /mnt/boot", + "btrfs subvol create /mnt/nixos", + "btrfs subvol create /mnt/nixos/default", + "umount /mnt", + "mount -o defaults,subvol=nixos/default LABEL=root /mnt", + "mkdir /mnt/boot", + "mount -o defaults,subvol=boot LABEL=root /mnt/boot", + ); + ''; + }; + + # Test to see if we can detect default and aux subvolumes correctly + btrfsSubvolDefault = makeInstallerTest "btrfsSubvolDefault" { + createPartitions = '' + $machine->succeed( + "sgdisk -Z /dev/vda", + "sgdisk -n 1:0:+1M -n 2:0:+1G -N 3 -t 1:ef02 -t 2:8200 -t 3:8300 -c 3:root /dev/vda", + "mkswap /dev/vda2 -L swap", + "swapon -L swap", + "mkfs.btrfs -L root /dev/vda3", + "btrfs device scan", + "mount LABEL=root /mnt", + "btrfs subvol create /mnt/badpath", + "btrfs subvol create /mnt/badpath/boot", + "btrfs subvol create /mnt/nixos", + "btrfs subvol set-default \$(btrfs subvol list /mnt | grep 'nixos' | awk '{print \$2}') /mnt", + "umount /mnt", + "mount -o defaults LABEL=root /mnt", + "mkdir -p /mnt/badpath/boot", # Help ensure the detection mechanism is actually looking up subvolumes + "mkdir /mnt/boot", + "mount -o defaults,subvol=badpath/boot LABEL=root /mnt/boot", + ); + ''; + }; } diff --git a/nixos/tests/nat.nix b/nixos/tests/nat.nix index 5fdcc0e97ca..87ed974edad 100644 --- a/nixos/tests/nat.nix +++ b/nixos/tests/nat.nix @@ -13,7 +13,7 @@ import ./make-test.nix { { virtualisation.vlans = [ 1 ]; networking.firewall.allowPing = true; networking.defaultGateway = - nodes.router.config.networking.interfaces.eth2.ipAddress; + (pkgs.lib.head nodes.router.config.networking.interfaces.eth2.ip4).address; }; router = diff --git a/nixos/tests/phabricator.nix b/nixos/tests/phabricator.nix index 53038474c91..0fe31f66502 100644 --- a/nixos/tests/phabricator.nix +++ b/nixos/tests/phabricator.nix @@ -32,9 +32,16 @@ import ./make-test.nix ({ pkgs, ... }: { }]; }; + phd = { + enable = true; + }; + mysql = { enable = true; package = pkgs.mysql; + extraOptions = '' + sql_mode=STRICT_ALL_TABLES + ''; }; }; |