diff options
author | Mikey Ariel <mariel@redhat.com> | 2014-08-24 19:18:18 +0200 |
---|---|---|
committer | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2014-08-26 19:03:49 +0200 |
commit | a099ca45054940b63b1615920de158ebafb25ea8 (patch) | |
tree | 52907df9dc996cbab14885c8eab72b473086126a /nixos/doc/manual/development | |
parent | 8707a070baca84d881a7e03e04a44374d8cc05e1 (diff) | |
download | nixlib-a099ca45054940b63b1615920de158ebafb25ea8.tar nixlib-a099ca45054940b63b1615920de158ebafb25ea8.tar.gz nixlib-a099ca45054940b63b1615920de158ebafb25ea8.tar.bz2 nixlib-a099ca45054940b63b1615920de158ebafb25ea8.tar.lz nixlib-a099ca45054940b63b1615920de158ebafb25ea8.tar.xz nixlib-a099ca45054940b63b1615920de158ebafb25ea8.tar.zst nixlib-a099ca45054940b63b1615920de158ebafb25ea8.zip |
Chunk NixOS manual
[Squashed commits to make git blame etc. more likely to work. -ED]
Diffstat (limited to 'nixos/doc/manual/development')
-rw-r--r-- | nixos/doc/manual/development/building-nixos.xml | 32 | ||||
-rw-r--r-- | nixos/doc/manual/development/building-parts.xml | 113 | ||||
-rw-r--r-- | nixos/doc/manual/development/development.xml | 20 | ||||
-rw-r--r-- | nixos/doc/manual/development/nixos-tests.xml | 19 | ||||
-rw-r--r-- | nixos/doc/manual/development/option-declarations.xml | 141 | ||||
-rw-r--r-- | nixos/doc/manual/development/option-def.xml | 112 | ||||
-rw-r--r-- | nixos/doc/manual/development/running-nixos-tests.xml | 77 | ||||
-rw-r--r-- | nixos/doc/manual/development/sources.xml | 95 | ||||
-rw-r--r-- | nixos/doc/manual/development/testing-installer.xml | 27 | ||||
-rw-r--r-- | nixos/doc/manual/development/writing-modules.xml | 175 | ||||
-rw-r--r-- | nixos/doc/manual/development/writing-nixos-tests.xml | 251 |
11 files changed, 1062 insertions, 0 deletions
diff --git a/nixos/doc/manual/development/building-nixos.xml b/nixos/doc/manual/development/building-nixos.xml new file mode 100644 index 000000000000..21c5bfe6a5b1 --- /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 000000000000..cb8dee039c8e --- /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 000000000000..747159c44270 --- /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 000000000000..a98da9933309 --- /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 000000000000..6d93dc5c0094 --- /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 000000000000..4e267ecfd1e3 --- /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 000000000000..d9be761eb01d --- /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 000000000000..992a07af9813 --- /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 000000000000..87e40e326171 --- /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 000000000000..9cf29e5dc57d --- /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 000000000000..bbb655eed2a6 --- /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 |