summary refs log tree commit diff
path: root/nixos/doc/manual/development
diff options
context:
space:
mode:
authorMikey Ariel <mariel@redhat.com>2014-08-24 19:18:18 +0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2014-08-26 19:03:49 +0200
commita099ca45054940b63b1615920de158ebafb25ea8 (patch)
tree52907df9dc996cbab14885c8eab72b473086126a /nixos/doc/manual/development
parent8707a070baca84d881a7e03e04a44374d8cc05e1 (diff)
downloadnixlib-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.xml32
-rw-r--r--nixos/doc/manual/development/building-parts.xml113
-rw-r--r--nixos/doc/manual/development/development.xml20
-rw-r--r--nixos/doc/manual/development/nixos-tests.xml19
-rw-r--r--nixos/doc/manual/development/option-declarations.xml141
-rw-r--r--nixos/doc/manual/development/option-def.xml112
-rw-r--r--nixos/doc/manual/development/running-nixos-tests.xml77
-rw-r--r--nixos/doc/manual/development/sources.xml95
-rw-r--r--nixos/doc/manual/development/testing-installer.xml27
-rw-r--r--nixos/doc/manual/development/writing-modules.xml175
-rw-r--r--nixos/doc/manual/development/writing-nixos-tests.xml251
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 '&lt;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
+&gt;
+</screen>
+
+You can then take any Perl statement, e.g.
+
+<screen>
+&gt; startAll
+&gt; $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