mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-27 17:33:09 +00:00
Merge the NixOS repository into Nixpkgs
This commit is contained in:
commit
2a537fb369
2
nixos/.gitignore
vendored
Normal file
2
nixos/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*~
|
||||
.version-suffix
|
1
nixos/.version
Normal file
1
nixos/.version
Normal file
@ -0,0 +1 @@
|
||||
13.09
|
18
nixos/COPYING
Normal file
18
nixos/COPYING
Normal file
@ -0,0 +1,18 @@
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
5
nixos/README
Normal file
5
nixos/README
Normal file
@ -0,0 +1,5 @@
|
||||
*** NixOS ***
|
||||
|
||||
NixOS is a Linux distribution based on the purely functional package
|
||||
management system Nix. More information can be found at
|
||||
http://nixos.org/nixos and in the manual in doc/manual.
|
44
nixos/default.nix
Normal file
44
nixos/default.nix
Normal file
@ -0,0 +1,44 @@
|
||||
{ configuration ? import ./lib/from-env.nix "NIXOS_CONFIG" <nixos-config>
|
||||
, system ? builtins.currentSystem
|
||||
, nixpkgs ? <nixpkgs>
|
||||
}:
|
||||
|
||||
let
|
||||
|
||||
eval = import ./lib/eval-config.nix {
|
||||
inherit system nixpkgs;
|
||||
modules = [ configuration ];
|
||||
};
|
||||
|
||||
inherit (eval) config pkgs;
|
||||
|
||||
# This is for `nixos-rebuild build-vm'.
|
||||
vmConfig = (import ./lib/eval-config.nix {
|
||||
inherit system nixpkgs;
|
||||
modules = [ configuration ./modules/virtualisation/qemu-vm.nix ];
|
||||
}).config;
|
||||
|
||||
# This is for `nixos-rebuild build-vm-with-bootloader'.
|
||||
vmWithBootLoaderConfig = (import ./lib/eval-config.nix {
|
||||
inherit system nixpkgs;
|
||||
modules =
|
||||
[ configuration
|
||||
./modules/virtualisation/qemu-vm.nix
|
||||
{ virtualisation.useBootLoader = true; }
|
||||
];
|
||||
}).config;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
inherit eval config;
|
||||
|
||||
system = config.system.build.toplevel;
|
||||
|
||||
vm = vmConfig.system.build.vm;
|
||||
|
||||
vmWithBootLoader = vmWithBootLoaderConfig.system.build.vm;
|
||||
|
||||
# The following are used by nixos-rebuild.
|
||||
nixFallback = pkgs.nixUnstable;
|
||||
}
|
21
nixos/doc/config-examples/basic.nix
Normal file
21
nixos/doc/config-examples/basic.nix
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
boot = {
|
||||
loader.grub.device = "/dev/sda";
|
||||
};
|
||||
|
||||
fileSystems = [
|
||||
{ mountPoint = "/";
|
||||
device = "/dev/sda1";
|
||||
}
|
||||
];
|
||||
|
||||
swapDevices = [
|
||||
{ device = "/dev/sdb1"; }
|
||||
];
|
||||
|
||||
services = {
|
||||
openssh = {
|
||||
enable = true;
|
||||
};
|
||||
};
|
||||
}
|
32
nixos/doc/config-examples/closed-install-configuration.nix
Normal file
32
nixos/doc/config-examples/closed-install-configuration.nix
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
27
nixos/doc/config-examples/root-on-lvm.nix
Normal file
27
nixos/doc/config-examples/root-on-lvm.nix
Normal file
@ -0,0 +1,27 @@
|
||||
# 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"; }
|
||||
];
|
||||
}
|
36
nixos/doc/config-examples/svn-server.nix
Normal file
36
nixos/doc/config-examples/svn-server.nix
Normal file
@ -0,0 +1,36 @@
|
||||
{
|
||||
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";
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
20
nixos/doc/config-examples/x86_64-usbstick.nix
Normal file
20
nixos/doc/config-examples/x86_64-usbstick.nix
Normal file
@ -0,0 +1,20 @@
|
||||
# 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;
|
||||
};
|
||||
}
|
810
nixos/doc/manual/configuration.xml
Normal file
810
nixos/doc/manual/configuration.xml
Normal file
@ -0,0 +1,810 @@
|
||||
<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 that file only take
|
||||
effect after you run <command>nixos-rebuild</command>.</para>
|
||||
|
||||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section><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 overriden instance, to prevent an infinite
|
||||
recursion.)</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section><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 <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><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" ];
|
||||
isSystemUser = false;
|
||||
useDefaultShell = true;
|
||||
openssh.authorizedKeys.keys = [ "ssh-dss AAAAB3Nza... alice@foobar" ];
|
||||
};
|
||||
</programlisting>
|
||||
|
||||
Note that <literal>alice</literal> is a member of the
|
||||
<literal>wheel</literal> group, which allows her to use
|
||||
<command>sudo</command> to execute commands as
|
||||
<literal>root</literal>. 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><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>
|
||||
service.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><title>Networking</title>
|
||||
|
||||
<section><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><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><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><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 can be enabled as follows:
|
||||
|
||||
<programlisting>
|
||||
networking.firewall.enable = true;
|
||||
</programlisting>
|
||||
|
||||
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><title>Wireless networks</title>
|
||||
|
||||
<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><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 in
|
||||
<filename>/run/booted-system/kernel-modules/config</filename>. 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>
|
98
nixos/doc/manual/default.nix
Normal file
98
nixos/doc/manual/default.nix
Normal file
@ -0,0 +1,98 @@
|
||||
{ pkgs, options
|
||||
# revision can have multiple values: local, HEAD or any revision number.
|
||||
, revision ? "HEAD"
|
||||
}:
|
||||
|
||||
let
|
||||
|
||||
# To prevent infinite recursion, remove system.path from the
|
||||
# options. Not sure why this happens.
|
||||
options_ =
|
||||
options //
|
||||
{ system = removeAttrs options.system ["path"]; };
|
||||
|
||||
optionsXML = builtins.toFile "options.xml" (builtins.unsafeDiscardStringContext
|
||||
(builtins.toXML (pkgs.lib.optionAttrSetToDocList "" options_)));
|
||||
|
||||
optionsDocBook = pkgs.runCommand "options-db.xml" {} ''
|
||||
${pkgs.libxslt}/bin/xsltproc \
|
||||
--stringparam revision '${revision}' \
|
||||
-o $out ${./options-to-docbook.xsl} ${optionsXML}
|
||||
'';
|
||||
|
||||
in rec {
|
||||
|
||||
# Generate the NixOS manual.
|
||||
manual = pkgs.stdenv.mkDerivation {
|
||||
name = "nixos-manual";
|
||||
|
||||
sources = pkgs.lib.sourceFilesBySuffices ./. [".xml"];
|
||||
|
||||
buildInputs = [ pkgs.libxml2 pkgs.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
|
||||
|
||||
# Check the validity of the manual sources.
|
||||
xmllint --noout --nonet --xinclude --noxincludenode \
|
||||
--relaxng ${pkgs.docbook5}/xml/rng/docbook/docbook.rng \
|
||||
manual.xml
|
||||
|
||||
# Generate the HTML manual.
|
||||
dst=$out/share/doc/nixos
|
||||
ensureDir $dst
|
||||
xsltproc $xsltFlags --nonet --xinclude \
|
||||
--output $dst/manual.html \
|
||||
${pkgs.docbook5_xsl}/xml/xsl/docbook/xhtml/docbook.xsl \
|
||||
./manual.xml
|
||||
|
||||
mkdir -p $dst/images/callouts
|
||||
cp ${pkgs.docbook5_xsl}/xml/xsl/docbook/images/callouts/*.gif $dst/images/callouts/
|
||||
|
||||
cp ${./style.css} $dst/style.css
|
||||
|
||||
ensureDir $out/nix-support
|
||||
echo "doc manual $dst manual.html" >> $out/nix-support/hydra-build-products
|
||||
''; # */
|
||||
};
|
||||
|
||||
# Generate the NixOS manpages.
|
||||
manpages = pkgs.stdenv.mkDerivation {
|
||||
name = "nixos-manpages";
|
||||
|
||||
sources = pkgs.lib.sourceFilesBySuffices ./. [".xml"];
|
||||
|
||||
buildInputs = [ pkgs.libxml2 pkgs.libxslt ];
|
||||
|
||||
buildCommand = ''
|
||||
ln -s $sources/*.xml . # */
|
||||
ln -s ${optionsDocBook} options-db.xml
|
||||
|
||||
# Check the validity of the manual sources.
|
||||
xmllint --noout --nonet --xinclude --noxincludenode \
|
||||
--relaxng ${pkgs.docbook5}/xml/rng/docbook/docbook.rng \
|
||||
./man-pages.xml
|
||||
|
||||
# Generate manpages.
|
||||
ensureDir $out/share/man
|
||||
xsltproc --nonet --xinclude \
|
||||
--param man.output.in.separate.dir 1 \
|
||||
--param man.output.base.dir "'$out/share/man/'" \
|
||||
--param man.endnotes.are.numbered 0 \
|
||||
${pkgs.docbook5_xsl}/xml/xsl/docbook/manpages/docbook.xsl \
|
||||
./man-pages.xml
|
||||
'';
|
||||
};
|
||||
|
||||
}
|
599
nixos/doc/manual/development.xml
Normal file
599
nixos/doc/manual/development.xml
Normal file
@ -0,0 +1,599 @@
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
|
||||
<title>Development</title>
|
||||
|
||||
<para>This chapter has some random notes on hacking on
|
||||
NixOS.</para>
|
||||
|
||||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section>
|
||||
|
||||
<title>Hacking on NixOS</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/nixos.git
|
||||
$ git clone git://github.com/NixOS/nixpkgs.git
|
||||
</screen>
|
||||
|
||||
This will check out the latest NixOS sources to
|
||||
<filename><replaceable>/my/sources</replaceable>/nixos</filename> and
|
||||
the Nixpkgs sources to
|
||||
<filename><replaceable>/my/sources</replaceable>/nixpkgs</filename>.
|
||||
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 <replaceable>/my/sources</replaceable>
|
||||
</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<para><command>nixos-rebuild</command> affects only the system profile.
|
||||
To install packages to your user profile from expressions in
|
||||
<replaceable>/my/sources</replaceable>, use
|
||||
<command>nix-env -f <replaceable>/my/sources</replaceable>/nixpkgs</command>,
|
||||
or change the default by replacing the symlink in
|
||||
<filename>~/.nix-defexpr</filename>:
|
||||
|
||||
<screen>
|
||||
$ rm -f ~/.nix-defexpr/channels
|
||||
$ ln -s <replaceable>/my/sources</replaceable>/nixpkgs ~/.nix-defexpr/nixpkgs
|
||||
</screen>
|
||||
|
||||
</para>
|
||||
|
||||
<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>
|
||||
|
||||
<title>Extending NixOS</title>
|
||||
|
||||
<para>NixOS is based on a modular system for declarative configuration.
|
||||
This system combines multiple <emphasis>modules</emphasis> to produce one
|
||||
configuration. One of the module which compose your computer
|
||||
configuration is <filename>/etc/nixos/configuration.nix</filename>. Other
|
||||
modules are available under NixOS <filename>modules</filename>
|
||||
directory</para>
|
||||
|
||||
<para>A module is a file which handles one specific part of the
|
||||
configuration. This part of the configuration could correspond to
|
||||
hardware, a service, network settings, or preferences. A module
|
||||
configuration does not have to handle everything from scratch, it can base
|
||||
its configuration on other configurations provided by other modules. Thus
|
||||
a module can <emphasis>define</emphasis> options to setup its
|
||||
configuration, and it can also <emphasis>declare</emphasis> options to be
|
||||
fed by other modules.</para>
|
||||
|
||||
<!-- module syntax -->
|
||||
|
||||
<para xml:id="para-module-syn">A module is a file which contains a Nix
|
||||
expression. This expression should be either an expression which gets
|
||||
evaluated into an attribute set or a function which returns an attribute
|
||||
set.</para>
|
||||
|
||||
<para>When the expression is a function, it should expect only one argument
|
||||
which is an attribute set containing an attribute
|
||||
named <varname>config</varname> and another attribute
|
||||
named <varname>pkgs</varname>. The <varname>config</varname> attribute
|
||||
contains the result of the merge of all modules. This attribute is
|
||||
evaluated lazily, such as any Nix expression. For more details on how
|
||||
options are merged, see the details in <xref linkend="para-opt-decl"/>.
|
||||
The <varname>pkgs</varname> attribute
|
||||
contains <emphasis>nixpkgs</emphasis> attribute set of packages. This
|
||||
attribute is necessary for declaring options.</para>
|
||||
|
||||
<example xml:id='module-syntax'><title>Usual module content</title>
|
||||
<programlisting>
|
||||
{ config, pkgs, ... }: <co xml:id='module-syntax-1' />
|
||||
|
||||
{
|
||||
imports =
|
||||
[ <co xml:id='module-syntax-2' />
|
||||
];
|
||||
|
||||
options = {
|
||||
<co xml:id='module-syntax-3' />
|
||||
};
|
||||
|
||||
config = {
|
||||
<co xml:id='module-syntax-4' />
|
||||
};
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para><xref linkend='module-syntax' /> Illustrates
|
||||
a <emphasis>module</emphasis> skeleton.
|
||||
|
||||
<calloutlist>
|
||||
<callout arearefs='module-syntax-1'>
|
||||
<para>This line makes the current Nix expression a function. 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 is used to enumerate path to other modules which are
|
||||
declaring options used by the current module. In NixOS, default modules
|
||||
are listed in the file <filename>modules/module-list.nix</filename>.
|
||||
The default modules don't need to be added in the import list.</para>
|
||||
</callout>
|
||||
|
||||
<callout arearefs='module-syntax-3'>
|
||||
<para>This attribute set contains an attribute set of <emphasis>option
|
||||
declaration</emphasis>.</para>
|
||||
</callout>
|
||||
|
||||
<callout arearefs='module-syntax-4'>
|
||||
<para>This attribute set contains an attribute set of <emphasis>option
|
||||
definitions</emphasis>. If the module does not have any imported
|
||||
modules or any option declarations, then this attribute set can be used
|
||||
in place of its parent attribute set. This is a common case for simple
|
||||
modules such
|
||||
as <filename>/etc/nixos/configuration.nix</filename>.</para>
|
||||
</callout>
|
||||
</calloutlist>
|
||||
|
||||
</para>
|
||||
|
||||
<!-- option definitions -->
|
||||
|
||||
<para xml:id="para-opt-def">A module defines a configuration which would be
|
||||
interpreted by other modules. To define a configuration, a module needs
|
||||
to provide option definitions. An option definition is a simple
|
||||
attribute assignment.</para>
|
||||
|
||||
<para>Option definitions are made in a declarative manner. Without
|
||||
properties, options will always be defined with the same value. To
|
||||
introduce more flexibility in the system, option definitions are guarded
|
||||
by <emphasis>properties</emphasis>.</para>
|
||||
|
||||
<para>Properties are means to introduce conditional values inside option
|
||||
definitions. This conditional values can be distinguished in two
|
||||
categories. The condition which are local to the current configuration
|
||||
and conditions which are dependent on others configurations. Local
|
||||
properties are <varname>mkIf</varname>
|
||||
and <varname>mkAssert</varname>. Global properties
|
||||
are <varname>mkOverride</varname>, <varname>mkDefault</varname>
|
||||
and <varname>mkOrder</varname>.</para>
|
||||
|
||||
<para><varname>mkIf</varname> is used to remove the option definitions which
|
||||
are below it if the condition is evaluated to
|
||||
false. <varname>mkAssert</varname> expects the condition to be evaluated
|
||||
to true otherwise it raises an error message.</para>
|
||||
|
||||
<para><varname>mkOverride</varname> is used to mask previous definitions if
|
||||
the current value has a lower mask number. The mask value is 100 (default)
|
||||
for any option definition which does not use this property.
|
||||
Thus, <varname>mkDefault</varname> is just a short-cut with a higher mask
|
||||
(1000) than the default mask value. This means that a module can set an
|
||||
option definition as a preference, and still let another module defining
|
||||
it with a different value without using any property.</para>
|
||||
|
||||
<para><varname>mkOrder</varname> is used to sort definitions based on the
|
||||
rank number. The rank number will sort all options definitions before
|
||||
giving the sorted list of option definition to the merge function defined
|
||||
in the option declaration. A lower rank will move the definition to the
|
||||
beginning and a higher rank will move the option toward the end. The
|
||||
default rank is 100.</para>
|
||||
|
||||
<!-- option declarations -->
|
||||
|
||||
<para xml:id="para-opt-decl">A module may declare options which are used by
|
||||
other module to change the configuration provided by the current module.
|
||||
Changes to the option definitions are made with properties which are using
|
||||
values extracted from the result of the merge of all modules
|
||||
(the <varname>config</varname> argument).</para>
|
||||
|
||||
<para>The <varname>config</varname> argument reproduce the same hierarchy of
|
||||
all options declared in all modules. For each option, the result of the
|
||||
option is available, it is either the default value or the merge of all
|
||||
definitions of the option.</para>
|
||||
|
||||
<para>Options are declared with the
|
||||
function <varname>pkgs.lib.mkOption</varname>. This function expects an
|
||||
attribute set which at least provides a description. A default value, an
|
||||
example, a type, a merge function and a post-process function can be
|
||||
added.</para>
|
||||
|
||||
<para>Types are used to provide a merge strategy for options and to ensure
|
||||
the type of each option definitions. They are defined
|
||||
in <varname>pkgs.lib.types</varname>.</para>
|
||||
|
||||
<para>The merge function expects a list of option definitions and merge
|
||||
them to obtain one result of the same type.</para>
|
||||
|
||||
<para>The post-process function (named <varname>apply</varname>) takes the
|
||||
result of the merge or of the default value, and produce an output which
|
||||
could have a different type than the type expected by the option.</para>
|
||||
|
||||
<!-- end -->
|
||||
|
||||
<example xml:id='locate-example'><title>Locate Module Example</title>
|
||||
<programlisting>
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
cfg = config.services.locate;
|
||||
locatedb = "/var/cache/locatedb";
|
||||
logfile = "/var/log/updatedb";
|
||||
cmd =''root updatedb --localuser=nobody --output=${locatedb} > ${logfile}'';
|
||||
in
|
||||
|
||||
{
|
||||
imports = [ /etc/nixos/nixos/modules/services/scheduling/cron.nix ];
|
||||
|
||||
options = {
|
||||
services.locate = {
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
example = true;
|
||||
type = with types; bool;
|
||||
description = ''
|
||||
If enabled, NixOS will periodically update the database of
|
||||
files used by the <command>locate</command> command.
|
||||
'';
|
||||
};
|
||||
|
||||
period = mkOption {
|
||||
default = "15 02 * * *";
|
||||
type = with types; uniq string;
|
||||
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 = mkIf cfg.enable {
|
||||
services.cron = {
|
||||
enable = true;
|
||||
systemCronJobs = "${cfg.period} root ${cmd}";
|
||||
};
|
||||
};
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para><xref linkend='locate-example' /> illustrates a module which handles
|
||||
the regular update of the database which index all files on the file
|
||||
system. This modules has option definitions to rely on the cron service
|
||||
to run the command at predefined dates. In addition, this modules
|
||||
provides option declarations to enable the indexing and to use different
|
||||
period of time to run the indexing. Properties are used to prevent
|
||||
ambiguous definitions of option (enable locate service and disable cron
|
||||
services) and to ensure that no options would be defined if the locate
|
||||
service is not enabled.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section>
|
||||
|
||||
<title>Building specific parts of NixOS</title>
|
||||
|
||||
<para>
|
||||
|
||||
<screen>
|
||||
$ nix-build /etc/nixos/nixos -A <replaceable>attr</replaceable></screen>
|
||||
|
||||
where <replaceable>attr</replaceable> is an attribute in
|
||||
<filename>/etc/nixos/nixos/default.nix</filename>. Attributes of interest include:
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>config</varname></term>
|
||||
<listitem><para>The computer configuration generated from
|
||||
the <envar>NIXOS_CONFIG</envar> environment variable (default
|
||||
is <filename>/etc/nixos/configuration.nix</filename>) with the NixOS
|
||||
default set of modules.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>system</varname></term>
|
||||
<listitem><para>The derivation which build your computer system. It is
|
||||
built by the command <command>nixos-rebuild
|
||||
build</command></para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>vm</varname></term>
|
||||
<listitem><para>The derivation which build your computer system inside a
|
||||
virtual machine. It is built by the command <command>nixos-rebuild
|
||||
build-vm</command></para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Most parts of NixOS can be built through the <varname>config</varname>
|
||||
attribute set. This attribute set allows you to have a view of the merged
|
||||
option definitions and all its derivations. Important derivations are store
|
||||
inside the option <option>system.build</option> and can be listed with the
|
||||
command <command>nix-instantiate --xml --eval-only /etc/nixos/nixos -A
|
||||
config.system.build</command>
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section>
|
||||
|
||||
<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>
|
||||
$ export NIXOS_CONFIG=/etc/nixos/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix
|
||||
$ nix-build /etc/nixos/nixos -A config.system.build.isoImage</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/building the NixOS Manual</title>
|
||||
|
||||
<para>A quick way to see if your documentation improvements
|
||||
or option descriptions look good:
|
||||
|
||||
<screen>
|
||||
$ nix-build -A config.system.build.manual</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>
|
||||
$ export NIXOS_CONFIG=/etc/nixos/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix
|
||||
$ nix-build /etc/nixos/nixos -A config.system.build.nixosInstall
|
||||
$ dd if=/dev/zero of=diskimage seek=2G count=0 bs=1
|
||||
$ yes | mke2fs -j diskimage
|
||||
$ mount -o loop diskimage /mnt
|
||||
$ ./result/bin/nixos-install</screen>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section>
|
||||
|
||||
<title>Testing the <literal>initrd</literal></title>
|
||||
|
||||
<para>A quick way to test whether the kernel and the initial ramdisk
|
||||
boot correctly is to use QEMU’s <option>-kernel</option> and
|
||||
<option>-initrd</option> options:
|
||||
|
||||
<screen>
|
||||
$ nix-build /etc/nixos/nixos -A config.system.build.initialRamdisk -o initrd
|
||||
$ nix-build /etc/nixos/nixos -A config.system.build.kernel -o kernel
|
||||
$ qemu-system-x86_64 -kernel ./kernel/bzImage -initrd ./initrd/initrd -hda /dev/null
|
||||
</screen>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
|
||||
<title>Whole-system testing using virtual machines</title>
|
||||
|
||||
<para>
|
||||
Complete NixOS GNU/Linux systems can be tested in virtual machines
|
||||
(VMs). This makes it possible to test a system upgrade or
|
||||
configuration change before rebooting into it, using the
|
||||
<command>nixos-rebuild build-vm</command> or
|
||||
<command>nixos-rebuild build-vm-with-bootloader</command> command.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<!-- The following is adapted from
|
||||
http://wiki.nixos.org/wiki/NixOS_VM_tests, by Eelco Dolstra. -->
|
||||
|
||||
The <filename>tests/</filename> directory in the NixOS source tree
|
||||
contains several <emphasis>whole-system unit tests</emphasis>.
|
||||
These tests can be run<footnote><para>NixOS tests can be run both from
|
||||
NixOS and from a non-NixOS GNU/Linux distribution, provided the
|
||||
Nix package manager is installed.</para></footnote> from the NixOS
|
||||
source tree as follows:
|
||||
|
||||
<screen>
|
||||
$ nix-build tests/ -A nfs.test
|
||||
</screen>
|
||||
|
||||
This performs an automated test of the NFS client and server
|
||||
functionality in the Linux kernel, including file locking
|
||||
semantics (e.g., whether locks are maintained across server
|
||||
crashes). It will first build or download all the dependencies of
|
||||
the test (e.g., all packages needed to run a NixOS VM). The test
|
||||
is defined in <link
|
||||
xlink:href="https://nixos.org/repos/nix/nixos/trunk/tests/nfs.nix">
|
||||
<filename>tests/nfs.nix</filename></link>. If the test succeeds,
|
||||
<command>nix-build</command> will place a symlink
|
||||
<filename>./result</filename> in the current directory pointing at
|
||||
the location in the Nix store of the test results (e.g.,
|
||||
screenshots, test reports, and so on). In particular, a
|
||||
pretty-printed log of the test is written to
|
||||
<filename>log.html</filename>, which can be viewed using a web
|
||||
browser like this:
|
||||
|
||||
<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 tests/ -A nfs.driver
|
||||
$ ./result/bin/nixos-run-vms
|
||||
</screen>
|
||||
|
||||
The script <command>nixos-run-vms</command> starts the three
|
||||
virtual machines defined in the NFS test using QEMU/KVM. 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>
|
||||
|
||||
Perl statements can now be typed in to start or manipulate the
|
||||
VMs:
|
||||
|
||||
<screen>
|
||||
> startAll;
|
||||
(the VMs start booting)
|
||||
> $server->waitForJob("nfs-kernel-nfsd");
|
||||
> $client1->succeed("flock -x /data/lock -c 'sleep 100000' &");
|
||||
> $client2->fail("flock -n -s /data/lock true");
|
||||
> $client1->shutdown;
|
||||
(this releases client1's lock)
|
||||
> $client2->succeed("flock -n -s /data/lock true");
|
||||
</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>
|
||||
|
||||
<para>
|
||||
This and other tests are continuously run on <link
|
||||
xlink:href="http://hydra.nixos.org/jobset/nixos/trunk">the Hydra
|
||||
instance at <literal>nixos.org</literal></link>, which allows
|
||||
developers to be notified of any regressions introduced by a NixOS
|
||||
or Nixpkgs change.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The actual Nix programming interface to VM testing is in NixOS,
|
||||
under <link
|
||||
xlink:href="https://nixos.org/repos/nix/nixos/trunk/lib/testing.nix">
|
||||
<filename>lib/testing.nix</filename></link>. This file defines a
|
||||
function which takes an attribute set containing a
|
||||
<literal>nixpkgs</literal> attribute (the path to a Nixpkgs
|
||||
checkout), and a <literal>system</literal> attribute (the system
|
||||
type). It returns an attribute set containing several utility
|
||||
functions, among which the main entry point is
|
||||
<literal>makeTest</literal>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <literal>makeTest</literal> function takes a function similar to
|
||||
that found in <link
|
||||
xlink:href="https://nixos.org/repos/nix/nixos/trunk/tests/nfs.nix">
|
||||
<filename>tests/nfs.nix</filename></link> (discussed above). It
|
||||
returns an attribute set containing (among others):
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>test</varname></term>
|
||||
<listitem><para>A derivation containing the test log as an HTML file,
|
||||
as seen above, suitable for presentation in the Hydra continuous
|
||||
build system.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>report</varname></term>
|
||||
<listitem><para>A derivation containing a code coverage report, with
|
||||
meta-data suitable for Hydra.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>driver</varname></term>
|
||||
<listitem><para>A derivation containing scripts to run the VM test or
|
||||
interact with the VM network interactively, as seen above.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
</chapter>
|
340
nixos/doc/manual/installation.xml
Normal file
340
nixos/doc/manual/installation.xml
Normal file
@ -0,0 +1,340 @@
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
|
||||
<title>Installing NixOS</title>
|
||||
|
||||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section>
|
||||
|
||||
<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>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section>
|
||||
|
||||
<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>, 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>. This will
|
||||
make the file system configuration independent from device
|
||||
changes.</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>.</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 configuration that
|
||||
you want to be built and activated, and then NixOS takes care of
|
||||
realising that configuration. The command
|
||||
<command>nixos-option</command> can generate an initial
|
||||
configuration file for you:
|
||||
|
||||
<screen>
|
||||
$ nixos-option --install</screen>
|
||||
|
||||
It tries to figure out the kernel modules necessary for mounting
|
||||
the root device, as well as various other hardware
|
||||
characteristics. However, it doesn’t try to figure out the
|
||||
<option>fileSystems</option> option yet.</para>
|
||||
|
||||
<para>You should edit
|
||||
<filename>/mnt/etc/nixos/configuration.nix</filename> to suit your
|
||||
needs. The text editors <command>nano</command> and
|
||||
<command>vim</command> are available.</para>
|
||||
|
||||
<para>You need to specify a root file system in
|
||||
<option>fileSystems</option> and the target device for the Grub boot
|
||||
loader in <option>boot.loader.grub.device</option>. See
|
||||
<xref linkend="ch-options"/> for a list of the available configuration
|
||||
options.</para>
|
||||
|
||||
<note><para>It is very important that you specify in the option
|
||||
<option>boot.initrd.kernelModules</option> all 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-option --install</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>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>Optionally, you can run
|
||||
|
||||
<screen>
|
||||
$ nixos-checkout</screen>
|
||||
|
||||
to make the installer use the latest NixOS/Nixpkgs sources from the
|
||||
Git repository, rather than the sources on CD.</para></listitem>
|
||||
-->
|
||||
|
||||
<listitem><para>Do the installation:
|
||||
|
||||
<screen>
|
||||
$ nixos-install</screen>
|
||||
|
||||
Cross fingers.</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><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 <lineannotation>(idem)</lineannotation>
|
||||
$ mkswap -L swap /dev/sda2 <lineannotation>(idem)</lineannotation>
|
||||
$ mount LABEL=nixos /mnt
|
||||
$ nixos-option --install
|
||||
$ nano /mnt/etc/nixos/configuration.nix
|
||||
<lineannotation>(in particular, set the fileSystems and swapDevices options)</lineannotation>
|
||||
$ nixos-install
|
||||
$ reboot</screen>
|
||||
</example>
|
||||
|
||||
<example xml:id='ex-config'><title>NixOS configuration</title>
|
||||
<screen>
|
||||
{
|
||||
boot.loader.grub.device = "/dev/sda";
|
||||
|
||||
fileSystems."/".device = "/dev/disk/by-label/nixos";
|
||||
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-label/swap"; } ];
|
||||
|
||||
services.sshd.enable = true;
|
||||
}</screen>
|
||||
</example>
|
||||
|
||||
</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>
|
||||
|
||||
<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>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 <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 use any data from your host system, so your
|
||||
existing user accounts and home directories will not be
|
||||
available.</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 the <literal>nixos-unstable</literal> channel. (A channel is a
|
||||
Nix mechanism for distributing Nix expressions and associated
|
||||
binaries.) The NixOS channel is updated automatically from NixOS’s
|
||||
Git repository after running certain tests and building most
|
||||
packages.</para>
|
||||
|
||||
<para>NixOS automatically subscribes you to the NixOS channel. If for
|
||||
some reason this is not the case, just do
|
||||
|
||||
<screen>
|
||||
$ nix-channel --add http://nixos.org/channels/nixos-unstable
|
||||
</screen>
|
||||
|
||||
You can then upgrade NixOS to the latest version in the channel by
|
||||
running
|
||||
|
||||
<screen>
|
||||
$ nix-channel --update nixos
|
||||
</screen>
|
||||
|
||||
and running the <command>nixos-rebuild</command> command as described
|
||||
in <xref linkend="sec-changing-config"/>.</para>
|
||||
|
||||
</section>
|
||||
|
||||
</chapter>
|
38
nixos/doc/manual/man-configuration.xml
Normal file
38
nixos/doc/manual/man-configuration.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle><filename>configuration.nix</filename></refentrytitle>
|
||||
<manvolnum>5</manvolnum>
|
||||
<refmiscinfo class="source">NixOS</refmiscinfo>
|
||||
<!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname><filename>configuration.nix</filename></refname>
|
||||
<refpurpose>NixOS system configuration specification</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>The file <filename>/etc/nixos/configuration.nix</filename>
|
||||
contains the declarative specification of your NixOS system
|
||||
configuration. The command <command>nixos-rebuild</command> takes
|
||||
this file and realises the system configuration specified
|
||||
therein.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<refsection><title>Options</title>
|
||||
|
||||
<para>You can use the following options in
|
||||
<filename>configuration.nix</filename>.</para>
|
||||
|
||||
<xi:include href="options-db.xml" />
|
||||
|
||||
</refsection>
|
||||
|
||||
</refentry>
|
110
nixos/doc/manual/man-nixos-build-vms.xml
Normal file
110
nixos/doc/manual/man-nixos-build-vms.xml
Normal file
@ -0,0 +1,110 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle><command>nixos-build-vms</command></refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
<refmiscinfo class="source">NixOS</refmiscinfo>
|
||||
<!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname><command>nixos-build-vms</command></refname>
|
||||
<refpurpose>build a network of virtual machines from a network of NixOS configurations</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nixos-build-vms</command>
|
||||
<arg><option>--show-trace</option></arg>
|
||||
<arg><option>--no-out-link</option></arg>
|
||||
<arg><option>--help</option></arg>
|
||||
<arg choice="plain"><replaceable>network.nix</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>This command builds a network of QEMU-KVM virtual machines of a Nix expression
|
||||
specifying a network of NixOS machines. The virtual network can be started by
|
||||
executing the <filename>bin/run-vms</filename> shell script that is generated by
|
||||
this command. By default, a <filename>result</filename> symlink is produced that
|
||||
points to the generated virtual network.
|
||||
</para>
|
||||
|
||||
<para>A network Nix expression has the following structure:
|
||||
|
||||
<screen>
|
||||
{
|
||||
test1 = {pkgs, config, ...}:
|
||||
{
|
||||
services.openssh.enable = true;
|
||||
nixpkgs.system = "i686-linux";
|
||||
deployment.targetHost = "test1.example.net";
|
||||
|
||||
# Other NixOS options
|
||||
};
|
||||
|
||||
test2 = {pkgs, config, ...}:
|
||||
{
|
||||
services.openssh.enable = true;
|
||||
services.httpd.enable = true;
|
||||
environment.systemPackages = [ pkgs.lynx ];
|
||||
nixpkgs.system = "x86_64-linux";
|
||||
deployment.targetHost = "test2.example.net";
|
||||
|
||||
# Other NixOS options
|
||||
};
|
||||
}
|
||||
</screen>
|
||||
|
||||
Each attribute in the expression represents a machine in the network
|
||||
(e.g. <varname>test1</varname> and <varname>test2</varname>)
|
||||
referring to a function defining a NixOS configuration.
|
||||
In each NixOS configuration, two attributes have a special meaning.
|
||||
The <varname>deployment.targetHost</varname> specifies the address
|
||||
(domain name or IP address)
|
||||
of the system which is used by <command>ssh</command> to perform
|
||||
remote deployment operations. The <varname>nixpkgs.system</varname>
|
||||
attribute can be used to specify an architecture for the target machine,
|
||||
such as <varname>i686-linux</varname> which builds a 32-bit NixOS
|
||||
configuration. Omitting this property will build the configuration
|
||||
for the same architecture as the host system.
|
||||
</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Options</title>
|
||||
|
||||
<para>This command accepts the following options:</para>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--show-trace</option></term>
|
||||
<listitem>
|
||||
<para>Shows a trace of the output.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--no-out-link</option></term>
|
||||
<listitem>
|
||||
<para>Do not create a 'result' symlink.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-h</option>, <option>--help</option></term>
|
||||
<listitem>
|
||||
<para>Shows the usage of this command to the user.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
</refentry>
|
170
nixos/doc/manual/man-nixos-option.xml
Normal file
170
nixos/doc/manual/man-nixos-option.xml
Normal file
@ -0,0 +1,170 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle><command>nixos-option</command></refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
<refmiscinfo class="source">NixOS</refmiscinfo>
|
||||
<!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname><command>nixos-option</command></refname>
|
||||
<refpurpose>inspect a NixOS configuration</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nixos-option</command>
|
||||
<group choice="opt">
|
||||
<option>-i</option>
|
||||
<option>v</option>
|
||||
<option>d</option>
|
||||
<option>l</option>
|
||||
</group>
|
||||
<arg choice='plain'><replaceable>option.name</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
<cmdsynopsis>
|
||||
<command>nixos-option</command>
|
||||
<arg choice='plain'><option>--install</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<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>
|
||||
|
||||
<para>When the option name is not an option, the command prints the list of
|
||||
attributes in contained in the attribute set. This could used to provide
|
||||
completion in some editors.</para>
|
||||
|
||||
<para>When the option <option>--install</option> (or <option>-i</option>) is
|
||||
used with no option name, this command generates a template configuration
|
||||
with a scan of the target system. It produces a template configuration
|
||||
in <filename>/etc/nixos/configuration.nix</filename>, and a scan of the
|
||||
machine in <filename>/etc/nixos/hardware-configuration.nix</filename>. The
|
||||
scan of the machine is produced
|
||||
by <command>nixos-hardware-scan</command>.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Options</title>
|
||||
|
||||
<para>This command accepts the following options:</para>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--install</option>, <option>-i</option></term>
|
||||
<listitem>
|
||||
<para>Use the installation configuration instead of current system
|
||||
configuration. Generate a template configuration if no option name is
|
||||
specified.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<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>
|
||||
|
||||
<varlistentry>
|
||||
<term><envar>mountPoint</envar></term>
|
||||
<listitem>
|
||||
<para>Location of the target file system. Defaults to
|
||||
<filename>/mnt</filename>. This environment variable is only used in
|
||||
combinaison with <option>--install</option> option.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><envar>NIXOS_CONFIG</envar></term>
|
||||
<listitem>
|
||||
<para>Path to the main NixOS configuration module. Defaults to
|
||||
<filename>/etc/nixos/configuration.nix</filename>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<refsection><title>Examples</title>
|
||||
|
||||
<para>Investigate option values:
|
||||
|
||||
<screen>$ nixos-option boot.loader
|
||||
This attribute set contains:
|
||||
generationsDir
|
||||
grub
|
||||
initScript
|
||||
|
||||
$ nixos-option boot.loader.grub.enable
|
||||
true</screen></para>
|
||||
|
||||
<para>Prints option information:
|
||||
|
||||
<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:
|
||||
|
||||
<screen>$ nixos-option -l hardware.firmware
|
||||
Declared by:
|
||||
/mnt/data/nix-sources/nixos/modules/services/hardware/udev.nix
|
||||
|
||||
Defined by:
|
||||
/etc/nixos/nixos/modules/system/boot/kernel.nix
|
||||
/etc/nixos/nixos/modules/hardware/network/rt73.nix
|
||||
/etc/nixos/nixos/modules/hardware/network/intel-3945abg.nix
|
||||
/etc/nixos/nixos/modules/hardware/network/intel-2200bg.nix</screen></para>
|
||||
|
||||
</refsection>
|
||||
|
||||
<refsection><title>Bugs</title>
|
||||
|
||||
<para>The author listed in the following section is wrong. If there is any
|
||||
other bug, please report to Nicolas Pierron.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
</refentry>
|
300
nixos/doc/manual/man-nixos-rebuild.xml
Normal file
300
nixos/doc/manual/man-nixos-rebuild.xml
Normal file
@ -0,0 +1,300 @@
|
||||
<refentry xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle><command>nixos-rebuild</command></refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
<refmiscinfo class="source">NixOS</refmiscinfo>
|
||||
<!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname><command>nixos-rebuild</command></refname>
|
||||
<refpurpose>reconfigure a NixOS machine</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>nixos-rebuild</command>
|
||||
<group choice='req'>
|
||||
<arg choice='plain'><option>switch</option></arg>
|
||||
<arg choice='plain'><option>boot</option></arg>
|
||||
<arg choice='plain'><option>test</option></arg>
|
||||
<arg choice='plain'><option>build</option></arg>
|
||||
<arg choice='plain'><option>dry-run</option></arg>
|
||||
<arg choice='plain'><option>build-vm</option></arg>
|
||||
<arg choice='plain'><option>build-vm-with-bootloader</option></arg>
|
||||
</group>
|
||||
<sbr />
|
||||
<arg><option>--upgrade</option></arg>
|
||||
<arg><option>--install-grub</option></arg>
|
||||
<arg><option>--no-build-nix</option></arg>
|
||||
<arg><option>--fast</option></arg>
|
||||
<arg><option>--rollback</option></arg>
|
||||
<sbr />
|
||||
<arg><option>--show-trace</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
|
||||
<refsection><title>Description</title>
|
||||
|
||||
<para>This command updates the system so that it corresponds to the
|
||||
configuration specified in
|
||||
<filename>/etc/nixos/configuration.nix</filename>. Thus, every time
|
||||
you modify <filename>/etc/nixos/configuration.nix</filename> or any
|
||||
NixOS module, you must run <command>nixos-rebuild</command> to make
|
||||
the changes take effect. It builds the new system in
|
||||
<filename>/nix/store</filename>, runs its activation script, and stop
|
||||
and (re)starts any system services if needed.</para>
|
||||
|
||||
<para>This command has one required argument, which specifies the
|
||||
desired operation. It must be one of the following:
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>switch</option></term>
|
||||
<listitem>
|
||||
<para>Build and activate the new configuration, and make it the
|
||||
boot default. That is, the configuration is added to the GRUB
|
||||
boot menu as the default meny entry, so that subsequent reboots
|
||||
will boot the system into the new configuration. Previous
|
||||
configurations activated with <command>nixos-rebuild
|
||||
switch</command> or <command>nixos-rebuild boot</command> remain
|
||||
available in the GRUB menu.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>boot</option></term>
|
||||
<listitem>
|
||||
<para>Build the new configuration and make it the boot default
|
||||
(as with <command>nixos-rebuild switch</command>), but do not
|
||||
activate it. That is, the system continues to run the previous
|
||||
configuration until the next reboot.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>test</option></term>
|
||||
<listitem>
|
||||
<para>Build and activate the new configuration, but do not add
|
||||
it to the GRUB boot menu. Thus, if you reboot the system (or if
|
||||
it crashes), you will automatically revert to the default
|
||||
configuration (i.e. the configuration resulting from the last
|
||||
call to <command>nixos-rebuild switch</command> or
|
||||
<command>nixos-rebuild boot</command>).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>build</option></term>
|
||||
<listitem>
|
||||
<para>Build the new configuration, but neither activate it nor
|
||||
add it to the GRUB boot menu. It leaves a symlink named
|
||||
<filename>result</filename> in the current directory, which
|
||||
points to the output of the top-level “system” derivation. This
|
||||
is essentially the same as doing
|
||||
<screen>
|
||||
$ nix-build /etc/nixos/nixos -A system
|
||||
</screen>
|
||||
Note that you do not need to be <literal>root</literal> to run
|
||||
<command>nixos-rebuild build</command>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>dry-run</option></term>
|
||||
<listitem>
|
||||
<para>Simply show what store paths would be built or downloaded
|
||||
by any of the operations above.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>build-vm</option></term>
|
||||
<listitem>
|
||||
<para>Build a script that starts a NixOS virtual machine with
|
||||
the desired configuration. It leaves a symlink
|
||||
<filename>result</filename> in the current directory that points
|
||||
(under
|
||||
<filename>result/bin/run-<replaceable>hostname</replaceable>-vm</filename>)
|
||||
at the script that starts the VM. Thus, to test a NixOS
|
||||
configuration in a virtual machine, you should do the following:
|
||||
<screen>
|
||||
$ nixos-rebuild build-vm
|
||||
$ ./result/bin/run-*-vm
|
||||
</screen></para>
|
||||
|
||||
<para>The VM is implemented using the <literal>qemu</literal>
|
||||
package. For best performance, you should load the
|
||||
<literal>kvm-intel</literal> or <literal>kvm-amd</literal>
|
||||
kernel modules to get hardware virtualisation.</para>
|
||||
|
||||
<para>The VM mounts the Nix store of the host through the 9P
|
||||
file system. The host Nix store is read-only, so Nix commands
|
||||
that modify the Nix store will not work in the VM. This
|
||||
includes commands such as <command>nixos-rebuild</command>; to
|
||||
change the VM’s configuration, you must halt the VM and re-run
|
||||
the commands above.
|
||||
</para>
|
||||
|
||||
<para>The VM has its own <literal>ext3</literal> root file
|
||||
system, which is automatically created when the VM is first
|
||||
started, and is persistent across reboots of the VM. It is
|
||||
stored in
|
||||
<literal>./<replaceable>hostname</replaceable>.qcow2</literal>.
|
||||
<!-- The entire file system hierarchy of the host is available in
|
||||
the VM under <filename>/hostfs</filename>.--></para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>build-vm-with-bootloader</option></term>
|
||||
<listitem>
|
||||
<para>Like <option>build-vm</option>, but boots using the
|
||||
regular boot loader of your configuration (e.g., GRUB 1 or 2),
|
||||
rather than booting directly into the kernel and initial ramdisk
|
||||
of the system. This allows you to test whether the boot loader
|
||||
works correctly. However, it does not guarantee that your NixOS
|
||||
configuration will boot successfully on the host hardware (i.e.,
|
||||
after running <command>nixos-rebuild switch</command>), because
|
||||
the hardware and boot loader configuration in the VM are
|
||||
different. The boot loader is installed on an automatically
|
||||
generated virtual disk containing a <filename>/boot</filename>
|
||||
partition, which is mounted read-only in the VM.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</para>
|
||||
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<refsection><title>Options</title>
|
||||
|
||||
<para>This command accepts the following options:</para>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--upgrade</option></term>
|
||||
<listitem>
|
||||
<para>Fetch the latest version of NixOS from the NixOS
|
||||
channel.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--install-grub</option></term>
|
||||
<listitem>
|
||||
<para>Causes the GRUB boot loader to be (re)installed on the
|
||||
device specified by the
|
||||
<varname>boot.loader.grub.device</varname> configuration
|
||||
option.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--no-build-nix</option></term>
|
||||
<listitem>
|
||||
<para>Normally, <command>nixos-rebuild</command> first builds
|
||||
the <varname>nixUnstable</varname> attribute in Nixpkgs, and
|
||||
uses the resulting instance of the Nix package manager to build
|
||||
the new system configuration. This is necessary if the NixOS
|
||||
modules use features not provided by the currently installed
|
||||
version of Nix. This option disables building a new Nix.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--fast</option></term>
|
||||
<listitem>
|
||||
<para>Equivalent to <option>--no-build-nix</option>
|
||||
<option>--show-trace</option>. This option is useful if you
|
||||
call <command>nixos-rebuild</command> frequently (e.g. if you’re
|
||||
hacking on a NixOS module).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--rollback</option></term>
|
||||
<listitem>
|
||||
<para>Instead of building a new configuration as specified by
|
||||
<filename>/etc/nixos/configuration.nix</filename>, roll back to
|
||||
the previous configuration. (The previous configuration is
|
||||
defined as the one before the “current” generation of the
|
||||
profile <filename>/nix/var/nix/profiles/system</filename>.)</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<para>In addition, <command>nixos-rebuild</command> accepts various
|
||||
Nix-related flags, including <option>--max-jobs</option> /
|
||||
<option>-j</option>, <option>--show-trace</option>,
|
||||
<option>--keep-failed</option>, <option>--keep-going</option> and
|
||||
<option>--verbose</option> / <option>-v</option>. See
|
||||
the Nix manual for details.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<refsection><title>Environment</title>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><envar>NIXOS_CONFIG</envar></term>
|
||||
<listitem>
|
||||
<para>Path to the main NixOS configuration module. Defaults to
|
||||
<filename>/etc/nixos/configuration.nix</filename>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<refsection><title>Files</title>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><filename>/run/current-system</filename></term>
|
||||
<listitem>
|
||||
<para>A symlink to the currently active system configuration in
|
||||
the Nix store.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><filename>/nix/var/nix/profiles/system</filename></term>
|
||||
<listitem>
|
||||
<para>The Nix profile that contains the current and previous
|
||||
system configurations. Used to generate the GRUB boot
|
||||
menu.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
<refsection><title>Bugs</title>
|
||||
|
||||
<para>This command should be renamed to something more
|
||||
descriptive.</para>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
|
||||
</refentry>
|
31
nixos/doc/manual/man-pages.xml
Normal file
31
nixos/doc/manual/man-pages.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<reference xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<title>NixOS Reference Pages</title>
|
||||
|
||||
<info>
|
||||
|
||||
<author>
|
||||
<personname>
|
||||
<firstname>Eelco</firstname>
|
||||
<surname>Dolstra</surname>
|
||||
</personname>
|
||||
<contrib>Author</contrib>
|
||||
</author>
|
||||
|
||||
<copyright>
|
||||
<year>2007</year>
|
||||
<year>2008</year>
|
||||
<year>2009</year>
|
||||
<holder>Eelco Dolstra</holder>
|
||||
</copyright>
|
||||
|
||||
</info>
|
||||
|
||||
<xi:include href="man-configuration.xml" />
|
||||
<xi:include href="man-nixos-rebuild.xml" />
|
||||
<xi:include href="man-nixos-option.xml" />
|
||||
<xi:include href="man-nixos-build-vms.xml" />
|
||||
|
||||
</reference>
|
62
nixos/doc/manual/manual.xml
Normal file
62
nixos/doc/manual/manual.xml
Normal file
@ -0,0 +1,62 @@
|
||||
<book xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<info>
|
||||
|
||||
<title>NixOS Manual</title>
|
||||
|
||||
<author>
|
||||
<personname>
|
||||
<firstname>Eelco</firstname>
|
||||
<surname>Dolstra</surname>
|
||||
</personname>
|
||||
</author>
|
||||
|
||||
<author>
|
||||
<personname>
|
||||
<firstname>Nicolas</firstname>
|
||||
<surname>Pierron</surname>
|
||||
</personname>
|
||||
</author>
|
||||
|
||||
<copyright>
|
||||
<year>2007-2013</year>
|
||||
<holder>Eelco Dolstra</holder>
|
||||
</copyright>
|
||||
|
||||
</info>
|
||||
|
||||
|
||||
<preface>
|
||||
<title>Preface</title>
|
||||
|
||||
<para>This manual describes how to install, use and extend NixOS,
|
||||
a Linux distribution based on the purely functional package
|
||||
management system Nix.</para>
|
||||
|
||||
<para>If you encounter problems, please report them on the
|
||||
<literal
|
||||
xlink:href="http://lists.science.uu.nl/mailman/listinfo/nix-dev">nix-dev@lists.science.uu.nl</literal>
|
||||
mailing list or on the <link
|
||||
xlink:href="irc://irc.freenode.net/#nixos">
|
||||
<literal>#nixos</literal> channel on Freenode</link>. Bugs should
|
||||
be reported in <link
|
||||
xlink:href="https://github.com/NixOS/nixos/issues">NixOS’ GitHub
|
||||
issue tracker</link>.</para>
|
||||
|
||||
</preface>
|
||||
|
||||
|
||||
<xi:include href="installation.xml" />
|
||||
<xi:include href="configuration.xml" />
|
||||
<xi:include href="running.xml" />
|
||||
<!-- <xi:include href="userconfiguration.xml" /> -->
|
||||
<xi:include href="troubleshooting.xml" />
|
||||
<xi:include href="development.xml" />
|
||||
<chapter xml:id="ch-options">
|
||||
<title>List of Options</title>
|
||||
<xi:include href="options-db.xml" />
|
||||
</chapter>
|
||||
|
||||
</book>
|
187
nixos/doc/manual/options-to-docbook.xsl
Normal file
187
nixos/doc/manual/options-to-docbook.xsl
Normal file
@ -0,0 +1,187 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:str="http://exslt.org/strings"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://docbook.org/ns/docbook"
|
||||
extension-element-prefixes="str"
|
||||
>
|
||||
|
||||
<xsl:output method='xml' encoding="UTF-8" />
|
||||
|
||||
<xsl:param name="revision" />
|
||||
|
||||
|
||||
<xsl:template match="/expr/list">
|
||||
|
||||
<variablelist>
|
||||
|
||||
<xsl:for-each select="attrs">
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<option>
|
||||
<xsl:for-each select="attr[@name = 'name']/string">
|
||||
<xsl:value-of select="@value" />
|
||||
<xsl:if test="position() != last()">.</xsl:if>
|
||||
</xsl:for-each>
|
||||
</option>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
|
||||
<para>
|
||||
<xsl:value-of disable-output-escaping="yes"
|
||||
select="attr[@name = 'description']/string/@value" />
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis>Default:</emphasis>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="attr[@name = 'default']">
|
||||
<literal>
|
||||
<xsl:apply-templates select="attr[@name = 'default']" />
|
||||
</literal>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
none
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</para>
|
||||
|
||||
<xsl:if test="attr[@name = 'example']">
|
||||
|
||||
<para>
|
||||
<emphasis>Example:</emphasis>
|
||||
<xsl:text> </xsl:text>
|
||||
<xsl:choose>
|
||||
<xsl:when test="attr[@name = 'example']/attrs[attr[@name = '_type' and string[@value = 'literalExample']]]">
|
||||
<programlisting><xsl:value-of select="attr[@name = 'example']/attrs/attr[@name = 'text']/string/@value" /></programlisting>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<literal>
|
||||
<xsl:apply-templates select="attr[@name = 'example']" />
|
||||
</literal>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</para>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="count(attr[@name = 'declarations']/list/*) != 0">
|
||||
<para>
|
||||
<emphasis>Declared by:</emphasis>
|
||||
</para>
|
||||
<xsl:apply-templates select="attr[@name = 'declarations']" />
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="count(attr[@name = 'definitions']/list/*) != 0">
|
||||
<para>
|
||||
<emphasis>Defined by:</emphasis>
|
||||
</para>
|
||||
<xsl:apply-templates select="attr[@name = 'definitions']" />
|
||||
</xsl:if>
|
||||
|
||||
</listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
</xsl:for-each>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="string">
|
||||
<!-- !!! escaping -->
|
||||
<xsl:text>"</xsl:text><xsl:value-of select="str:replace(str:replace(str:replace(@value, '\', '\\'), '"', '\"'), '
', '\n')" /><xsl:text>"</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="int">
|
||||
<xsl:value-of select="@value" />
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="bool[@value = 'true']">
|
||||
<xsl:text>true</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="bool[@value = 'false']">
|
||||
<xsl:text>false</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="list">
|
||||
[
|
||||
<xsl:for-each select="*">
|
||||
<xsl:apply-templates select="." />
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:for-each>
|
||||
]
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="attrs">
|
||||
{
|
||||
<xsl:for-each select="attr">
|
||||
<xsl:value-of select="@name" />
|
||||
<xsl:text> = </xsl:text>
|
||||
<xsl:apply-templates select="*" /><xsl:text>; </xsl:text>
|
||||
</xsl:for-each>
|
||||
}
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="derivation">
|
||||
<xsl:choose>
|
||||
<xsl:when test="attr[@name = 'url']/string/@value">
|
||||
<replaceable>(download of <xsl:value-of select="attr[@name = 'url']/string/@value" />)</replaceable>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<replaceable>(build of <xsl:value-of select="attr[@name = 'name']/string/@value" />)</replaceable>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="attr[@name = 'declarations' or @name = 'definitions']">
|
||||
<simplelist>
|
||||
<xsl:for-each select="list/string">
|
||||
<member><filename>
|
||||
<!-- Hyperlink the filename either to the NixOS Subversion
|
||||
repository (if it’s a module and we have a revision number),
|
||||
or to the local filesystem. -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="$revision != 'local' and contains(@value, '/modules/')">
|
||||
<xsl:attribute name="xlink:href">https://github.com/NixOS/nixos/blob/<xsl:value-of select="$revision"/>/modules/<xsl:value-of select="substring-after(@value, '/modules/')"/></xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:when test="$revision != 'local' and contains(@value, 'nixops') and contains(@value, '/nix/')">
|
||||
<xsl:attribute name="xlink:href">https://github.com/NixOS/nixops/blob/<xsl:value-of select="$revision"/>/nix/<xsl:value-of select="substring-after(@value, '/nix/')"/></xsl:attribute>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:attribute name="xlink:href">file://<xsl:value-of select="@value"/></xsl:attribute>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
<!-- Print the filename and make it user-friendly by replacing the
|
||||
/nix/store/<hash> prefix by the default location of nixos
|
||||
sources. -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="contains(@value, '/modules/')">
|
||||
<nixos/modules/<xsl:value-of select="substring-after(@value, '/modules/')"/>>
|
||||
</xsl:when>
|
||||
<xsl:when test="contains(@value, 'nixops') and contains(@value, '/nix/')">
|
||||
<nixops/<xsl:value-of select="substring-after(@value, '/nix/')"/>>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:value-of select="@value" />
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</filename></member>
|
||||
</xsl:for-each>
|
||||
</simplelist>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
369
nixos/doc/manual/running.xml
Normal file
369
nixos/doc/manual/running.xml
Normal file
@ -0,0 +1,369 @@
|
||||
<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><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><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><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><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><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><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>
|
268
nixos/doc/manual/style.css
Normal file
268
nixos/doc/manual/style.css
Normal file
@ -0,0 +1,268 @@
|
||||
/* Copied from http://bakefile.sourceforge.net/, which appears
|
||||
licensed under the GNU GPL. */
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Basic headers and text:
|
||||
***************************************************************************/
|
||||
|
||||
body
|
||||
{
|
||||
font-family: "Nimbus Sans L", sans-serif;
|
||||
background: white;
|
||||
margin: 2em 1em 2em 1em;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4
|
||||
{
|
||||
color: #005aa0;
|
||||
}
|
||||
|
||||
h1 /* title */
|
||||
{
|
||||
font-size: 200%;
|
||||
}
|
||||
|
||||
h2 /* chapters, appendices, subtitle */
|
||||
{
|
||||
font-size: 180%;
|
||||
}
|
||||
|
||||
/* Extra space between chapters, appendices. */
|
||||
div.chapter > div.titlepage h2, div.appendix > div.titlepage h2
|
||||
{
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
div.section > div.titlepage h2 /* sections */
|
||||
{
|
||||
font-size: 150%;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
h3 /* subsections */
|
||||
{
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
div.simplesect h2
|
||||
{
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
div.appendix h3
|
||||
{
|
||||
font-size: 150%;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
div.refnamediv h2, div.refsynopsisdiv h2, div.refsection h2 /* refentry parts */
|
||||
{
|
||||
margin-top: 1.4em;
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
div.refsection h3
|
||||
{
|
||||
font-size: 110%;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Examples:
|
||||
***************************************************************************/
|
||||
|
||||
div.example
|
||||
{
|
||||
border: 1px solid #b0b0b0;
|
||||
padding: 6px 6px;
|
||||
margin-left: 1.5em;
|
||||
margin-right: 1.5em;
|
||||
background: #f4f4f8;
|
||||
border-radius: 0.4em;
|
||||
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
|
||||
}
|
||||
|
||||
div.example p.title
|
||||
{
|
||||
margin-top: 0em;
|
||||
}
|
||||
|
||||
div.example pre
|
||||
{
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Screen dumps:
|
||||
***************************************************************************/
|
||||
|
||||
pre.screen, pre.programlisting
|
||||
{
|
||||
border: 1px solid #b0b0b0;
|
||||
padding: 3px 3px;
|
||||
margin-left: 1.5em;
|
||||
margin-right: 1.5em;
|
||||
color: #600000;
|
||||
background: #f4f4f8;
|
||||
font-family: monospace;
|
||||
border-radius: 0.4em;
|
||||
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
|
||||
}
|
||||
|
||||
div.example pre.programlisting
|
||||
{
|
||||
border: 0px;
|
||||
padding: 0 0;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Notes, warnings etc:
|
||||
***************************************************************************/
|
||||
|
||||
.note, .warning
|
||||
{
|
||||
border: 1px solid #b0b0b0;
|
||||
padding: 3px 3px;
|
||||
margin-left: 1.5em;
|
||||
margin-right: 1.5em;
|
||||
margin-bottom: 1em;
|
||||
padding: 0.3em 0.3em 0.3em 0.3em;
|
||||
background: #fffff5;
|
||||
border-radius: 0.4em;
|
||||
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
|
||||
}
|
||||
|
||||
div.note, div.warning
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
div.note h3, div.warning h3
|
||||
{
|
||||
color: red;
|
||||
font-size: 100%;
|
||||
padding-right: 0.5em;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.note p, div.warning p
|
||||
{
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
div.note h3 + p, div.warning h3 + p
|
||||
{
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.note h3
|
||||
{
|
||||
color: blue;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
div.navfooter *
|
||||
{
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Links colors and highlighting:
|
||||
***************************************************************************/
|
||||
|
||||
a { text-decoration: none; }
|
||||
a:hover { text-decoration: underline; }
|
||||
a:link { color: #0048b3; }
|
||||
a:visited { color: #002a6a; }
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Table of contents:
|
||||
***************************************************************************/
|
||||
|
||||
div.toc
|
||||
{
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.toc dl
|
||||
{
|
||||
margin-top: 0em;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Special elements:
|
||||
***************************************************************************/
|
||||
|
||||
tt, code
|
||||
{
|
||||
color: #400000;
|
||||
}
|
||||
|
||||
.term
|
||||
{
|
||||
font-weight: bold;
|
||||
|
||||
}
|
||||
|
||||
div.variablelist dd p, div.glosslist dd p
|
||||
{
|
||||
margin-top: 0em;
|
||||
}
|
||||
|
||||
div.variablelist dd, div.glosslist dd
|
||||
{
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
div.glosslist dt
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.varname
|
||||
{
|
||||
color: #400000;
|
||||
}
|
||||
|
||||
span.command strong
|
||||
{
|
||||
font-weight: normal;
|
||||
color: #400000;
|
||||
}
|
||||
|
||||
div.calloutlist table
|
||||
{
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
table
|
||||
{
|
||||
border-collapse: collapse;
|
||||
box-shadow: 0.4em 0.4em 0.5em #e0e0e0;
|
||||
}
|
||||
|
||||
table.simplelist
|
||||
{
|
||||
text-align: left;
|
||||
color: #005aa0;
|
||||
border: 0;
|
||||
padding: 5px;
|
||||
background: #fffff5;
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
box-shadow: none;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
div.affiliation
|
||||
{
|
||||
font-style: italic;
|
||||
}
|
198
nixos/doc/manual/troubleshooting.xml
Normal file
198
nixos/doc/manual/troubleshooting.xml
Normal file
@ -0,0 +1,198 @@
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
|
||||
<title>Troubleshooting</title>
|
||||
|
||||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section><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><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><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><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><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>
|
80
nixos/doc/manual/userconfiguration.xml
Normal file
80
nixos/doc/manual/userconfiguration.xml
Normal file
@ -0,0 +1,80 @@
|
||||
<chapter xmlns="http://docbook.org/ns/docbook"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
|
||||
<title>Configuration in home directory</title>
|
||||
|
||||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section>
|
||||
<title>Compiz Fusion</title>
|
||||
<para>
|
||||
Compiz Fusion is just a set of plugins for Compiz. Your best interest is to have
|
||||
them found both by Compiz and by Compiz Configuration Settings (also in Compiz Fusion
|
||||
distribution). By default they look in Compiz installation path and in home directory.
|
||||
You do not need to track /nix/store manually - everything is already in
|
||||
/run/current-system/sw/share.
|
||||
|
||||
<orderedlist>
|
||||
<listitem><para><filename>$HOME/.compiz/plugins</filename>
|
||||
should contain plugins you want to load. All the installed
|
||||
plugins are available in
|
||||
<filename>/run/current-system/sw/share/compiz-plugins/compiz/</filename>,
|
||||
so you can use symlinks to this directory.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para><filename>$HOME/.compiz/metadata</filename>
|
||||
should contain metadata (definition of configuration options) for plugins
|
||||
you want to load. All the installed metadata is available in
|
||||
<filename>/run/current-system/sw/share/compiz/</filename>,
|
||||
so you can use symlinks to this directory.
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
Probably a way to load <literal>GConf</literal> configuration backend by default
|
||||
should be found, but if you run <literal>Compiz</literal> with
|
||||
<literal>GConf</literal> configuration (default for <literal>X server</literal> job
|
||||
for now), you have to link
|
||||
<filename>/run/current-system/sw/share/compizconfig/backends/</filename>
|
||||
into <filename>$HOME/.compizconfig/backends</filename> directory.
|
||||
</para></listitem>
|
||||
|
||||
</orderedlist>
|
||||
|
||||
To summarize the above, these are the commands you have to execute
|
||||
<command>ln -s /run/current-system/sw/share/compiz/ $HOME/.compiz/metadata</command>
|
||||
<command>ln -s /run/current-system/sw/share/compiz-plugins/compiz/ $HOME/.compiz/plugins</command>
|
||||
<command>ln -s /run/current-system/sw/share/compizconfig/backends/ $HOME/.compizconfig/backends</command>
|
||||
|
||||
Now you can launch <literal>ccsm</literal> and configure everything. You should select
|
||||
GConf as a backend in the preferences menu of <literal>ccsm</literal>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Pidgin-LaTeX</title>
|
||||
<para>
|
||||
To have pidgin-latex plugin working after installation, you need the following:
|
||||
<orderedlist>
|
||||
<listitem><para>
|
||||
Symlink <filename>/run/current-system/sw/share/pidgin-latex/pidgin-latex.so</filename>
|
||||
to <filename>$HOME/.purple/plugins/pidgin-latex.so</filename>
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Enable smileys. If you do not want to, you can create
|
||||
<filename>$HOME/.purple/smileys/empty/theme</filename> with the following contents:
|
||||
<programlisting>
|
||||
Name=Empty
|
||||
Description=No predefined smileys
|
||||
Author=Nobody
|
||||
</programlisting>
|
||||
Enabling this theme will enable smileys, but define none.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Enable the plugin.
|
||||
</para></listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</chapter>
|
16
nixos/gui/README
Normal file
16
nixos/gui/README
Normal file
@ -0,0 +1,16 @@
|
||||
This file should become a nix expression. (see modules/installer/tools/tools.nix)
|
||||
|
||||
you need to:
|
||||
- download the latest jQuery from and copy it to chrome/content:
|
||||
http://code.jquery.com/jquery-1.5.2.js
|
||||
|
||||
- install 'xulrunner' with nix:
|
||||
nix-env -Ai nixpkgs_sys.firefox40Pkgs.xulrunner
|
||||
|
||||
- make sure nixos-option in your path
|
||||
|
||||
- have /etc/nixos/nixpkgs
|
||||
- have /etc/nixos/nixos
|
||||
|
||||
run it:
|
||||
- xulrunner /etc/nixos/nixos/gui/application.ini -jsconsole
|
36
nixos/gui/application.ini
Normal file
36
nixos/gui/application.ini
Normal file
@ -0,0 +1,36 @@
|
||||
[App]
|
||||
;
|
||||
; This field specifies your organization's name. This field is recommended,
|
||||
; but optional.
|
||||
Vendor=NixOS
|
||||
;
|
||||
; This field specifies your application's name. This field is required.
|
||||
Name=NixOS-gui
|
||||
;
|
||||
; This field specifies your application's version. This field is optional.
|
||||
Version=0.1
|
||||
;
|
||||
; This field specifies your application's build ID (timestamp). This field is
|
||||
; required.
|
||||
BuildID=20110424
|
||||
;
|
||||
; This field specifies a compact copyright notice for your application. This
|
||||
; field is optional.
|
||||
;Copyright=
|
||||
|
||||
;
|
||||
; This ID is just an example. Every XUL app ought to have it's own unique ID.
|
||||
; You can use the microsoft "guidgen" or "uuidgen" tools, or go on
|
||||
; irc.mozilla.org and /msg botbot uuid. This field is optional.
|
||||
;ID=
|
||||
|
||||
[Gecko]
|
||||
;
|
||||
; This field is required. It specifies the minimum Gecko version that this
|
||||
; application requires.
|
||||
MinVersion=1.9a5
|
||||
;
|
||||
; This field is optional. It specifies the maximum Gecko version that this
|
||||
; application requires. It should be specified if your application uses
|
||||
; unfrozen interfaces.
|
||||
MaxVersion=2.*
|
1
nixos/gui/chrome.manifest
Normal file
1
nixos/gui/chrome.manifest
Normal file
@ -0,0 +1 @@
|
||||
manifest chrome/chrome.manifest
|
1
nixos/gui/chrome/chrome.manifest
Normal file
1
nixos/gui/chrome/chrome.manifest
Normal file
@ -0,0 +1 @@
|
||||
content nixos-gui content/
|
137
nixos/gui/chrome/content/io.js
Normal file
137
nixos/gui/chrome/content/io.js
Normal file
@ -0,0 +1,137 @@
|
||||
|
||||
function inspect(obj, maxLevels, level)
|
||||
{
|
||||
var str = '', type, msg;
|
||||
|
||||
// Start Input Validations
|
||||
// Don't touch, we start iterating at level zero
|
||||
if(level == null) level = 0;
|
||||
|
||||
// At least you want to show the first level
|
||||
if(maxLevels == null) maxLevels = 1;
|
||||
if(maxLevels < 1)
|
||||
return '<font color="red">Error: Levels number must be > 0</font>';
|
||||
|
||||
// We start with a non null object
|
||||
if(obj == null)
|
||||
return '<font color="red">Error: Object <b>NULL</b></font>';
|
||||
// End Input Validations
|
||||
|
||||
// Each Iteration must be indented
|
||||
str += '<ul>';
|
||||
|
||||
// Start iterations for all objects in obj
|
||||
for(property in obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Show "property" and "type property"
|
||||
type = typeof(obj[property]);
|
||||
str += '<li>(' + type + ') ' + property +
|
||||
( (obj[property]==null)?(': <b>null</b>'):('')) + '</li>';
|
||||
|
||||
// We keep iterating if this property is an Object, non null
|
||||
// and we are inside the required number of levels
|
||||
if((type == 'object') && (obj[property] != null) && (level+1 < maxLevels))
|
||||
str += inspect(obj[property], maxLevels, level+1);
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
// Is there some properties in obj we can't access? Print it red.
|
||||
if(typeof(err) == 'string') msg = err;
|
||||
else if(err.message) msg = err.message;
|
||||
else if(err.description) msg = err.description;
|
||||
else msg = 'Unknown';
|
||||
|
||||
str += '<li><font color="red">(Error) ' + property + ': ' + msg +'</font></li>';
|
||||
}
|
||||
}
|
||||
|
||||
// Close indent
|
||||
str += '</ul>';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// Run xulrunner application.ini -jsconsole -console, to see messages.
|
||||
function log(str)
|
||||
{
|
||||
Components.classes['@mozilla.org/consoleservice;1']
|
||||
.getService(Components.interfaces.nsIConsoleService)
|
||||
.logStringMessage(str);
|
||||
}
|
||||
|
||||
function makeTempFile(prefix)
|
||||
{
|
||||
var file = Components.classes["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties)
|
||||
.get("TmpD", Components.interfaces.nsIFile);
|
||||
file.append(prefix || "xulrunner");
|
||||
file.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0664);
|
||||
return file;
|
||||
}
|
||||
|
||||
function writeToFile(file, data)
|
||||
{
|
||||
// file is nsIFile, data is a string
|
||||
var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIFileOutputStream);
|
||||
|
||||
// use 0x02 | 0x10 to open file for appending.
|
||||
foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
|
||||
foStream.write(data, data.length);
|
||||
foStream.close();
|
||||
}
|
||||
|
||||
function readFromFile(file)
|
||||
{
|
||||
// |file| is nsIFile
|
||||
var data = "";
|
||||
var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]
|
||||
.createInstance(Components.interfaces.nsIFileInputStream);
|
||||
var sstream = Components.classes["@mozilla.org/scriptableinputstream;1"]
|
||||
.createInstance(Components.interfaces.nsIScriptableInputStream);
|
||||
fstream.init(file, -1, 0, 0);
|
||||
sstream.init(fstream);
|
||||
|
||||
var str = sstream.read(4096);
|
||||
while (str.length > 0) {
|
||||
data += str;
|
||||
str = sstream.read(4096);
|
||||
}
|
||||
|
||||
sstream.close();
|
||||
fstream.close();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function runProgram(commandLine)
|
||||
{
|
||||
// create an nsILocalFile for the executable
|
||||
var file = Components.classes["@mozilla.org/file/local;1"]
|
||||
.createInstance(Components.interfaces.nsILocalFile);
|
||||
file.initWithPath("/bin/sh");
|
||||
|
||||
// create an nsIProcess
|
||||
var process = Components.classes["@mozilla.org/process/util;1"]
|
||||
.createInstance(Components.interfaces.nsIProcess);
|
||||
process.init(file);
|
||||
|
||||
// Run the process.
|
||||
// If first param is true, calling thread will be blocked until
|
||||
// called process terminates.
|
||||
// Second and third params are used to pass command-line arguments
|
||||
// to the process.
|
||||
var args = ["-c", commandLine];
|
||||
process.run(true, args, args.length);
|
||||
}
|
||||
|
||||
// only for testing...
|
||||
function testIO()
|
||||
{
|
||||
var f = makeTempFile();
|
||||
writeToFile(f, "essai\ntest");
|
||||
alert(readFromFile(f));
|
||||
runProgram("zenity --info");
|
||||
}
|
70
nixos/gui/chrome/content/main.js
Normal file
70
nixos/gui/chrome/content/main.js
Normal file
@ -0,0 +1,70 @@
|
||||
// global variables.
|
||||
var gNixOS;
|
||||
var gOptionView;
|
||||
|
||||
/*
|
||||
var gProgressBar;
|
||||
function setProgress(current, max)
|
||||
{
|
||||
if (gProgressBar) {
|
||||
gProgressBar.value = 100 * current / max;
|
||||
log("progress: " + gProgressBar.value + "%");
|
||||
}
|
||||
else
|
||||
log("unknow progress bar");
|
||||
}
|
||||
*/
|
||||
|
||||
function updateTextbox(id, value)
|
||||
{
|
||||
// setting the height cause an overflow which resize the textbox to its
|
||||
// content due to its onoverflow attribute.
|
||||
$(id).attr("value", value).attr("height", 1);
|
||||
};
|
||||
|
||||
function updatePanel(options)
|
||||
{
|
||||
log("updatePanel: " + options.length);
|
||||
if (options.length == 0)
|
||||
return;
|
||||
// FIXME: ignore the rest of the selection for now.
|
||||
var o = options[0];
|
||||
$("#name").attr("label", o.path);
|
||||
|
||||
if (o.typename != null)
|
||||
$("#typename").attr("label", o.typename);
|
||||
else
|
||||
$("#typename").attr("label", "");
|
||||
|
||||
$("#desc").text(o.description);
|
||||
|
||||
if (o.value != null)
|
||||
updateTextbox("#val", o.value);
|
||||
else
|
||||
updateTextbox("#val", "");
|
||||
|
||||
if (o.defaultValue != null)
|
||||
updateTextbox("#def", o.defaultValue);
|
||||
else
|
||||
updateTextbox("#def", "");
|
||||
|
||||
if (o.example != null)
|
||||
updateTextbox("#exp", o.example);
|
||||
else
|
||||
updateTextbox("#exp", "");
|
||||
|
||||
updateTextbox("#decls", o.declarations.join("\n"));
|
||||
updateTextbox("#defs", o.definitions.join("\n"));
|
||||
}
|
||||
|
||||
|
||||
function onload()
|
||||
{
|
||||
var optionTree = document.getElementById("option-tree");
|
||||
// gProgressBar = document.getElementById("progress-bar");
|
||||
// setProgress(0, 1);
|
||||
|
||||
gNixOS = new NixOS();
|
||||
gOptionView = new OptionView(gNixOS.option, updatePanel);
|
||||
optionTree.view = gOptionView;
|
||||
}
|
63
nixos/gui/chrome/content/myviewer.xul
Normal file
63
nixos/gui/chrome/content/myviewer.xul
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
|
||||
<!DOCTYPE window>
|
||||
|
||||
<!-- To edit this file I recommend you to use:
|
||||
http://xulfr.org/outils/xulediteur.xul
|
||||
-->
|
||||
|
||||
<window
|
||||
id = "nixos-gui"
|
||||
title = "NixOS gui"
|
||||
width = "800"
|
||||
height = "600"
|
||||
xmlns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script src="jquery-1.5.2.js"/>
|
||||
<script src="io.js"/>
|
||||
<script src="nixos.js"/>
|
||||
<script src="optionView.js"/>
|
||||
<script src="main.js"/>
|
||||
<hbox flex="1">
|
||||
<vbox width="250">
|
||||
<tree flex="1" id="option-tree" persist="height" onselect="gOptionView.selectionChanged()">
|
||||
<treecols>
|
||||
<treecol persist="hidden width" flex="9" id="opt-name"
|
||||
label="Option" primary="true"/>
|
||||
<!-- Uncomment the following column to see the number of option
|
||||
printed below each options. -->
|
||||
<!--
|
||||
<treecol persist="hidden width" flex="1" id="dbg-size"
|
||||
label="sz"/>
|
||||
-->
|
||||
</treecols>
|
||||
<treechildren id="first-child" flex="1"/>
|
||||
</tree>
|
||||
</vbox>
|
||||
<vbox flex="3" style="overflow: auto">
|
||||
<caption id="name" label=""/>
|
||||
<caption id="typename" label=""/>
|
||||
<separator/>
|
||||
<description id="desc" hidden="false"></description>
|
||||
<separator/>
|
||||
<caption label="Value:"/>
|
||||
<textbox id="val" readonly="true" multiline="true" value=""
|
||||
class="plain" hidden="false" onoverflow="this.height =
|
||||
this.inputField.scrollHeight;" />
|
||||
<separator/>
|
||||
<caption label="Default:"/>
|
||||
<textbox id="def" readonly="true" multiline="true" value="" class="plain" hidden="false" onoverflow="this.height = this.inputField.scrollHeight;" />
|
||||
<separator/>
|
||||
<caption label="Example:"/>
|
||||
<textbox id="exp" readonly="true" multiline="true" value="" class="plain" hidden="false" onoverflow="this.height = this.inputField.scrollHeight;" />
|
||||
<separator/>
|
||||
<caption label="Declarations:"/>
|
||||
<textbox id="decls" readonly="true" multiline="true" value="" class="plain" hidden="false" onoverflow="this.height = this.inputField.scrollHeight;" />
|
||||
<separator/>
|
||||
<caption label="Definitions:"/>
|
||||
<textbox id="defs" readonly="true" multiline="true" value=""
|
||||
class="plain" hidden="false" onoverflow="this.height = this.inputField.scrollHeight;" />
|
||||
</vbox>
|
||||
</hbox>
|
||||
<!-- <progressmeter id="progress-bar" value="0%"/> -->
|
||||
</window>
|
255
nixos/gui/chrome/content/nixos.js
Normal file
255
nixos/gui/chrome/content/nixos.js
Normal file
@ -0,0 +1,255 @@
|
||||
|
||||
function NixOS () {
|
||||
var env = Components.classes["@mozilla.org/process/environment;1"].
|
||||
getService(Components.interfaces.nsIEnvironment);
|
||||
|
||||
if (env.exists("NIXOS"))
|
||||
this.nixos = env.get("NIXOS");
|
||||
if (env.exists("NIXOS_CONFIG"))
|
||||
this.config = env.get("NIXOS_CONFIG");
|
||||
if (env.exists("NIXPKGS"))
|
||||
this.nixpkgs = env.get("NIXPKGS");
|
||||
if (env.exists("mountPoint"))
|
||||
this.root = env.get("mountPoint");
|
||||
if (env.exists("NIXOS_OPTION"))
|
||||
this.optionBin = env.get("NIXOS_OPTION");
|
||||
this.option = new Option("options", this, null);
|
||||
};
|
||||
|
||||
NixOS.prototype = {
|
||||
root: "",
|
||||
nixos: "/etc/nixos/nixos",
|
||||
nixpkgs: "/etc/nixos/nixpkgs",
|
||||
config: "/etc/nixos/configuration.nix",
|
||||
instantiateBin: "/run/current-system/sw/bin/nix-instantiate",
|
||||
optionBin: "/run/current-system/sw/bin/nixos-option",
|
||||
tmpFile: "nixos-gui",
|
||||
option: null
|
||||
};
|
||||
|
||||
function Option (name, context, parent) {
|
||||
this.name = name;
|
||||
this.context_ = context;
|
||||
if (parent == null)
|
||||
this.path = "";
|
||||
else if (parent.path == "")
|
||||
this.path = name;
|
||||
else
|
||||
this.path = parent.path + "." + name;
|
||||
};
|
||||
|
||||
Option.prototype = {
|
||||
load: function () {
|
||||
var env = "";
|
||||
env += "'NIXOS=" + this.context_.root + this.context_.nixos + "' ";
|
||||
env += "'NIXOS_PKGS=" + this.context_.root + this.context_.nixpkgs + "' ";
|
||||
env += "'NIXOS_CONFIG=" + this.context_.config + "' ";
|
||||
var out = makeTempFile(this.context_.tmpFile);
|
||||
var prog = this.context_.optionBin + " 2>&1 >" + out.path + " ";
|
||||
var args = " --xml " + this.path;
|
||||
|
||||
runProgram(/*env + */ prog + args);
|
||||
var xml = readFromFile(out);
|
||||
out.remove(false);
|
||||
|
||||
// jQuery does a stack overflow when converting a huge XML to a DOM.
|
||||
var dom = DOMParser().parseFromString(xml, "text/xml");
|
||||
var xmlAttrs = $("expr > attrs > attr", dom);
|
||||
|
||||
this.isOption = xmlAttrs.first().attr("name") == "_isOption";
|
||||
|
||||
if (!this.isOption)
|
||||
this.loadSubOptions(xmlAttrs);
|
||||
else
|
||||
this.loadOption(xmlAttrs);
|
||||
this.isLoaded = true;
|
||||
},
|
||||
|
||||
loadSubOptions: function (xmlAttrs) {
|
||||
var cur = this;
|
||||
var attrs = new Array();
|
||||
|
||||
xmlAttrs.each(
|
||||
function (index) {
|
||||
var name = $(this).attr("name");
|
||||
var attr = new Option(name, cur.context_, cur);
|
||||
attrs.push(attr);
|
||||
}
|
||||
);
|
||||
|
||||
this.subOptions = attrs;
|
||||
},
|
||||
|
||||
optionAttributeMap: {
|
||||
_isOption: function (cur, v) { },
|
||||
value: function (cur, v) { cur.value = xml2nix($(v).children().first()); },
|
||||
default: function (cur, v) { cur.defaultValue = xml2nix($(v).children().first()); },
|
||||
example: function (cur, v) { cur.example = xml2nix($(v).children().first()); },
|
||||
description: function (cur, v) { cur.description = this.string(v); },
|
||||
typename: function (cur, v) { cur.typename = this.string(v); },
|
||||
options: function (cur, v) { cur.loadSubOptions($("attrs", v).children()); },
|
||||
declarations: function (cur, v) { cur.declarations = this.pathList(v); },
|
||||
definitions: function (cur, v) { cur.definitions = this.pathList(v); },
|
||||
|
||||
string: function (v) {
|
||||
return $(v).children("string").first().attr("value");
|
||||
},
|
||||
|
||||
pathList: function (v) {
|
||||
var list = [];
|
||||
$(v).children("list").first().children().each(
|
||||
function (idx) {
|
||||
list.push($(this).attr("value"));
|
||||
}
|
||||
);
|
||||
return list;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
loadOption: function (attrs) {
|
||||
var cur = this;
|
||||
|
||||
attrs.each(
|
||||
function (index) {
|
||||
var name = $(this).attr("name");
|
||||
log("loadOption: " + name);
|
||||
cur.optionAttributeMap[name](cur, this);
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
// keep the context under which this option has been used.
|
||||
context_: null,
|
||||
// name of the option.
|
||||
name: "",
|
||||
// result of nixos-option.
|
||||
value: null,
|
||||
typename: null,
|
||||
defaultValue: null,
|
||||
example: null,
|
||||
description: "",
|
||||
declarations: [],
|
||||
definitions: [],
|
||||
// path to reach this option
|
||||
path: "",
|
||||
|
||||
// list of options accessible from here.
|
||||
isLoaded: false,
|
||||
isOption: false,
|
||||
subOptions: []
|
||||
};
|
||||
|
||||
var xml2nix_pptable = {
|
||||
attrs: function (node, depth, pp) {
|
||||
var children = node.children().not(
|
||||
function () {
|
||||
var name = $(this).attr("name");
|
||||
return name.charAt(0) == "_";
|
||||
}
|
||||
);
|
||||
var c = 0;
|
||||
var out = "";
|
||||
out += "{";
|
||||
depth += 1;
|
||||
children.each(
|
||||
function (idx) {
|
||||
c += 1;
|
||||
out += pp.indent(depth);
|
||||
out += pp.dispatch($(this), depth, pp);
|
||||
}
|
||||
);
|
||||
depth -= 1;
|
||||
if (c > 0)
|
||||
out += this.indent(depth);
|
||||
else
|
||||
out += " ";
|
||||
out += "}";
|
||||
return out;
|
||||
},
|
||||
list: function (node, depth, pp) {
|
||||
var children = node.children();
|
||||
var c = 0;
|
||||
var out = "";
|
||||
out += "[";
|
||||
depth += 1;
|
||||
children.each(
|
||||
function (idx) {
|
||||
c += 1;
|
||||
out += pp.indent(depth);
|
||||
out += pp.dispatch($(this), depth, pp);
|
||||
}
|
||||
);
|
||||
depth -= 1;
|
||||
if (c > 0)
|
||||
out += this.indent(depth);
|
||||
else
|
||||
out += " ";
|
||||
out += "]";
|
||||
return out;
|
||||
},
|
||||
attr: function (node, depth, pp) {
|
||||
var name = node.attr("name");
|
||||
var out = "";
|
||||
var val = "";
|
||||
out += name + " = ";
|
||||
depth += 1;
|
||||
val = pp.dispatch(node.children().first(), depth, pp);
|
||||
out += val;
|
||||
depth -= 1;
|
||||
out += ";";
|
||||
return out;
|
||||
},
|
||||
string: function (node, depth, pp) {
|
||||
return "\"" + node.attr("value") + "\"";
|
||||
},
|
||||
path: function (node, depth, pp) {
|
||||
return node.attr("value");
|
||||
},
|
||||
bool: function (node, depth, pp) {
|
||||
return node.attr("value");
|
||||
},
|
||||
"int": function (node, depth, pp) {
|
||||
return node.attr("value");
|
||||
},
|
||||
null: function (node, depth, pp) {
|
||||
return "null";
|
||||
},
|
||||
derivation: function (node, depth, pp) {
|
||||
return "<derivation>";
|
||||
},
|
||||
function: function (node, depth, pp) {
|
||||
return "<function>";
|
||||
},
|
||||
unevaluated: function (node, depth, pp) {
|
||||
return "<unevaluated>";
|
||||
},
|
||||
|
||||
dispatch: function (node, depth, pp) {
|
||||
for (var key in pp)
|
||||
{
|
||||
if(node.is(key))
|
||||
{
|
||||
// log(this.indent(depth) + "dispatch: " + key);
|
||||
var out = pp[key](node, depth, pp);
|
||||
// log(this.indent(depth) + "dispatch: => " + out);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
return "<dispatch-error>";
|
||||
},
|
||||
indent: function (depth) {
|
||||
var ret = "\n";
|
||||
while (depth--)
|
||||
ret += " ";
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
function xml2nix(node) {
|
||||
var depth = 0;
|
||||
var pp = xml2nix_pptable;
|
||||
var out = pp.dispatch(node, depth, pp);
|
||||
// log("pretty:\n" + out);
|
||||
return out;
|
||||
}
|
242
nixos/gui/chrome/content/optionView.js
Normal file
242
nixos/gui/chrome/content/optionView.js
Normal file
@ -0,0 +1,242 @@
|
||||
// extend NixOS options to handle the Tree View. Should be better to keep a
|
||||
// separation of concern here.
|
||||
|
||||
Option.prototype.tv_opened = false;
|
||||
Option.prototype.tv_size = 1;
|
||||
|
||||
Option.prototype.tv_open = function () {
|
||||
this.tv_opened = true;
|
||||
this.tv_size = 1;
|
||||
|
||||
// load an option if it is not loaded yet, and initialize them to be
|
||||
// read by the Option view.
|
||||
if (!this.isLoaded)
|
||||
this.load();
|
||||
|
||||
// If this is not an option, then add it's lits of sub-options size.
|
||||
if (!this.isOption)
|
||||
{
|
||||
for (var i = 0; i < this.subOptions.length; i++)
|
||||
this.tv_size += this.subOptions[i].tv_size;
|
||||
}
|
||||
};
|
||||
|
||||
Option.prototype.tv_close = function () {
|
||||
this.tv_opened = false;
|
||||
this.tv_size = 1;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
function OptionView (root, selCallback) {
|
||||
root.tv_open();
|
||||
this.rootOption = root;
|
||||
this.selCallback = selCallback;
|
||||
}
|
||||
|
||||
OptionView.prototype = {
|
||||
rootOption: null,
|
||||
selCallback: null,
|
||||
|
||||
// This function returns the path to option which is at the specified row.
|
||||
reach_cache: null,
|
||||
reachRow: function (row) {
|
||||
var o = this.rootOption; // Current option.
|
||||
var r = 0; // Number of rows traversed.
|
||||
var c = 0; // Child index.
|
||||
var path = [{ row: r, opt: o }]; // new Array();
|
||||
// hypothesis: this.rootOption.tv_size is always open and bigger than
|
||||
|
||||
// Use the previous returned value to avoid making to many checks and to
|
||||
// optimize for frequent access of near rows.
|
||||
if (this.reach_cache != null)
|
||||
{
|
||||
for (var i = this.reach_cache.length - 2; i >= 0; i--) {
|
||||
var p = this.reach_cache[i];
|
||||
// If we will have to go the same path.
|
||||
if (row >= p.row && row < p.row + p.opt.tv_size)
|
||||
{
|
||||
path.unshift(p);
|
||||
r = path[0].row;
|
||||
o = path[0].opt;
|
||||
}
|
||||
else
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
while (r != row)
|
||||
{
|
||||
// Go deeper in the child which contains the requested row. The
|
||||
// tv_size contains the size of the tree starting from each option.
|
||||
c = 0;
|
||||
while (c < o.subOptions.length && r + o.subOptions[c].tv_size < row)
|
||||
{
|
||||
r += o.subOptions[c].tv_size;
|
||||
c += 1;
|
||||
}
|
||||
if (c < o.subOptions.length && r + o.subOptions[c].tv_size >= row)
|
||||
{
|
||||
// Count the current option as a row.
|
||||
o = o.subOptions[c];
|
||||
r += 1;
|
||||
}
|
||||
else
|
||||
alert("WTF: " + o.name + " ask: " + row + " children: " + o.subOptions + " c: " + c);
|
||||
path.unshift({ row: r, opt: o });
|
||||
}
|
||||
|
||||
this.reach_cache = path;
|
||||
return path;
|
||||
},
|
||||
|
||||
// needs to return true if there is a /row/ at the same level /after/ a
|
||||
// given row.
|
||||
hasNextSibling: function(row, after) {
|
||||
log("sibling " + row + " after " + after);
|
||||
var path = reachRow(row);
|
||||
if (path.length > 1)
|
||||
{
|
||||
var last = path[1].row + path[1].opt.tv_size;
|
||||
// Has a next sibling if the row is not over the size of the
|
||||
// parent and if the current one is not the last child.
|
||||
return after + 1 < last && path[0].row + path[0].opt.tv_size < last;
|
||||
}
|
||||
else
|
||||
// The top-level option has no sibling.
|
||||
return false;
|
||||
},
|
||||
|
||||
// Does the current row contain any sub-options?
|
||||
isContainer: function(row) {
|
||||
return !this.reachRow(row)[0].opt.isOption;
|
||||
},
|
||||
isContainerEmpty: function(row) {
|
||||
return this.reachRow(row)[0].opt.subOptions.length == 0;
|
||||
},
|
||||
isContainerOpen: function(row) {
|
||||
return this.reachRow(row)[0].opt.tv_opened;
|
||||
},
|
||||
|
||||
// Open or close an option.
|
||||
toggleOpenState: function (row) {
|
||||
var path = this.reachRow(row);
|
||||
var delta = -path[0].opt.tv_size;
|
||||
if (path[0].opt.tv_opened)
|
||||
path[0].opt.tv_close();
|
||||
else
|
||||
path[0].opt.tv_open();
|
||||
delta += path[0].opt.tv_size;
|
||||
|
||||
// Parents are alreay opened, but we need to update the tv_size
|
||||
// counters. Thus we have to invalidate the reach cache.
|
||||
this.reach_cache = null;
|
||||
for (var i = 1; i < path.length; i++)
|
||||
path[i].opt.tv_open();
|
||||
|
||||
this.tree.rowCountChanged(row + 1, delta);
|
||||
},
|
||||
|
||||
// Return the identation level of the option at the line /row/. The
|
||||
// top-level level is 0.
|
||||
getLevel: function(row) {
|
||||
return this.reachRow(row).length - 1;
|
||||
},
|
||||
|
||||
// Obtain the index of a parent row. If there is no parent row,
|
||||
// returns -1.
|
||||
getParentIndex: function(row) {
|
||||
var path = this.reachRow(row);
|
||||
if (path.length > 1)
|
||||
return path[1].row;
|
||||
else
|
||||
return -1;
|
||||
},
|
||||
|
||||
|
||||
// Return the content of each row base on the column name.
|
||||
getCellText: function(row, column) {
|
||||
if (column.id == "opt-name")
|
||||
return this.reachRow(row)[0].opt.name;
|
||||
if (column.id == "dbg-size")
|
||||
return this.reachRow(row)[0].opt.tv_size;
|
||||
return "";
|
||||
},
|
||||
|
||||
// We have no column with images.
|
||||
getCellValue: function(row, column) { },
|
||||
|
||||
|
||||
isSelectable: function(row, column) { return true; },
|
||||
|
||||
// Get the selection out of the tree and give options to the call back
|
||||
// function.
|
||||
selectionChanged: function() {
|
||||
if (this.selCallback == null)
|
||||
return;
|
||||
var opts = [];
|
||||
var start = new Object();
|
||||
var end = new Object();
|
||||
var numRanges = this.tree.view.selection.getRangeCount();
|
||||
|
||||
for (var t = 0; t < numRanges; t++) {
|
||||
this.tree.view.selection.getRangeAt(t,start,end);
|
||||
for (var v = start.value; v <= end.value; v++) {
|
||||
var opt = this.reachRow(v)[0].opt;
|
||||
if (!opt.isLoaded)
|
||||
opt.load();
|
||||
if (opt.isOption)
|
||||
opts.push(opt);
|
||||
|
||||
// FIXME: no need to make things slowing down, because our current
|
||||
// callback do not handle multiple option display.
|
||||
if (!opts.empty)
|
||||
break;
|
||||
}
|
||||
// FIXME: no need to make things slowing down, because our current
|
||||
// callback do not handle multiple option display.
|
||||
if (!opts.empty)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!opts.empty)
|
||||
this.selCallback(opts);
|
||||
},
|
||||
|
||||
set rowCount(c) { throw "rowCount is a readonly property"; },
|
||||
get rowCount() { return this.rootOption.tv_size; },
|
||||
|
||||
// refuse drag-n-drop of options.
|
||||
canDrop: function (index, orientation, dataTransfer) { return false; },
|
||||
drop: function (index, orientation, dataTransfer) { },
|
||||
|
||||
// ?
|
||||
getCellProperties: function(row, column, prop) { },
|
||||
getColumnProperties: function(column, prop) { },
|
||||
getRowProperties: function(row, prop) { },
|
||||
getImageSrc: function(row, column) { },
|
||||
|
||||
// No progress columns are used.
|
||||
getProgressMode: function(row, column) { },
|
||||
|
||||
// Do not add options yet.
|
||||
isEditable: function(row, column) { return false; },
|
||||
setCellValue: function(row, column, value) { },
|
||||
setCellText: function(row, column, value) { },
|
||||
|
||||
// ...
|
||||
isSeparator: function(index) { return false; },
|
||||
isSorted: function() { return false; },
|
||||
performAction: function(action) { },
|
||||
performActionOnCell: function(action, row, column) { },
|
||||
performActionOnRow: function(action, row) { }, // ??
|
||||
|
||||
// ??
|
||||
cycleCell: function (row, col) { },
|
||||
cycleHeader: function(col) { },
|
||||
|
||||
selection: null,
|
||||
tree: null,
|
||||
setTree: function(tree) { this.tree = tree; }
|
||||
};
|
154
nixos/gui/components/clh.js
Normal file
154
nixos/gui/components/clh.js
Normal file
@ -0,0 +1,154 @@
|
||||
const nsIAppShellService = Components.interfaces.nsIAppShellService;
|
||||
const nsISupports = Components.interfaces.nsISupports;
|
||||
const nsICategoryManager = Components.interfaces.nsICategoryManager;
|
||||
const nsIComponentRegistrar = Components.interfaces.nsIComponentRegistrar;
|
||||
const nsICommandLine = Components.interfaces.nsICommandLine;
|
||||
const nsICommandLineHandler = Components.interfaces.nsICommandLineHandler;
|
||||
const nsIFactory = Components.interfaces.nsIFactory;
|
||||
const nsIModule = Components.interfaces.nsIModule;
|
||||
const nsIWindowWatcher = Components.interfaces.nsIWindowWatcher;
|
||||
|
||||
// CHANGEME: to the chrome URI of your extension or application
|
||||
const CHROME_URI = "chrome://nixos-gui/content/myviewer.xul";
|
||||
|
||||
// CHANGEME: change the contract id, CID, and category to be unique
|
||||
// to your application.
|
||||
const clh_contractID = "@mozilla.org/commandlinehandler/general-startup;1?type=myapp";
|
||||
|
||||
// use uuidgen to generate a unique ID
|
||||
const clh_CID = Components.ID("{2991c315-b871-42cd-b33f-bfee4fcbf682}");
|
||||
|
||||
// category names are sorted alphabetically. Typical command-line handlers use a
|
||||
// category that begins with the letter "m".
|
||||
const clh_category = "m-myapp";
|
||||
|
||||
/**
|
||||
* Utility functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Opens a chrome window.
|
||||
* @param aChromeURISpec a string specifying the URI of the window to open.
|
||||
* @param aArgument an argument to pass to the window (may be null)
|
||||
*/
|
||||
function openWindow(aChromeURISpec, aArgument)
|
||||
{
|
||||
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"].
|
||||
getService(Components.interfaces.nsIWindowWatcher);
|
||||
ww.openWindow(null, aChromeURISpec, "_blank",
|
||||
"chrome,menubar,toolbar,status,resizable,dialog=no",
|
||||
aArgument);
|
||||
}
|
||||
|
||||
/**
|
||||
* The XPCOM component that implements nsICommandLineHandler.
|
||||
* It also implements nsIFactory to serve as its own singleton factory.
|
||||
*/
|
||||
const myAppHandler = {
|
||||
/* nsISupports */
|
||||
QueryInterface : function clh_QI(iid)
|
||||
{
|
||||
if (iid.equals(nsICommandLineHandler) ||
|
||||
iid.equals(nsIFactory) ||
|
||||
iid.equals(nsISupports))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
/* nsICommandLineHandler */
|
||||
|
||||
handle : function clh_handle(cmdLine)
|
||||
{
|
||||
openWindow(CHROME_URI, cmdLine);
|
||||
cmdLine.preventDefault = true;
|
||||
},
|
||||
|
||||
// CHANGEME: change the help info as appropriate, but
|
||||
// follow the guidelines in nsICommandLineHandler.idl
|
||||
// specifically, flag descriptions should start at
|
||||
// character 24, and lines should be wrapped at
|
||||
// 72 characters with embedded newlines,
|
||||
// and finally, the string should end with a newline
|
||||
helpInfo : " <filename> Open the file in the viewer\n",
|
||||
|
||||
/* nsIFactory */
|
||||
|
||||
createInstance : function clh_CI(outer, iid)
|
||||
{
|
||||
if (outer != null)
|
||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
|
||||
return this.QueryInterface(iid);
|
||||
},
|
||||
|
||||
lockFactory : function clh_lock(lock)
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The XPCOM glue that implements nsIModule
|
||||
*/
|
||||
const myAppHandlerModule = {
|
||||
/* nsISupports */
|
||||
QueryInterface : function mod_QI(iid)
|
||||
{
|
||||
if (iid.equals(nsIModule) ||
|
||||
iid.equals(nsISupports))
|
||||
return this;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
/* nsIModule */
|
||||
getClassObject : function mod_gch(compMgr, cid, iid)
|
||||
{
|
||||
if (cid.equals(clh_CID))
|
||||
return myAppHandler.QueryInterface(iid);
|
||||
|
||||
throw Components.results.NS_ERROR_NOT_REGISTERED;
|
||||
},
|
||||
|
||||
registerSelf : function mod_regself(compMgr, fileSpec, location, type)
|
||||
{
|
||||
compMgr.QueryInterface(nsIComponentRegistrar);
|
||||
|
||||
compMgr.registerFactoryLocation(clh_CID,
|
||||
"myAppHandler",
|
||||
clh_contractID,
|
||||
fileSpec,
|
||||
location,
|
||||
type);
|
||||
|
||||
var catMan = Components.classes["@mozilla.org/categorymanager;1"].
|
||||
getService(nsICategoryManager);
|
||||
catMan.addCategoryEntry("command-line-handler",
|
||||
clh_category,
|
||||
clh_contractID, true, true);
|
||||
},
|
||||
|
||||
unregisterSelf : function mod_unreg(compMgr, location, type)
|
||||
{
|
||||
compMgr.QueryInterface(nsIComponentRegistrar);
|
||||
compMgr.unregisterFactoryLocation(clh_CID, location);
|
||||
|
||||
var catMan = Components.classes["@mozilla.org/categorymanager;1"].
|
||||
getService(nsICategoryManager);
|
||||
catMan.deleteCategoryEntry("command-line-handler", clh_category);
|
||||
},
|
||||
|
||||
canUnload : function (compMgr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/* The NSGetModule function is the magic entry point that XPCOM uses to find what XPCOM objects
|
||||
* this component provides
|
||||
*/
|
||||
function NSGetModule(comMgr, fileSpec)
|
||||
{
|
||||
return myAppHandlerModule;
|
||||
}
|
11
nixos/gui/defaults/preferences/myviewer-prefs.js
Normal file
11
nixos/gui/defaults/preferences/myviewer-prefs.js
Normal file
@ -0,0 +1,11 @@
|
||||
pref("toolkit.defaultChromeURI", "chrome://nixos-gui/content/myviewer.xul");
|
||||
pref("general.useragent.extra.myviewer", "NixOS gui/0.0");
|
||||
|
||||
/* debugging prefs */
|
||||
pref("browser.dom.window.dump.enabled", true); // enable output to stderr
|
||||
pref("javascript.options.showInConsole", true); // show javascript errors from chrome: files in the jsconsole
|
||||
pref("javascript.options.strict", true); // show javascript strict warnings in the jsconsole
|
||||
|
||||
/* disable xul cache so that modifications to chrome: files apply without restarting xulrunner */
|
||||
pref("nglayout.debug.disable_xul_cache", true);
|
||||
pref("nglayout.debug.disable_xul_fastload", true);
|
87
nixos/lib/build-vms.nix
Normal file
87
nixos/lib/build-vms.nix
Normal file
@ -0,0 +1,87 @@
|
||||
{ system, minimal ? false }:
|
||||
|
||||
let pkgs = import <nixpkgs> { config = {}; inherit system; }; in
|
||||
|
||||
with pkgs.lib;
|
||||
with import ../lib/qemu-flags.nix;
|
||||
|
||||
rec {
|
||||
|
||||
inherit pkgs;
|
||||
|
||||
|
||||
# Build a virtual network from an attribute set `{ machine1 =
|
||||
# config1; ... machineN = configN; }', where `machineX' is the
|
||||
# hostname and `configX' is a NixOS system configuration. Each
|
||||
# machine is given an arbitrary IP address in the virtual network.
|
||||
buildVirtualNetwork =
|
||||
nodes: let nodesOut = mapAttrs (n: buildVM nodesOut) (assignIPAddresses nodes); in nodesOut;
|
||||
|
||||
|
||||
buildVM =
|
||||
nodes: configurations:
|
||||
|
||||
import ./eval-config.nix {
|
||||
inherit system;
|
||||
modules = configurations ++
|
||||
[ ../modules/virtualisation/qemu-vm.nix
|
||||
../modules/testing/test-instrumentation.nix # !!! should only get added for automated test runs
|
||||
{ key = "no-manual"; services.nixosManual.enable = false; }
|
||||
] ++ optional minimal ../modules/testing/minimal-kernel.nix;
|
||||
extraArgs = { inherit nodes; };
|
||||
};
|
||||
|
||||
|
||||
# Given an attribute set { machine1 = config1; ... machineN =
|
||||
# configN; }, sequentially assign IP addresses in the 192.168.1.0/24
|
||||
# range to each machine, and set the hostname to the attribute name.
|
||||
assignIPAddresses = nodes:
|
||||
|
||||
let
|
||||
|
||||
machines = attrNames nodes;
|
||||
|
||||
machinesNumbered = zipTwoLists machines (range 1 254);
|
||||
|
||||
nodes_ = flip map machinesNumbered (m: nameValuePair m.first
|
||||
[ ( { config, pkgs, nodes, ... }:
|
||||
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";
|
||||
});
|
||||
in
|
||||
{ key = "ip-address";
|
||||
config =
|
||||
{ networking.hostName = m.first;
|
||||
|
||||
networking.interfaces = listToAttrs interfaces;
|
||||
|
||||
networking.primaryIPAddress =
|
||||
optionalString (interfaces != []) (head interfaces).value.ipAddress;
|
||||
|
||||
# Put the IP addresses of all VMs in this machine's
|
||||
# /etc/hosts file. If a machine has multiple
|
||||
# interfaces, use the IP address corresponding to
|
||||
# the first interface (i.e. the first network in its
|
||||
# virtualisation.vlans option).
|
||||
networking.extraHosts = flip concatMapStrings machines
|
||||
(m: let config = (getAttr m nodes).config; in
|
||||
optionalString (config.networking.primaryIPAddress != "")
|
||||
("${config.networking.primaryIPAddress} " +
|
||||
"${config.networking.hostName}\n"));
|
||||
|
||||
virtualisation.qemu.options =
|
||||
flip map interfacesNumbered
|
||||
({ first, second }: qemuNICFlags second first m.second);
|
||||
};
|
||||
}
|
||||
)
|
||||
(getAttr m.first nodes)
|
||||
] );
|
||||
|
||||
in listToAttrs nodes_;
|
||||
|
||||
}
|
6
nixos/lib/channel-expr.nix
Normal file
6
nixos/lib/channel-expr.nix
Normal file
@ -0,0 +1,6 @@
|
||||
{ system ? builtins.currentSystem }:
|
||||
|
||||
{ pkgs =
|
||||
(import nixpkgs/default.nix { inherit system; })
|
||||
// { recurseForDerivations = true; };
|
||||
}
|
73
nixos/lib/eval-config.nix
Normal file
73
nixos/lib/eval-config.nix
Normal file
@ -0,0 +1,73 @@
|
||||
# From an end-user configuration file (`configuration'), build a NixOS
|
||||
# configuration object (`config') from which we can retrieve option
|
||||
# values.
|
||||
|
||||
{ system ? builtins.currentSystem
|
||||
, pkgs ? null
|
||||
, baseModules ? import ../modules/module-list.nix
|
||||
, extraArgs ? {}
|
||||
, modules
|
||||
, nixpkgs ? <nixpkgs>
|
||||
}:
|
||||
|
||||
let extraArgs_ = extraArgs; pkgs_ = pkgs; system_ = system; in
|
||||
|
||||
rec {
|
||||
|
||||
# These are the NixOS modules that constitute the system configuration.
|
||||
configComponents = modules ++ baseModules;
|
||||
|
||||
# Merge the option definitions in all modules, forming the full
|
||||
# system configuration. It's not checked for undeclared options.
|
||||
systemModule =
|
||||
pkgs.lib.fixMergeModules configComponents extraArgs;
|
||||
|
||||
optionDefinitions = systemModule.config;
|
||||
optionDeclarations = systemModule.options;
|
||||
inherit (systemModule) options;
|
||||
|
||||
# These are the extra arguments passed to every module. In
|
||||
# particular, Nixpkgs is passed through the "pkgs" argument.
|
||||
extraArgs = extraArgs_ // {
|
||||
inherit pkgs modules baseModules;
|
||||
modulesPath = ../modules;
|
||||
pkgs_i686 = import nixpkgs { system = "i686-linux"; };
|
||||
utils = import ./utils.nix pkgs;
|
||||
};
|
||||
|
||||
# Import Nixpkgs, allowing the NixOS option nixpkgs.config to
|
||||
# specify the Nixpkgs configuration (e.g., to set package options
|
||||
# such as firefox.enableGeckoMediaPlayer, or to apply global
|
||||
# overrides such as changing GCC throughout the system), and the
|
||||
# option nixpkgs.system to override the platform type. This is
|
||||
# tricky, because we have to prevent an infinite recursion: "pkgs"
|
||||
# is passed as an argument to NixOS modules, but the value of "pkgs"
|
||||
# depends on config.nixpkgs.config, which we get from the modules.
|
||||
# So we call ourselves here with "pkgs" explicitly set to an
|
||||
# instance that doesn't depend on nixpkgs.config.
|
||||
pkgs =
|
||||
if pkgs_ != null
|
||||
then pkgs_
|
||||
else import nixpkgs (
|
||||
let
|
||||
system = if nixpkgsOptions.system != "" then nixpkgsOptions.system else system_;
|
||||
nixpkgsOptions = (import ./eval-config.nix {
|
||||
inherit system extraArgs modules;
|
||||
# For efficiency, leave out most NixOS modules; they don't
|
||||
# define nixpkgs.config, so it's pointless to evaluate them.
|
||||
baseModules = [ ../modules/misc/nixpkgs.nix ];
|
||||
pkgs = import nixpkgs { system = system_; config = {}; };
|
||||
}).optionDefinitions.nixpkgs;
|
||||
in
|
||||
{
|
||||
inherit system;
|
||||
inherit (nixpkgsOptions) config;
|
||||
});
|
||||
|
||||
# Optionally check wether all config values have corresponding
|
||||
# option declarations.
|
||||
config =
|
||||
let doCheck = optionDefinitions.environment.checkConfigurationOptions; in
|
||||
assert doCheck -> pkgs.lib.checkModule "" systemModule;
|
||||
systemModule.config;
|
||||
}
|
4
nixos/lib/from-env.nix
Normal file
4
nixos/lib/from-env.nix
Normal file
@ -0,0 +1,4 @@
|
||||
# TODO: remove this file. There is lib.maybeEnv now
|
||||
name: default:
|
||||
let value = builtins.getEnv name; in
|
||||
if value == "" then default else value
|
60
nixos/lib/make-iso9660-image.nix
Normal file
60
nixos/lib/make-iso9660-image.nix
Normal file
@ -0,0 +1,60 @@
|
||||
{ stdenv, perl, cdrkit, pathsFromGraph
|
||||
|
||||
, # The file name of the resulting ISO image.
|
||||
isoName ? "cd.iso"
|
||||
|
||||
, # The files and directories to be placed in the ISO file system.
|
||||
# This is a list of attribute sets {source, target} where `source'
|
||||
# is the file system object (regular file or directory) to be
|
||||
# grafted in the file system at path `target'.
|
||||
contents
|
||||
|
||||
, # In addition to `contents', the closure of the store paths listed
|
||||
# in `packages' are also placed in the Nix store of the CD. This is
|
||||
# a list of attribute sets {object, symlink} where `object' if a
|
||||
# store path whose closure will be copied, and `symlink' is a
|
||||
# symlink to `object' that will be added to the CD.
|
||||
storeContents ? []
|
||||
|
||||
, # Whether this should be an El-Torito bootable CD.
|
||||
bootable ? false
|
||||
|
||||
, # Whether this should be an efi-bootable El-Torito CD.
|
||||
efiBootable ? false
|
||||
|
||||
, # The path (in the ISO file system) of the boot image.
|
||||
bootImage ? ""
|
||||
|
||||
, # The path (in the ISO file system) of the efi boot image.
|
||||
efiBootImage ? ""
|
||||
|
||||
, # Whether to compress the resulting ISO image with bzip2.
|
||||
compressImage ? false
|
||||
|
||||
, # The volume ID.
|
||||
volumeID ? ""
|
||||
|
||||
}:
|
||||
|
||||
assert bootable -> bootImage != "";
|
||||
assert efiBootable -> efiBootImage != "";
|
||||
|
||||
stdenv.mkDerivation {
|
||||
name = "iso9660-image";
|
||||
builder = ./make-iso9660-image.sh;
|
||||
buildInputs = [perl cdrkit];
|
||||
|
||||
inherit isoName bootable bootImage compressImage volumeID pathsFromGraph efiBootImage efiBootable;
|
||||
|
||||
# !!! should use XML.
|
||||
sources = map (x: x.source) contents;
|
||||
targets = map (x: x.target) contents;
|
||||
|
||||
# !!! should use XML.
|
||||
objects = map (x: x.object) storeContents;
|
||||
symlinks = map (x: x.symlink) storeContents;
|
||||
|
||||
# For obtaining the closure of `storeContents'.
|
||||
exportReferencesGraph =
|
||||
map (x: [("closure-" + baseNameOf x.object) x.object]) storeContents;
|
||||
}
|
91
nixos/lib/make-iso9660-image.sh
Normal file
91
nixos/lib/make-iso9660-image.sh
Normal file
@ -0,0 +1,91 @@
|
||||
source $stdenv/setup
|
||||
|
||||
sources_=($sources)
|
||||
targets_=($targets)
|
||||
|
||||
objects=($objects)
|
||||
symlinks=($symlinks)
|
||||
|
||||
|
||||
# Remove the initial slash from a path, since genisofs likes it that way.
|
||||
stripSlash() {
|
||||
res="$1"
|
||||
if test "${res:0:1}" = /; then res=${res:1}; fi
|
||||
}
|
||||
|
||||
stripSlash "$bootImage"; bootImage="$res"
|
||||
|
||||
|
||||
if test -n "$bootable"; then
|
||||
|
||||
# The -boot-info-table option modifies the $bootImage file, so
|
||||
# find it in `contents' and make a copy of it (since the original
|
||||
# is read-only in the Nix store...).
|
||||
for ((i = 0; i < ${#targets_[@]}; i++)); do
|
||||
stripSlash "${targets_[$i]}"
|
||||
if test "$res" = "$bootImage"; then
|
||||
echo "copying the boot image ${sources_[$i]}"
|
||||
cp "${sources_[$i]}" boot.img
|
||||
chmod u+w boot.img
|
||||
sources_[$i]=boot.img
|
||||
fi
|
||||
done
|
||||
|
||||
bootFlags="-b $bootImage -c .boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table"
|
||||
fi
|
||||
|
||||
if test -n "$efiBootable"; then
|
||||
bootFlags="$bootFlags -eltorito-alt-boot -e $efiBootImage -no-emul-boot"
|
||||
fi
|
||||
|
||||
touch pathlist
|
||||
|
||||
|
||||
# Add the individual files.
|
||||
for ((i = 0; i < ${#targets_[@]}; i++)); do
|
||||
stripSlash "${targets_[$i]}"
|
||||
echo "$res=${sources_[$i]}" >> pathlist
|
||||
done
|
||||
|
||||
|
||||
# Add the closures of the top-level store objects.
|
||||
storePaths=$(perl $pathsFromGraph closure-*)
|
||||
for i in $storePaths; do
|
||||
echo "${i:1}=$i" >> pathlist
|
||||
done
|
||||
|
||||
|
||||
# Also include a manifest of the closures in a format suitable for
|
||||
# nix-store --load-db.
|
||||
if [ -n "$object" ]; then
|
||||
printRegistration=1 perl $pathsFromGraph closure-* > nix-path-registration
|
||||
echo "nix-path-registration=nix-path-registration" >> pathlist
|
||||
fi
|
||||
|
||||
|
||||
# Add symlinks to the top-level store objects.
|
||||
for ((n = 0; n < ${#objects[*]}; n++)); do
|
||||
object=${objects[$n]}
|
||||
symlink=${symlinks[$n]}
|
||||
if test "$symlink" != "none"; then
|
||||
mkdir -p $(dirname ./$symlink)
|
||||
ln -s $object ./$symlink
|
||||
echo "$symlink=./$symlink" >> pathlist
|
||||
fi
|
||||
done
|
||||
|
||||
# !!! what does this do?
|
||||
cat pathlist | sed -e 's/=\(.*\)=\(.*\)=/\\=\1=\2\\=/' | tee pathlist.safer
|
||||
|
||||
|
||||
ensureDir $out/iso
|
||||
genCommand="genisoimage -iso-level 4 -r -J $bootFlags -hide-rr-moved -graft-points -path-list pathlist.safer ${volumeID:+-V $volumeID}"
|
||||
if test -z "$compressImage"; then
|
||||
$genCommand -o $out/iso/$isoName
|
||||
else
|
||||
$genCommand | bzip2 > $out/iso/$isoName.bz2
|
||||
fi
|
||||
|
||||
|
||||
ensureDir $out/nix-support
|
||||
echo $system > $out/nix-support/system
|
30
nixos/lib/make-squashfs.nix
Normal file
30
nixos/lib/make-squashfs.nix
Normal file
@ -0,0 +1,30 @@
|
||||
{ stdenv, squashfsTools, perl, pathsFromGraph
|
||||
|
||||
, # The root directory of the squashfs filesystem is filled with the
|
||||
# closures of the Nix store paths listed here.
|
||||
storeContents ? []
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
name = "squashfs.img";
|
||||
|
||||
buildInputs = [perl squashfsTools];
|
||||
|
||||
# For obtaining the closure of `storeContents'.
|
||||
exportReferencesGraph =
|
||||
map (x: [("closure-" + baseNameOf x) x]) storeContents;
|
||||
|
||||
buildCommand =
|
||||
''
|
||||
# Add the closures of the top-level store objects.
|
||||
storePaths=$(perl ${pathsFromGraph} closure-*)
|
||||
|
||||
# Also include a manifest of the closures in a format suitable
|
||||
# for nix-store --load-db.
|
||||
printRegistration=1 perl ${pathsFromGraph} closure-* > nix-path-registration
|
||||
|
||||
# Generate the squashfs image.
|
||||
mksquashfs nix-path-registration $storePaths $out \
|
||||
-keep-as-directory -all-root
|
||||
'';
|
||||
}
|
38
nixos/lib/make-system-tarball.nix
Normal file
38
nixos/lib/make-system-tarball.nix
Normal file
@ -0,0 +1,38 @@
|
||||
{ stdenv, perl, xz, pathsFromGraph
|
||||
|
||||
, # The file name of the resulting tarball
|
||||
fileName ? "nixos-system-${stdenv.system}"
|
||||
|
||||
, # The files and directories to be placed in the tarball.
|
||||
# This is a list of attribute sets {source, target} where `source'
|
||||
# is the file system object (regular file or directory) to be
|
||||
# grafted in the file system at path `target'.
|
||||
contents
|
||||
|
||||
, # In addition to `contents', the closure of the store paths listed
|
||||
# in `packages' are also placed in the Nix store of the tarball. This is
|
||||
# a list of attribute sets {object, symlink} where `object' if a
|
||||
# store path whose closure will be copied, and `symlink' is a
|
||||
# symlink to `object' that will be added to the tarball.
|
||||
storeContents ? []
|
||||
}:
|
||||
|
||||
stdenv.mkDerivation {
|
||||
name = "tarball";
|
||||
builder = ./make-system-tarball.sh;
|
||||
buildInputs = [perl xz];
|
||||
|
||||
inherit fileName pathsFromGraph;
|
||||
|
||||
# !!! should use XML.
|
||||
sources = map (x: x.source) contents;
|
||||
targets = map (x: x.target) contents;
|
||||
|
||||
# !!! should use XML.
|
||||
objects = map (x: x.object) storeContents;
|
||||
symlinks = map (x: x.symlink) storeContents;
|
||||
|
||||
# For obtaining the closure of `storeContents'.
|
||||
exportReferencesGraph =
|
||||
map (x: [("closure-" + baseNameOf x.object) x.object]) storeContents;
|
||||
}
|
58
nixos/lib/make-system-tarball.sh
Normal file
58
nixos/lib/make-system-tarball.sh
Normal file
@ -0,0 +1,58 @@
|
||||
source $stdenv/setup
|
||||
set -x
|
||||
|
||||
sources_=($sources)
|
||||
targets_=($targets)
|
||||
|
||||
echo $objects
|
||||
objects=($objects)
|
||||
symlinks=($symlinks)
|
||||
|
||||
|
||||
# Remove the initial slash from a path, since genisofs likes it that way.
|
||||
stripSlash() {
|
||||
res="$1"
|
||||
if test "${res:0:1}" = /; then res=${res:1}; fi
|
||||
}
|
||||
|
||||
touch pathlist
|
||||
|
||||
# Add the individual files.
|
||||
for ((i = 0; i < ${#targets_[@]}; i++)); do
|
||||
stripSlash "${targets_[$i]}"
|
||||
mkdir -p "$(dirname "$res")"
|
||||
cp -a "${sources_[$i]}" "$res"
|
||||
done
|
||||
|
||||
|
||||
# Add the closures of the top-level store objects.
|
||||
mkdir -p nix/store
|
||||
storePaths=$(perl $pathsFromGraph closure-*)
|
||||
for i in $storePaths; do
|
||||
cp -a "$i" "${i:1}"
|
||||
done
|
||||
|
||||
|
||||
# TODO tar ruxo
|
||||
# Also include a manifest of the closures in a format suitable for
|
||||
# nix-store --load-db.
|
||||
printRegistration=1 perl $pathsFromGraph closure-* > nix-path-registration
|
||||
|
||||
# Add symlinks to the top-level store objects.
|
||||
for ((n = 0; n < ${#objects[*]}; n++)); do
|
||||
object=${objects[$n]}
|
||||
symlink=${symlinks[$n]}
|
||||
if test "$symlink" != "none"; then
|
||||
mkdir -p $(dirname ./$symlink)
|
||||
ln -s $object ./$symlink
|
||||
fi
|
||||
done
|
||||
|
||||
ensureDir $out/tarball
|
||||
|
||||
tar cvJf $out/tarball/$fileName.tar.xz *
|
||||
|
||||
ensureDir $out/nix-support
|
||||
echo $system > $out/nix-support/system
|
||||
echo "file system-tarball $out/tarball/$fileName.tar.xz" > $out/nix-support/hydra-build-products
|
||||
|
10
nixos/lib/qemu-flags.nix
Normal file
10
nixos/lib/qemu-flags.nix
Normal file
@ -0,0 +1,10 @@
|
||||
# QEMU flags shared between various Nix expressions.
|
||||
|
||||
{
|
||||
|
||||
qemuNICFlags = nic: net: machine:
|
||||
[ "-net nic,vlan=${toString nic},macaddr=52:54:00:12:${toString net}:${toString machine},model=virtio"
|
||||
"-net vde,vlan=${toString nic},sock=$QEMU_VDE_SOCKET_${toString net}"
|
||||
];
|
||||
|
||||
}
|
70
nixos/lib/test-driver/Logger.pm
Normal file
70
nixos/lib/test-driver/Logger.pm
Normal file
@ -0,0 +1,70 @@
|
||||
package Logger;
|
||||
|
||||
use strict;
|
||||
use Thread::Queue;
|
||||
use XML::Writer;
|
||||
|
||||
sub new {
|
||||
my ($class) = @_;
|
||||
|
||||
my $logFile = defined $ENV{LOGFILE} ? "$ENV{LOGFILE}" : "/dev/null";
|
||||
my $log = new XML::Writer(OUTPUT => new IO::File(">$logFile"));
|
||||
|
||||
my $self = {
|
||||
log => $log,
|
||||
logQueue => Thread::Queue->new()
|
||||
};
|
||||
|
||||
$self->{log}->startTag("logfile");
|
||||
|
||||
bless $self, $class;
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub close {
|
||||
my ($self) = @_;
|
||||
$self->{log}->endTag("logfile");
|
||||
$self->{log}->end;
|
||||
}
|
||||
|
||||
sub drainLogQueue {
|
||||
my ($self) = @_;
|
||||
while (defined (my $item = $self->{logQueue}->dequeue_nb())) {
|
||||
$self->{log}->dataElement("line", sanitise($item->{msg}), 'machine' => $item->{machine}, 'type' => 'serial');
|
||||
}
|
||||
}
|
||||
|
||||
sub maybePrefix {
|
||||
my ($msg, $attrs) = @_;
|
||||
$msg = $attrs->{machine} . ": " . $msg if defined $attrs->{machine};
|
||||
return $msg;
|
||||
}
|
||||
|
||||
sub nest {
|
||||
my ($self, $msg, $coderef, $attrs) = @_;
|
||||
print STDERR maybePrefix("$msg\n", $attrs);
|
||||
$self->{log}->startTag("nest");
|
||||
$self->{log}->dataElement("head", $msg, %{$attrs});
|
||||
$self->drainLogQueue();
|
||||
eval { &$coderef };
|
||||
my $res = $@;
|
||||
$self->drainLogQueue();
|
||||
$self->{log}->endTag("nest");
|
||||
die $@ if $@;
|
||||
}
|
||||
|
||||
sub sanitise {
|
||||
my ($s) = @_;
|
||||
$s =~ s/[[:cntrl:]\xff]//g;
|
||||
return $s;
|
||||
}
|
||||
|
||||
sub log {
|
||||
my ($self, $msg, $attrs) = @_;
|
||||
chomp $msg;
|
||||
print STDERR maybePrefix("$msg\n", $attrs);
|
||||
$self->drainLogQueue();
|
||||
$self->{log}->dataElement("line", $msg, %{$attrs});
|
||||
}
|
||||
|
||||
1;
|
568
nixos/lib/test-driver/Machine.pm
Normal file
568
nixos/lib/test-driver/Machine.pm
Normal file
@ -0,0 +1,568 @@
|
||||
package Machine;
|
||||
|
||||
use strict;
|
||||
use threads;
|
||||
use Socket;
|
||||
use IO::Handle;
|
||||
use POSIX qw(dup2);
|
||||
use FileHandle;
|
||||
use Cwd;
|
||||
use File::Basename;
|
||||
use File::Path qw(make_path);
|
||||
|
||||
|
||||
my $showGraphics = defined $ENV{'DISPLAY'};
|
||||
|
||||
my $sharedDir;
|
||||
|
||||
|
||||
sub new {
|
||||
my ($class, $args) = @_;
|
||||
|
||||
my $startCommand = $args->{startCommand};
|
||||
|
||||
my $name = $args->{name};
|
||||
if (!$name) {
|
||||
$startCommand =~ /run-(.*)-vm$/ if defined $startCommand;
|
||||
$name = $1 || "machine";
|
||||
}
|
||||
|
||||
if (!$startCommand) {
|
||||
# !!! merge with qemu-vm.nix.
|
||||
$startCommand =
|
||||
"qemu-kvm -m 384 " .
|
||||
"-net nic,model=virtio \$QEMU_OPTS ";
|
||||
my $iface = $args->{hdaInterface} || "virtio";
|
||||
$startCommand .= "-drive file=" . Cwd::abs_path($args->{hda}) . ",if=$iface,boot=on,werror=report "
|
||||
if defined $args->{hda};
|
||||
$startCommand .= "-cdrom $args->{cdrom} "
|
||||
if defined $args->{cdrom};
|
||||
$startCommand .= $args->{qemuFlags} || "";
|
||||
} else {
|
||||
$startCommand = Cwd::abs_path $startCommand;
|
||||
}
|
||||
|
||||
my $tmpDir = $ENV{'TMPDIR'} || "/tmp";
|
||||
unless (defined $sharedDir) {
|
||||
$sharedDir = $tmpDir . "/xchg-shared";
|
||||
make_path($sharedDir, { mode => 0700, owner => $< });
|
||||
}
|
||||
|
||||
my $allowReboot = 0;
|
||||
$allowReboot = $args->{allowReboot} if defined $args->{allowReboot};
|
||||
|
||||
my $self = {
|
||||
startCommand => $startCommand,
|
||||
name => $name,
|
||||
allowReboot => $allowReboot,
|
||||
booted => 0,
|
||||
pid => 0,
|
||||
connected => 0,
|
||||
socket => undef,
|
||||
stateDir => "$tmpDir/vm-state-$name",
|
||||
monitor => undef,
|
||||
log => $args->{log},
|
||||
redirectSerial => $args->{redirectSerial} // 1,
|
||||
};
|
||||
|
||||
mkdir $self->{stateDir}, 0700;
|
||||
|
||||
bless $self, $class;
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
sub log {
|
||||
my ($self, $msg) = @_;
|
||||
$self->{log}->log($msg, { machine => $self->{name} });
|
||||
}
|
||||
|
||||
|
||||
sub nest {
|
||||
my ($self, $msg, $coderef, $attrs) = @_;
|
||||
$self->{log}->nest($msg, $coderef, { %{$attrs || {}}, machine => $self->{name} });
|
||||
}
|
||||
|
||||
|
||||
sub name {
|
||||
my ($self) = @_;
|
||||
return $self->{name};
|
||||
}
|
||||
|
||||
|
||||
sub stateDir {
|
||||
my ($self) = @_;
|
||||
return $self->{stateDir};
|
||||
}
|
||||
|
||||
|
||||
sub start {
|
||||
my ($self) = @_;
|
||||
return if $self->{booted};
|
||||
|
||||
$self->log("starting vm");
|
||||
|
||||
# Create a socket pair for the serial line input/output of the VM.
|
||||
my ($serialP, $serialC);
|
||||
socketpair($serialP, $serialC, PF_UNIX, SOCK_STREAM, 0) or die;
|
||||
|
||||
# Create a Unix domain socket to which QEMU's monitor will connect.
|
||||
my $monitorPath = $self->{stateDir} . "/monitor";
|
||||
unlink $monitorPath;
|
||||
my $monitorS;
|
||||
socket($monitorS, PF_UNIX, SOCK_STREAM, 0) or die;
|
||||
bind($monitorS, sockaddr_un($monitorPath)) or die "cannot bind monitor socket: $!";
|
||||
listen($monitorS, 1) or die;
|
||||
|
||||
# Create a Unix domain socket to which the root shell in the guest will connect.
|
||||
my $shellPath = $self->{stateDir} . "/shell";
|
||||
unlink $shellPath;
|
||||
my $shellS;
|
||||
socket($shellS, PF_UNIX, SOCK_STREAM, 0) or die;
|
||||
bind($shellS, sockaddr_un($shellPath)) or die "cannot bind shell socket: $!";
|
||||
listen($shellS, 1) or die;
|
||||
|
||||
# Start the VM.
|
||||
my $pid = fork();
|
||||
die if $pid == -1;
|
||||
|
||||
if ($pid == 0) {
|
||||
close $serialP;
|
||||
close $monitorS;
|
||||
close $shellS;
|
||||
if ($self->{redirectSerial}) {
|
||||
open NUL, "</dev/null" or die;
|
||||
dup2(fileno(NUL), fileno(STDIN));
|
||||
dup2(fileno($serialC), fileno(STDOUT));
|
||||
dup2(fileno($serialC), fileno(STDERR));
|
||||
}
|
||||
$ENV{TMPDIR} = $self->{stateDir};
|
||||
$ENV{SHARED_DIR} = $sharedDir;
|
||||
$ENV{USE_TMPDIR} = 1;
|
||||
$ENV{QEMU_OPTS} =
|
||||
($self->{allowReboot} ? "" : "-no-reboot ") .
|
||||
"-monitor unix:./monitor -chardev socket,id=shell,path=./shell " .
|
||||
"-device virtio-serial -device virtconsole,chardev=shell " .
|
||||
($showGraphics ? "-serial stdio" : "-nographic") . " " . ($ENV{QEMU_OPTS} || "");
|
||||
chdir $self->{stateDir} or die;
|
||||
exec $self->{startCommand};
|
||||
die "running VM script: $!";
|
||||
}
|
||||
|
||||
# Process serial line output.
|
||||
close $serialC;
|
||||
|
||||
threads->create(\&processSerialOutput, $self, $serialP)->detach;
|
||||
|
||||
sub processSerialOutput {
|
||||
my ($self, $serialP) = @_;
|
||||
while (<$serialP>) {
|
||||
chomp;
|
||||
s/\r$//;
|
||||
print STDERR $self->{name}, "# $_\n";
|
||||
$self->{log}->{logQueue}->enqueue({msg => $_, machine => $self->{name}}); # !!!
|
||||
}
|
||||
}
|
||||
|
||||
eval {
|
||||
local $SIG{CHLD} = sub { die "QEMU died prematurely\n"; };
|
||||
|
||||
# Wait until QEMU connects to the monitor.
|
||||
accept($self->{monitor}, $monitorS) or die;
|
||||
|
||||
# Wait until QEMU connects to the root shell socket. QEMU
|
||||
# does so immediately; this doesn't mean that the root shell
|
||||
# has connected yet inside the guest.
|
||||
accept($self->{socket}, $shellS) or die;
|
||||
$self->{socket}->autoflush(1);
|
||||
};
|
||||
die "$@" if $@;
|
||||
|
||||
$self->waitForMonitorPrompt;
|
||||
|
||||
$self->log("QEMU running (pid $pid)");
|
||||
|
||||
$self->{pid} = $pid;
|
||||
$self->{booted} = 1;
|
||||
}
|
||||
|
||||
|
||||
# Send a command to the monitor and wait for it to finish. TODO: QEMU
|
||||
# also has a JSON-based monitor interface now, but it doesn't support
|
||||
# all commands yet. We should use it once it does.
|
||||
sub sendMonitorCommand {
|
||||
my ($self, $command) = @_;
|
||||
$self->log("sending monitor command: $command");
|
||||
syswrite $self->{monitor}, "$command\n";
|
||||
return $self->waitForMonitorPrompt;
|
||||
}
|
||||
|
||||
|
||||
# Wait until the monitor sends "(qemu) ".
|
||||
sub waitForMonitorPrompt {
|
||||
my ($self) = @_;
|
||||
my $res = "";
|
||||
my $s;
|
||||
while (sysread($self->{monitor}, $s, 1024)) {
|
||||
$res .= $s;
|
||||
last if $res =~ s/\(qemu\) $//;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
# Call the given code reference repeatedly, with 1 second intervals,
|
||||
# until it returns 1 or a timeout is reached.
|
||||
sub retry {
|
||||
my ($coderef) = @_;
|
||||
my $n;
|
||||
for ($n = 0; $n < 900; $n++) {
|
||||
return if &$coderef;
|
||||
sleep 1;
|
||||
}
|
||||
die "action timed out after $n seconds";
|
||||
}
|
||||
|
||||
|
||||
sub connect {
|
||||
my ($self) = @_;
|
||||
return if $self->{connected};
|
||||
|
||||
$self->nest("waiting for the VM to finish booting", sub {
|
||||
|
||||
$self->start;
|
||||
|
||||
local $SIG{ALRM} = sub { die "timed out waiting for the VM to connect\n"; };
|
||||
alarm 300;
|
||||
readline $self->{socket} or die "the VM quit before connecting\n";
|
||||
alarm 0;
|
||||
|
||||
$self->log("connected to guest root shell");
|
||||
$self->{connected} = 1;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub waitForShutdown {
|
||||
my ($self) = @_;
|
||||
return unless $self->{booted};
|
||||
|
||||
$self->nest("waiting for the VM to power off", sub {
|
||||
waitpid $self->{pid}, 0;
|
||||
$self->{pid} = 0;
|
||||
$self->{booted} = 0;
|
||||
$self->{connected} = 0;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub isUp {
|
||||
my ($self) = @_;
|
||||
return $self->{booted} && $self->{connected};
|
||||
}
|
||||
|
||||
|
||||
sub execute_ {
|
||||
my ($self, $command) = @_;
|
||||
|
||||
$self->connect;
|
||||
|
||||
print { $self->{socket} } ("( $command ); echo '|!=EOF' \$?\n");
|
||||
|
||||
my $out = "";
|
||||
|
||||
while (1) {
|
||||
my $line = readline($self->{socket});
|
||||
die "connection to VM lost unexpectedly" unless defined $line;
|
||||
#$self->log("got line: $line");
|
||||
if ($line =~ /^(.*)\|\!\=EOF\s+(\d+)$/) {
|
||||
$out .= $1;
|
||||
$self->log("exit status $2");
|
||||
return ($2, $out);
|
||||
}
|
||||
$out .= $line;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub execute {
|
||||
my ($self, $command) = @_;
|
||||
my @res;
|
||||
$self->nest("running command: $command", sub {
|
||||
@res = $self->execute_($command);
|
||||
});
|
||||
return @res;
|
||||
}
|
||||
|
||||
|
||||
sub succeed {
|
||||
my ($self, @commands) = @_;
|
||||
|
||||
my $res;
|
||||
foreach my $command (@commands) {
|
||||
$self->nest("must succeed: $command", sub {
|
||||
my ($status, $out) = $self->execute_($command);
|
||||
if ($status != 0) {
|
||||
$self->log("output: $out");
|
||||
die "command `$command' did not succeed (exit code $status)\n";
|
||||
}
|
||||
$res .= $out;
|
||||
});
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
sub mustSucceed {
|
||||
succeed @_;
|
||||
}
|
||||
|
||||
|
||||
sub waitUntilSucceeds {
|
||||
my ($self, $command) = @_;
|
||||
$self->nest("waiting for success: $command", sub {
|
||||
retry sub {
|
||||
my ($status, $out) = $self->execute($command);
|
||||
return 1 if $status == 0;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub waitUntilFails {
|
||||
my ($self, $command) = @_;
|
||||
$self->nest("waiting for failure: $command", sub {
|
||||
retry sub {
|
||||
my ($status, $out) = $self->execute($command);
|
||||
return 1 if $status != 0;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub fail {
|
||||
my ($self, $command) = @_;
|
||||
$self->nest("must fail: $command", sub {
|
||||
my ($status, $out) = $self->execute_($command);
|
||||
die "command `$command' unexpectedly succeeded"
|
||||
if $status == 0;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub mustFail {
|
||||
fail @_;
|
||||
}
|
||||
|
||||
|
||||
sub getUnitInfo {
|
||||
my ($self, $unit) = @_;
|
||||
my ($status, $lines) = $self->execute("systemctl --no-pager show '$unit'");
|
||||
return undef if $status != 0;
|
||||
my $info = {};
|
||||
foreach my $line (split '\n', $lines) {
|
||||
$line =~ /^([^=]+)=(.*)$/ or next;
|
||||
$info->{$1} = $2;
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
|
||||
# Wait for a systemd unit to reach the "active" state.
|
||||
sub waitForUnit {
|
||||
my ($self, $unit) = @_;
|
||||
$self->nest("waiting for unit ‘$unit’", sub {
|
||||
retry sub {
|
||||
my $info = $self->getUnitInfo($unit);
|
||||
my $state = $info->{ActiveState};
|
||||
die "unit ‘$unit’ reached state ‘$state’\n" if $state eq "failed";
|
||||
return 1 if $state eq "active";
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub waitForJob {
|
||||
my ($self, $jobName) = @_;
|
||||
return $self->waitForUnit($jobName);
|
||||
}
|
||||
|
||||
|
||||
# Wait until the specified file exists.
|
||||
sub waitForFile {
|
||||
my ($self, $fileName) = @_;
|
||||
$self->nest("waiting for file ‘$fileName’", sub {
|
||||
retry sub {
|
||||
my ($status, $out) = $self->execute("test -e $fileName");
|
||||
return 1 if $status == 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sub startJob {
|
||||
my ($self, $jobName) = @_;
|
||||
$self->execute("systemctl start $jobName");
|
||||
# FIXME: check result
|
||||
}
|
||||
|
||||
sub stopJob {
|
||||
my ($self, $jobName) = @_;
|
||||
$self->execute("systemctl stop $jobName");
|
||||
}
|
||||
|
||||
|
||||
# Wait until the machine is listening on the given TCP port.
|
||||
sub waitForOpenPort {
|
||||
my ($self, $port) = @_;
|
||||
$self->nest("waiting for TCP port $port", sub {
|
||||
retry sub {
|
||||
my ($status, $out) = $self->execute("nc -z localhost $port");
|
||||
return 1 if $status == 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
# Wait until the machine is not listening on the given TCP port.
|
||||
sub waitForClosedPort {
|
||||
my ($self, $port) = @_;
|
||||
retry sub {
|
||||
my ($status, $out) = $self->execute("nc -z localhost $port");
|
||||
return 1 if $status != 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub shutdown {
|
||||
my ($self) = @_;
|
||||
return unless $self->{booted};
|
||||
|
||||
print { $self->{socket} } ("poweroff\n");
|
||||
|
||||
$self->waitForShutdown;
|
||||
}
|
||||
|
||||
|
||||
sub crash {
|
||||
my ($self) = @_;
|
||||
return unless $self->{booted};
|
||||
|
||||
$self->log("forced crash");
|
||||
|
||||
$self->sendMonitorCommand("quit");
|
||||
|
||||
$self->waitForShutdown;
|
||||
}
|
||||
|
||||
|
||||
# Make the machine unreachable by shutting down eth1 (the multicast
|
||||
# interface used to talk to the other VMs). We keep eth0 up so that
|
||||
# the test driver can continue to talk to the machine.
|
||||
sub block {
|
||||
my ($self) = @_;
|
||||
$self->sendMonitorCommand("set_link virtio-net-pci.1 off");
|
||||
}
|
||||
|
||||
|
||||
# Make the machine reachable.
|
||||
sub unblock {
|
||||
my ($self) = @_;
|
||||
$self->sendMonitorCommand("set_link virtio-net-pci.1 on");
|
||||
}
|
||||
|
||||
|
||||
# Take a screenshot of the X server on :0.0.
|
||||
sub screenshot {
|
||||
my ($self, $filename) = @_;
|
||||
my $dir = $ENV{'out'} || Cwd::abs_path(".");
|
||||
$filename = "$dir/${filename}.png" if $filename =~ /^\w+$/;
|
||||
my $tmp = "${filename}.ppm";
|
||||
my $name = basename($filename);
|
||||
$self->nest("making screenshot ‘$name’", sub {
|
||||
$self->sendMonitorCommand("screendump $tmp");
|
||||
system("convert $tmp ${filename}") == 0
|
||||
or die "cannot convert screenshot";
|
||||
unlink $tmp;
|
||||
}, { image => $name } );
|
||||
}
|
||||
|
||||
|
||||
# Wait until it is possible to connect to the X server. Note that
|
||||
# testing the existence of /tmp/.X11-unix/X0 is insufficient.
|
||||
sub waitForX {
|
||||
my ($self, $regexp) = @_;
|
||||
$self->nest("waiting for the X11 server", sub {
|
||||
retry sub {
|
||||
my ($status, $out) = $self->execute("xwininfo -root > /dev/null 2>&1");
|
||||
return 1 if $status == 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub getWindowNames {
|
||||
my ($self) = @_;
|
||||
my $res = $self->mustSucceed(
|
||||
q{xwininfo -root -tree | sed 's/.*0x[0-9a-f]* \"\([^\"]*\)\".*/\1/; t; d'});
|
||||
return split /\n/, $res;
|
||||
}
|
||||
|
||||
|
||||
sub waitForWindow {
|
||||
my ($self, $regexp) = @_;
|
||||
$self->nest("waiting for a window to appear", sub {
|
||||
retry sub {
|
||||
my @names = $self->getWindowNames;
|
||||
foreach my $n (@names) {
|
||||
return 1 if $n =~ /$regexp/;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub copyFileFromHost {
|
||||
my ($self, $from, $to) = @_;
|
||||
my $s = `cat $from` or die;
|
||||
$self->mustSucceed("echo '$s' > $to"); # !!! escaping
|
||||
}
|
||||
|
||||
|
||||
sub sendKeys {
|
||||
my ($self, @keys) = @_;
|
||||
foreach my $key (@keys) {
|
||||
$key = "spc" if $key eq " ";
|
||||
$key = "ret" if $key eq "\n";
|
||||
$self->sendMonitorCommand("sendkey $key");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sub sendChars {
|
||||
my ($self, $chars) = @_;
|
||||
$self->nest("sending keys ‘$chars’", sub {
|
||||
$self->sendKeys(split //, $chars);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
# Sleep N seconds (in virtual guest time, not real time).
|
||||
sub sleep {
|
||||
my ($self, $time) = @_;
|
||||
$self->succeed("sleep $time");
|
||||
}
|
||||
|
||||
|
||||
# Forward a TCP port on the host to a TCP port on the guest. Useful
|
||||
# during interactive testing.
|
||||
sub forwardPort {
|
||||
my ($self, $hostPort, $guestPort) = @_;
|
||||
$hostPort = 8080 unless defined $hostPort;
|
||||
$guestPort = 80 unless defined $guestPort;
|
||||
$self->sendMonitorCommand("hostfwd_add tcp::$hostPort-:$guestPort");
|
||||
}
|
||||
|
||||
|
||||
1;
|
135
nixos/lib/test-driver/log2html.xsl
Normal file
135
nixos/lib/test-driver/log2html.xsl
Normal file
@ -0,0 +1,135 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
|
||||
<xsl:output method='html' encoding="UTF-8"
|
||||
doctype-public="-//W3C//DTD HTML 4.01//EN"
|
||||
doctype-system="http://www.w3.org/TR/html4/strict.dtd" />
|
||||
|
||||
<xsl:template match="logfile">
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js"></script>
|
||||
<script type="text/javascript" src="treebits.js" />
|
||||
<link rel="stylesheet" href="logfile.css" type="text/css" />
|
||||
<title>Log File</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>VM build log</h1>
|
||||
<p>
|
||||
<a href="javascript:" class="logTreeExpandAll">Expand all</a> |
|
||||
<a href="javascript:" class="logTreeCollapseAll">Collapse all</a>
|
||||
</p>
|
||||
<ul class='toplevel'>
|
||||
<xsl:for-each select='line|nest'>
|
||||
<li>
|
||||
<xsl:apply-templates select='.'/>
|
||||
</li>
|
||||
</xsl:for-each>
|
||||
</ul>
|
||||
|
||||
<xsl:if test=".//*[@image]">
|
||||
<h1>Screenshots</h1>
|
||||
<ul class="vmScreenshots">
|
||||
<xsl:for-each select='.//*[@image]'>
|
||||
<li><a href="{@image}"><xsl:value-of select="@image" /></a></li>
|
||||
</xsl:for-each>
|
||||
</ul>
|
||||
</xsl:if>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="nest">
|
||||
|
||||
<!-- The tree should be collapsed by default if all children are
|
||||
unimportant or if the header is unimportant. -->
|
||||
<xsl:variable name="collapsed" select="not(./head[@expanded]) and count(.//*[@error]) = 0"/>
|
||||
|
||||
<xsl:variable name="style"><xsl:if test="$collapsed">display: none;</xsl:if></xsl:variable>
|
||||
|
||||
<xsl:if test="line|nest">
|
||||
<a href="javascript:" class="logTreeToggle">
|
||||
<xsl:choose>
|
||||
<xsl:when test="$collapsed"><xsl:text>+</xsl:text></xsl:when>
|
||||
<xsl:otherwise><xsl:text>-</xsl:text></xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</a>
|
||||
<xsl:text> </xsl:text>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:apply-templates select='head'/>
|
||||
|
||||
<!-- Be careful to only generate <ul>s if there are <li>s, otherwise it’s malformed. -->
|
||||
<xsl:if test="line|nest">
|
||||
|
||||
<ul class='nesting' style="{$style}">
|
||||
<xsl:for-each select='line|nest'>
|
||||
|
||||
<!-- Is this the last line? If so, mark it as such so that it
|
||||
can be rendered differently. -->
|
||||
<xsl:variable name="class"><xsl:choose><xsl:when test="position() != last()">line</xsl:when><xsl:otherwise>lastline</xsl:otherwise></xsl:choose></xsl:variable>
|
||||
|
||||
<li class='{$class}'>
|
||||
<span class='lineconn' />
|
||||
<span class='linebody'>
|
||||
<xsl:apply-templates select='.'/>
|
||||
</span>
|
||||
</li>
|
||||
</xsl:for-each>
|
||||
</ul>
|
||||
</xsl:if>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="head|line">
|
||||
<code>
|
||||
<xsl:if test="@error">
|
||||
<xsl:attribute name="class">errorLine</xsl:attribute>
|
||||
</xsl:if>
|
||||
<xsl:if test="@warning">
|
||||
<xsl:attribute name="class">warningLine</xsl:attribute>
|
||||
</xsl:if>
|
||||
<xsl:if test="@priority = 3">
|
||||
<xsl:attribute name="class">prio3</xsl:attribute>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="@type = 'serial'">
|
||||
<xsl:attribute name="class">serial</xsl:attribute>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="@machine">
|
||||
<xsl:choose>
|
||||
<xsl:when test="@type = 'serial'">
|
||||
<span class="machine"><xsl:value-of select="@machine"/># </span>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<span class="machine"><xsl:value-of select="@machine"/>: </span>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:choose>
|
||||
<xsl:when test="@image">
|
||||
<a href="{@image}"><xsl:apply-templates/></a>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<xsl:apply-templates/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</code>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="storeref">
|
||||
<em class='storeref'>
|
||||
<span class='popup'><xsl:apply-templates/></span>
|
||||
<span class='elided'>/...</span><xsl:apply-templates select='name'/><xsl:apply-templates select='path'/>
|
||||
</em>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
129
nixos/lib/test-driver/logfile.css
Normal file
129
nixos/lib/test-driver/logfile.css
Normal file
@ -0,0 +1,129 @@
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
background: white;
|
||||
}
|
||||
|
||||
h1
|
||||
{
|
||||
color: #005aa0;
|
||||
font-size: 180%;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
ul.nesting, ul.toplevel {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ul.toplevel {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.line, .head {
|
||||
padding-top: 0em;
|
||||
}
|
||||
|
||||
ul.nesting li.line, ul.nesting li.lastline {
|
||||
position: relative;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
ul.nesting li.line {
|
||||
padding-left: 2.0em;
|
||||
}
|
||||
|
||||
ul.nesting li.lastline {
|
||||
padding-left: 2.1em; /* for the 0.1em border-left in .lastline > .lineconn */
|
||||
}
|
||||
|
||||
li.line {
|
||||
border-left: 0.1em solid #6185a0;
|
||||
}
|
||||
|
||||
li.line > span.lineconn, li.lastline > span.lineconn {
|
||||
position: absolute;
|
||||
height: 0.65em;
|
||||
left: 0em;
|
||||
width: 1.5em;
|
||||
border-bottom: 0.1em solid #6185a0;
|
||||
}
|
||||
|
||||
li.lastline > span.lineconn {
|
||||
border-left: 0.1em solid #6185a0;
|
||||
}
|
||||
|
||||
|
||||
em.storeref {
|
||||
color: #500000;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
em.storeref:hover {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
*.popup {
|
||||
display: none;
|
||||
/* background: url('http://losser.st-lab.cs.uu.nl/~mbravenb/menuback.png') repeat; */
|
||||
background: #ffffcd;
|
||||
border: solid #555555 1px;
|
||||
position: absolute;
|
||||
top: 0em;
|
||||
left: 0em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
em.storeref:hover span.popup {
|
||||
display: inline;
|
||||
width: 40em;
|
||||
}
|
||||
|
||||
|
||||
.logTreeToggle {
|
||||
text-decoration: none;
|
||||
font-family: monospace;
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
.errorLine {
|
||||
color: #ff0000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.warningLine {
|
||||
color: darkorange;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.prio3 {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
code {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.serial {
|
||||
color: #56115c;
|
||||
}
|
||||
|
||||
.machine {
|
||||
color: #002399;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
ul.vmScreenshots {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
ul.vmScreenshots li {
|
||||
font-family: monospace;
|
||||
list-style: square;
|
||||
}
|
178
nixos/lib/test-driver/test-driver.pl
Normal file
178
nixos/lib/test-driver/test-driver.pl
Normal file
@ -0,0 +1,178 @@
|
||||
#! /somewhere/perl -w
|
||||
|
||||
use strict;
|
||||
use Machine;
|
||||
use Term::ReadLine;
|
||||
use IO::File;
|
||||
use IO::Pty;
|
||||
use Logger;
|
||||
use Cwd;
|
||||
use POSIX qw(_exit dup2);
|
||||
|
||||
$SIG{PIPE} = 'IGNORE'; # because Unix domain sockets may die unexpectedly
|
||||
|
||||
STDERR->autoflush(1);
|
||||
|
||||
my $log = new Logger;
|
||||
|
||||
|
||||
# Start vde_switch for each network required by the test.
|
||||
my %vlans;
|
||||
foreach my $vlan (split / /, $ENV{VLANS} || "") {
|
||||
next if defined $vlans{$vlan};
|
||||
# Start vde_switch as a child process. We don't run it in daemon
|
||||
# mode because we want the child process to be cleaned up when we
|
||||
# die. Since we have to make sure that the control socket is
|
||||
# ready, we send a dummy command to vde_switch (via stdin) and
|
||||
# wait for a reply. Note that vde_switch requires stdin to be a
|
||||
# TTY, so we create one.
|
||||
$log->log("starting VDE switch for network $vlan");
|
||||
my $socket = Cwd::abs_path "./vde$vlan.ctl";
|
||||
my $pty = new IO::Pty;
|
||||
my ($stdoutR, $stdoutW); pipe $stdoutR, $stdoutW;
|
||||
my $pid = fork(); die "cannot fork" unless defined $pid;
|
||||
if ($pid == 0) {
|
||||
dup2(fileno($pty->slave), 0);
|
||||
dup2(fileno($stdoutW), 1);
|
||||
exec "vde_switch -s $socket" or _exit(1);
|
||||
}
|
||||
close $stdoutW;
|
||||
print $pty "version\n";
|
||||
readline $stdoutR or die "cannot start vde_switch";
|
||||
$ENV{"QEMU_VDE_SOCKET_$vlan"} = $socket;
|
||||
$vlans{$vlan} = $pty;
|
||||
die unless -e "$socket/ctl";
|
||||
}
|
||||
|
||||
|
||||
my %vms;
|
||||
my $context = "";
|
||||
|
||||
sub createMachine {
|
||||
my ($args) = @_;
|
||||
my $vm = Machine->new({%{$args}, log => $log, redirectSerial => ($ENV{USE_SERIAL} // "0") ne "1"});
|
||||
$vms{$vm->name} = $vm;
|
||||
return $vm;
|
||||
}
|
||||
|
||||
foreach my $vmScript (@ARGV) {
|
||||
my $vm = createMachine({startCommand => $vmScript});
|
||||
$context .= "my \$" . $vm->name . " = \$vms{'" . $vm->name . "'}; ";
|
||||
}
|
||||
|
||||
|
||||
sub startAll {
|
||||
$log->nest("starting all VMs", sub {
|
||||
$_->start foreach values %vms;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
# Wait until all VMs have terminated.
|
||||
sub joinAll {
|
||||
$log->nest("waiting for all VMs to finish", sub {
|
||||
$_->waitForShutdown foreach values %vms;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
# In interactive tests, this allows the non-interactive test script to
|
||||
# be executed conveniently.
|
||||
sub testScript {
|
||||
eval "$context $ENV{testScript};\n";
|
||||
warn $@ if $@;
|
||||
}
|
||||
|
||||
|
||||
my $nrTests = 0;
|
||||
my $nrSucceeded = 0;
|
||||
|
||||
|
||||
sub subtest {
|
||||
my ($name, $coderef) = @_;
|
||||
$log->nest("subtest: $name", sub {
|
||||
$nrTests++;
|
||||
eval { &$coderef };
|
||||
if ($@) {
|
||||
$log->log("error: $@", { error => 1 });
|
||||
} else {
|
||||
$nrSucceeded++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
sub runTests {
|
||||
if (defined $ENV{tests}) {
|
||||
$log->nest("running the VM test script", sub {
|
||||
eval "$context $ENV{tests}";
|
||||
if ($@) {
|
||||
$log->log("error: $@", { error => 1 });
|
||||
die $@;
|
||||
}
|
||||
}, { expanded => 1 });
|
||||
} else {
|
||||
my $term = Term::ReadLine->new('nixos-vm-test');
|
||||
$term->ReadHistory;
|
||||
while (defined ($_ = $term->readline("> "))) {
|
||||
eval "$context $_\n";
|
||||
warn $@ if $@;
|
||||
}
|
||||
$term->WriteHistory;
|
||||
}
|
||||
|
||||
# Copy the kernel coverage data for each machine, if the kernel
|
||||
# has been compiled with coverage instrumentation.
|
||||
$log->nest("collecting coverage data", sub {
|
||||
foreach my $vm (values %vms) {
|
||||
my $gcovDir = "/sys/kernel/debug/gcov";
|
||||
|
||||
next unless $vm->isUp();
|
||||
|
||||
my ($status, $out) = $vm->execute("test -e $gcovDir");
|
||||
next if $status != 0;
|
||||
|
||||
# Figure out where to put the *.gcda files so that the
|
||||
# report generator can find the corresponding kernel
|
||||
# sources.
|
||||
my $kernelDir = $vm->mustSucceed("echo \$(dirname \$(readlink -f /run/current-system/kernel))/.build/linux-*");
|
||||
chomp $kernelDir;
|
||||
my $coverageDir = "/tmp/xchg/coverage-data/$kernelDir";
|
||||
|
||||
# Copy all the *.gcda files.
|
||||
$vm->execute("for d in $gcovDir/nix/store/*/.build/linux-*; do for i in \$(cd \$d && find -name '*.gcda'); do echo \$i; mkdir -p $coverageDir/\$(dirname \$i); cp -v \$d/\$i $coverageDir/\$i; done; done");
|
||||
}
|
||||
});
|
||||
|
||||
if ($nrTests != 0) {
|
||||
$log->log("$nrSucceeded out of $nrTests tests succeeded",
|
||||
($nrSucceeded < $nrTests ? { error => 1 } : { }));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Create an empty raw virtual disk with the given name and size (in
|
||||
# MiB).
|
||||
sub createDisk {
|
||||
my ($name, $size) = @_;
|
||||
system("qemu-img create -f raw $name ${size}M") == 0
|
||||
or die "cannot create image of size $size";
|
||||
}
|
||||
|
||||
|
||||
END {
|
||||
$log->nest("cleaning up", sub {
|
||||
foreach my $vm (values %vms) {
|
||||
if ($vm->{pid}) {
|
||||
$log->log("killing " . $vm->{name} . " (pid " . $vm->{pid} . ")");
|
||||
kill 9, $vm->{pid};
|
||||
}
|
||||
}
|
||||
});
|
||||
$log->close();
|
||||
}
|
||||
|
||||
|
||||
runTests;
|
||||
|
||||
exit ($nrSucceeded < $nrTests ? 1 : 0);
|
30
nixos/lib/test-driver/treebits.js
Normal file
30
nixos/lib/test-driver/treebits.js
Normal file
@ -0,0 +1,30 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
/* When a toggle is clicked, show or hide the subtree. */
|
||||
$(".logTreeToggle").click(function() {
|
||||
if ($(this).siblings("ul:hidden").length != 0) {
|
||||
$(this).siblings("ul").show();
|
||||
$(this).text("-");
|
||||
} else {
|
||||
$(this).siblings("ul").hide();
|
||||
$(this).text("+");
|
||||
}
|
||||
});
|
||||
|
||||
/* Implementation of the expand all link. */
|
||||
$(".logTreeExpandAll").click(function() {
|
||||
$(".logTreeToggle", $(this).parent().siblings(".toplevel")).map(function() {
|
||||
$(this).siblings("ul").show();
|
||||
$(this).text("-");
|
||||
});
|
||||
});
|
||||
|
||||
/* Implementation of the collapse all link. */
|
||||
$(".logTreeCollapseAll").click(function() {
|
||||
$(".logTreeToggle", $(this).parent().siblings(".toplevel")).map(function() {
|
||||
$(this).siblings("ul").hide();
|
||||
$(this).text("+");
|
||||
});
|
||||
});
|
||||
|
||||
});
|
244
nixos/lib/testing.nix
Normal file
244
nixos/lib/testing.nix
Normal file
@ -0,0 +1,244 @@
|
||||
{ system, minimal ? false }:
|
||||
|
||||
with import ./build-vms.nix { inherit system minimal; };
|
||||
with pkgs;
|
||||
|
||||
rec {
|
||||
|
||||
inherit pkgs;
|
||||
|
||||
|
||||
testDriver = stdenv.mkDerivation {
|
||||
name = "nixos-test-driver";
|
||||
|
||||
buildInputs = [ makeWrapper perl ];
|
||||
|
||||
unpackPhase = "true";
|
||||
|
||||
installPhase =
|
||||
''
|
||||
mkdir -p $out/bin
|
||||
cp ${./test-driver/test-driver.pl} $out/bin/nixos-test-driver
|
||||
chmod u+x $out/bin/nixos-test-driver
|
||||
|
||||
libDir=$out/lib/perl5/site_perl
|
||||
mkdir -p $libDir
|
||||
cp ${./test-driver/Machine.pm} $libDir/Machine.pm
|
||||
cp ${./test-driver/Logger.pm} $libDir/Logger.pm
|
||||
|
||||
wrapProgram $out/bin/nixos-test-driver \
|
||||
--prefix PATH : "${pkgs.qemu_kvm}/bin:${pkgs.vde2}/bin:${imagemagick}/bin:${coreutils}/bin" \
|
||||
--prefix PERL5LIB : "${lib.makePerlPath [ perlPackages.TermReadLineGnu perlPackages.XMLWriter perlPackages.IOTty ]}:$out/lib/perl5/site_perl"
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
# Run an automated test suite in the given virtual network.
|
||||
# `driver' is the script that runs the network.
|
||||
runTests = driver:
|
||||
stdenv.mkDerivation {
|
||||
name = "vm-test-run";
|
||||
|
||||
requiredSystemFeatures = [ "kvm" "nixos-test" ];
|
||||
|
||||
buildInputs = [ pkgs.libxslt ];
|
||||
|
||||
buildCommand =
|
||||
''
|
||||
mkdir -p $out/nix-support
|
||||
|
||||
LOGFILE=$out/log.xml tests='eval $ENV{testScript}; die $@ if $@;' ${driver}/bin/nixos-test-driver || failed=1
|
||||
|
||||
# Generate a pretty-printed log.
|
||||
xsltproc --output $out/log.html ${./test-driver/log2html.xsl} $out/log.xml
|
||||
ln -s ${./test-driver/logfile.css} $out/logfile.css
|
||||
ln -s ${./test-driver/treebits.js} $out/treebits.js
|
||||
|
||||
touch $out/nix-support/hydra-build-products
|
||||
echo "report testlog $out log.html" >> $out/nix-support/hydra-build-products
|
||||
|
||||
for i in */xchg/coverage-data; do
|
||||
mkdir -p $out/coverage-data
|
||||
mv $i $out/coverage-data/$(dirname $(dirname $i))
|
||||
done
|
||||
|
||||
[ -z "$failed" ] || touch $out/nix-support/failed
|
||||
''; # */
|
||||
};
|
||||
|
||||
|
||||
# Generate a coverage report from the coverage data produced by
|
||||
# runTests.
|
||||
makeReport = x: runCommand "report" { buildInputs = [rsync]; }
|
||||
''
|
||||
mkdir -p $TMPDIR/gcov/
|
||||
|
||||
for d in ${x}/coverage-data/*; do
|
||||
echo "doing $d"
|
||||
[ -n "$(ls -A "$d")" ] || continue
|
||||
|
||||
for i in $(cd $d/nix/store && ls); do
|
||||
if ! test -e $TMPDIR/gcov/nix/store/$i; then
|
||||
echo "copying $i"
|
||||
mkdir -p $TMPDIR/gcov/$(echo $i | cut -c34-)
|
||||
rsync -rv /nix/store/$i/.build/* $TMPDIR/gcov/
|
||||
fi
|
||||
done
|
||||
|
||||
chmod -R u+w $TMPDIR/gcov
|
||||
|
||||
find $TMPDIR/gcov -name "*.gcda" -exec rm {} \;
|
||||
|
||||
for i in $(cd $d/nix/store && ls); do
|
||||
rsync -rv $d/nix/store/$i/.build/* $TMPDIR/gcov/
|
||||
done
|
||||
|
||||
find $TMPDIR/gcov -name "*.gcda" -exec chmod 644 {} \;
|
||||
|
||||
echo "producing info..."
|
||||
${pkgs.lcov}/bin/geninfo --ignore-errors source,gcov $TMPDIR/gcov --output-file $TMPDIR/app.info
|
||||
cat $TMPDIR/app.info >> $TMPDIR/full.info
|
||||
done
|
||||
|
||||
echo "making report..."
|
||||
mkdir -p $out/coverage
|
||||
${pkgs.lcov}/bin/genhtml --show-details $TMPDIR/full.info -o $out/coverage
|
||||
cp $TMPDIR/full.info $out/coverage/
|
||||
|
||||
mkdir -p $out/nix-support
|
||||
cat ${x}/nix-support/hydra-build-products >> $out/nix-support/hydra-build-products
|
||||
echo "report coverage $out/coverage" >> $out/nix-support/hydra-build-products
|
||||
[ ! -e ${x}/nix-support/failed ] || touch $out/nix-support/failed
|
||||
''; # */
|
||||
|
||||
|
||||
makeTest = testFun: complete (call testFun);
|
||||
makeTests = testsFun: lib.mapAttrs (name: complete) (call testsFun);
|
||||
|
||||
apply = makeTest; # compatibility
|
||||
call = f: f { inherit pkgs system; };
|
||||
|
||||
complete = t: t // rec {
|
||||
nodes = buildVirtualNetwork (
|
||||
if t ? nodes then t.nodes else
|
||||
if t ? machine then { machine = t.machine; }
|
||||
else { } );
|
||||
|
||||
testScript =
|
||||
# Call the test script with the computed nodes.
|
||||
if builtins.isFunction t.testScript
|
||||
then t.testScript { inherit nodes; }
|
||||
else t.testScript;
|
||||
|
||||
vlans = map (m: m.config.virtualisation.vlans) (lib.attrValues nodes);
|
||||
|
||||
vms = map (m: m.config.system.build.vm) (lib.attrValues nodes);
|
||||
|
||||
# Generate onvenience wrappers for running the test driver
|
||||
# interactively with the specified network, and for starting the
|
||||
# VMs from the command line.
|
||||
driver = runCommand "nixos-test-driver"
|
||||
{ buildInputs = [ makeWrapper];
|
||||
inherit testScript;
|
||||
preferLocalBuild = true;
|
||||
}
|
||||
''
|
||||
mkdir -p $out/bin
|
||||
echo "$testScript" > $out/test-script
|
||||
ln -s ${testDriver}/bin/nixos-test-driver $out/bin/
|
||||
vms="$(for i in ${toString vms}; do echo $i/bin/run-*-vm; done)"
|
||||
wrapProgram $out/bin/nixos-test-driver \
|
||||
--add-flags "$vms" \
|
||||
--run "testScript=\"\$(cat $out/test-script)\"" \
|
||||
--set testScript '"$testScript"' \
|
||||
--set VLANS '"${toString vlans}"'
|
||||
ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-run-vms
|
||||
wrapProgram $out/bin/nixos-run-vms \
|
||||
--add-flags "$vms" \
|
||||
--set tests '"startAll; joinAll;"' \
|
||||
--set VLANS '"${toString vlans}"' \
|
||||
${lib.optionalString (builtins.length vms == 1) "--set USE_SERIAL 1"}
|
||||
''; # "
|
||||
|
||||
test = runTests driver;
|
||||
|
||||
report = makeReport test;
|
||||
};
|
||||
|
||||
|
||||
runInMachine =
|
||||
{ drv
|
||||
, machine
|
||||
, preBuild ? ""
|
||||
, postBuild ? ""
|
||||
, ... # ???
|
||||
}:
|
||||
let
|
||||
vm = buildVM { }
|
||||
[ machine
|
||||
{ key = "hostname"; networking.hostName = "client"; }
|
||||
];
|
||||
|
||||
buildrunner = writeText "vm-build" ''
|
||||
source $1
|
||||
|
||||
${coreutils}/bin/mkdir -p $TMPDIR
|
||||
cd $TMPDIR
|
||||
|
||||
$origBuilder $origArgs
|
||||
|
||||
exit $?
|
||||
'';
|
||||
|
||||
testscript = ''
|
||||
startAll;
|
||||
${preBuild}
|
||||
$client->succeed("env -i ${pkgs.bash}/bin/bash ${buildrunner} /tmp/xchg/saved-env >&2");
|
||||
${postBuild}
|
||||
'';
|
||||
|
||||
vmRunCommand = writeText "vm-run" ''
|
||||
${coreutils}/bin/mkdir $out
|
||||
${coreutils}/bin/mkdir -p vm-state-client/xchg
|
||||
export > vm-state-client/xchg/saved-env
|
||||
export tests='${testscript}'
|
||||
${testDriver}/bin/nixos-test-driver ${vm.config.system.build.vm}/bin/run-*-vm
|
||||
''; # */
|
||||
|
||||
in
|
||||
lib.overrideDerivation drv (attrs: {
|
||||
requiredSystemFeatures = [ "kvm" ];
|
||||
builder = "${bash}/bin/sh";
|
||||
args = ["-e" vmRunCommand];
|
||||
origArgs = attrs.args;
|
||||
origBuilder = attrs.builder;
|
||||
});
|
||||
|
||||
|
||||
runInMachineWithX = { require ? [], ... } @ args:
|
||||
let
|
||||
client =
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
inherit require;
|
||||
virtualisation.memorySize = 1024;
|
||||
services.xserver.enable = true;
|
||||
services.xserver.displayManager.slim.enable = false;
|
||||
services.xserver.displayManager.auto.enable = true;
|
||||
services.xserver.windowManager.default = "icewm";
|
||||
services.xserver.windowManager.icewm.enable = true;
|
||||
services.xserver.desktopManager.default = "none";
|
||||
};
|
||||
in
|
||||
runInMachine ({
|
||||
machine = client;
|
||||
preBuild =
|
||||
''
|
||||
$client->waitForX;
|
||||
'';
|
||||
} // args);
|
||||
|
||||
|
||||
simpleTest = as: (makeTest ({ ... }: as)).test;
|
||||
|
||||
}
|
10
nixos/lib/utils.nix
Normal file
10
nixos/lib/utils.nix
Normal file
@ -0,0 +1,10 @@
|
||||
pkgs: with pkgs.lib;
|
||||
|
||||
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);
|
||||
|
||||
}
|
99
nixos/maintainers/option-usages.nix
Normal file
99
nixos/maintainers/option-usages.nix
Normal file
@ -0,0 +1,99 @@
|
||||
{ configuration ? import ../lib/from-env.nix "NIXOS_CONFIG" <nixos-config>
|
||||
|
||||
# []: display all options
|
||||
# [<option names>]: display the selected options
|
||||
, displayOptions ? [
|
||||
"hardware.pcmcia.enable"
|
||||
"environment.systemPackages"
|
||||
"boot.kernelModules"
|
||||
"services.udev.packages"
|
||||
"jobs"
|
||||
"environment.etc"
|
||||
"system.activationScripts"
|
||||
]
|
||||
}:
|
||||
|
||||
# This file is used to generate a dot graph which contains all options and
|
||||
# there dependencies to track problems and their sources.
|
||||
|
||||
let
|
||||
|
||||
evalFun = {
|
||||
extraArgs ? {}
|
||||
}: import ../lib/eval-config.nix {
|
||||
modules = [ configuration ];
|
||||
inherit extraArgs;
|
||||
};
|
||||
|
||||
eval = evalFun {};
|
||||
inherit (eval) pkgs;
|
||||
|
||||
reportNewFailures = old: new: with pkgs.lib;
|
||||
let
|
||||
filterChanges =
|
||||
filter ({fst, snd}:
|
||||
!(fst.config.success -> snd.config.success)
|
||||
);
|
||||
|
||||
keepNames =
|
||||
map ({fst, snd}:
|
||||
assert fst.name == snd.name; snd.name
|
||||
);
|
||||
in
|
||||
keepNames (
|
||||
filterChanges (
|
||||
zipLists (collect isOption old) (collect isOption new)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
# Create a list of modules where each module contains only one failling
|
||||
# options.
|
||||
introspectionModules = with pkgs.lib;
|
||||
let
|
||||
setIntrospection = opt: rec {
|
||||
name = opt.name;
|
||||
path = splitString "." opt.name;
|
||||
config = setAttrByPath path
|
||||
(throw "Usage introspection of '${name}' by forced failure.");
|
||||
};
|
||||
in
|
||||
map setIntrospection (collect isOption eval.options);
|
||||
|
||||
overrideConfig = thrower:
|
||||
pkgs.lib.recursiveUpdateUntil (path: old: new:
|
||||
path == thrower.path
|
||||
) eval.config thrower.config;
|
||||
|
||||
|
||||
graph = with pkgs.lib;
|
||||
map (thrower: {
|
||||
option = thrower.name;
|
||||
usedBy = reportNewFailures eval.options (evalFun {
|
||||
extraArgs = {
|
||||
config = overrideConfig thrower;
|
||||
};
|
||||
}).options;
|
||||
}) introspectionModules;
|
||||
|
||||
graphToDot = graph: with pkgs.lib; ''
|
||||
digraph "Option Usages" {
|
||||
${concatMapStrings ({option, usedBy}:
|
||||
assert __trace option true;
|
||||
if displayOptions == [] || elem option displayOptions then
|
||||
concatMapStrings (user: ''
|
||||
"${option}" -> "${user}"''
|
||||
) usedBy
|
||||
else ""
|
||||
) graph}
|
||||
}
|
||||
'';
|
||||
|
||||
in
|
||||
|
||||
pkgs.texFunctions.dot2pdf {
|
||||
dotGraph = pkgs.writeTextFile {
|
||||
name = "option_usages.dot";
|
||||
text = graphToDot graph;
|
||||
};
|
||||
}
|
220
nixos/maintainers/scripts/ec2/create-ebs-amis.py
Executable file
220
nixos/maintainers/scripts/ec2/create-ebs-amis.py
Executable file
@ -0,0 +1,220 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import argparse
|
||||
import nixops.util
|
||||
from nixops import deployment
|
||||
from boto.ec2.blockdevicemapping import BlockDeviceMapping, BlockDeviceType
|
||||
import boto.ec2
|
||||
|
||||
parser = argparse.ArgumentParser(description='Create an EBS-backed NixOS AMI')
|
||||
parser.add_argument('--region', dest='region', required=True, help='EC2 region to create the image in')
|
||||
parser.add_argument('--keep', dest='keep', action='store_true', help='Keep NixOps machine after use')
|
||||
parser.add_argument('--hvm', dest='hvm', action='store_true', help='Create HVM image')
|
||||
parser.add_argument('--key', dest='key_name', action='store_true', help='Keypair used for HVM instance creation', default="rob")
|
||||
args = parser.parse_args()
|
||||
|
||||
instance_type = "cc1.4xlarge" if args.hvm else "m1.small"
|
||||
ebs_size = 8 if args.hvm else 20
|
||||
|
||||
|
||||
# Start a NixOS machine in the given region.
|
||||
f = open("ebs-creator-config.nix", "w")
|
||||
f.write('''{{
|
||||
resources.ec2KeyPairs.keypair.accessKeyId = "logicblox-dev";
|
||||
resources.ec2KeyPairs.keypair.region = "{0}";
|
||||
|
||||
machine =
|
||||
{{ pkgs, ... }}:
|
||||
{{
|
||||
deployment.ec2.accessKeyId = "logicblox-dev";
|
||||
deployment.ec2.region = "{0}";
|
||||
deployment.ec2.blockDeviceMapping."/dev/xvdg".size = pkgs.lib.mkOverride 10 {1};
|
||||
}};
|
||||
}}
|
||||
'''.format(args.region, ebs_size))
|
||||
f.close()
|
||||
|
||||
db = deployment.open_database(deployment.get_default_state_file())
|
||||
try:
|
||||
depl = deployment.open_deployment(db, "ebs-creator")
|
||||
except Exception:
|
||||
depl = deployment.create_deployment(db)
|
||||
depl.name = "ebs-creator"
|
||||
depl.auto_response = "y"
|
||||
depl.nix_exprs = [os.path.abspath("./ebs-creator.nix"), os.path.abspath("./ebs-creator-config.nix")]
|
||||
if not args.keep: depl.destroy_resources()
|
||||
depl.deploy(allow_reboot=True)
|
||||
|
||||
m = depl.machines['machine']
|
||||
|
||||
|
||||
# Do the installation.
|
||||
device="/dev/xvdg"
|
||||
if args.hvm:
|
||||
m.run_command('parted -s /dev/xvdg -- mklabel msdos')
|
||||
m.run_command('parted -s /dev/xvdg -- mkpart primary ext2 1M -1s')
|
||||
device="/dev/xvdg1"
|
||||
|
||||
m.run_command("if mountpoint -q /mnt; then umount /mnt; fi")
|
||||
m.run_command("mkfs.ext4 -L nixos {0}".format(device))
|
||||
m.run_command("mkdir -p /mnt")
|
||||
m.run_command("mount {0} /mnt".format(device))
|
||||
m.run_command("touch /mnt/.ebs")
|
||||
m.run_command("mkdir -p /mnt/etc/nixos")
|
||||
m.run_command("nix-channel --add http://nixos.org/channels/nixos-unstable")
|
||||
m.run_command("nix-channel --update")
|
||||
m.run_command("nixos-rebuild switch")
|
||||
version = m.run_command("nixos-version", capture_stdout=True).replace('"', '').rstrip()
|
||||
print >> sys.stderr, "NixOS version is {0}".format(version)
|
||||
m.upload_file("./amazon-base-config.nix", "/mnt/etc/nixos/configuration.nix")
|
||||
m.run_command("nixos-install")
|
||||
if args.hvm:
|
||||
m.run_command('cp /mnt/nix/store/*-grub-0.97*/lib/grub/i386-pc/* /mnt/boot/grub')
|
||||
m.run_command('sed -i "s|hd0|hd0,0|" /mnt/boot/grub/menu.lst')
|
||||
m.run_command('echo "(hd1) /dev/xvdg" > device.map')
|
||||
m.run_command('echo -e "root (hd1,0)\nsetup (hd1)" | grub --device-map=device.map --batch')
|
||||
|
||||
|
||||
m.run_command("umount /mnt")
|
||||
|
||||
|
||||
if args.hvm:
|
||||
ami_name = "nixos-{0}-x86_64-ebs-hvm".format(version)
|
||||
description = "NixOS {0} (x86_64; EBS root; hvm)".format(version)
|
||||
else:
|
||||
ami_name = "nixos-{0}-x86_64-ebs".format(version)
|
||||
description = "NixOS {0} (x86_64; EBS root)".format(version)
|
||||
|
||||
|
||||
# Wait for the snapshot to finish.
|
||||
def check():
|
||||
status = snapshot.update()
|
||||
print >> sys.stderr, "snapshot status is {0}".format(status)
|
||||
return status == '100%'
|
||||
|
||||
m.connect()
|
||||
volume = m._conn.get_all_volumes([], filters={'attachment.instance-id': m.resource_id, 'attachment.device': "/dev/sdg"})[0]
|
||||
if args.hvm:
|
||||
instance = m._conn.run_instances( image_id="ami-6a9e4503"
|
||||
, instance_type=instance_type
|
||||
, key_name=args.key_name
|
||||
, placement=m.zone
|
||||
, security_groups=["eelco-test"]).instances[0]
|
||||
nixops.util.check_wait(lambda: instance.update() == 'running', max_tries=120)
|
||||
instance.stop()
|
||||
nixops.util.check_wait(lambda: instance.update() == 'stopped', max_tries=120)
|
||||
old_root_volume = m._conn.get_all_volumes([], filters={'attachment.instance-id': instance.id, 'attachment.device': "/dev/sda1"})[0]
|
||||
old_root_volume.detach()
|
||||
volume.detach()
|
||||
nixops.util.check_wait(lambda: volume.update() == 'available', max_tries=120)
|
||||
nixops.util.check_wait(lambda: old_root_volume.update() == 'available', max_tries=120)
|
||||
volume.attach(instance.id, '/dev/sda1')
|
||||
nixops.util.check_wait(lambda: volume.update() == 'in-use', max_tries=120)
|
||||
|
||||
ami_id = m._conn.create_image(instance.id, ami_name, description)
|
||||
time.sleep(5)
|
||||
image = m._conn.get_all_images([ami_id])[0]
|
||||
nixops.util.check_wait(lambda: image.update() == 'available', max_tries=120)
|
||||
instance.terminate()
|
||||
|
||||
else:
|
||||
# Create a snapshot.
|
||||
snapshot = volume.create_snapshot(description=description)
|
||||
print >> sys.stderr, "created snapshot {0}".format(snapshot.id)
|
||||
|
||||
nixops.util.check_wait(check, max_tries=120)
|
||||
|
||||
m._conn.create_tags([snapshot.id], {'Name': ami_name})
|
||||
|
||||
if not args.keep: depl.destroy_resources()
|
||||
|
||||
# Register the image.
|
||||
aki = m._conn.get_all_images(filters={'manifest-location': '*pv-grub-hd0_1.03-x86_64*'})[0]
|
||||
print >> sys.stderr, "using kernel image {0} - {1}".format(aki.id, aki.location)
|
||||
|
||||
block_map = BlockDeviceMapping()
|
||||
block_map['/dev/sda'] = BlockDeviceType(snapshot_id=snapshot.id, delete_on_termination=True)
|
||||
block_map['/dev/sdb'] = BlockDeviceType(ephemeral_name="ephemeral0")
|
||||
block_map['/dev/sdc'] = BlockDeviceType(ephemeral_name="ephemeral1")
|
||||
block_map['/dev/sdd'] = BlockDeviceType(ephemeral_name="ephemeral2")
|
||||
block_map['/dev/sde'] = BlockDeviceType(ephemeral_name="ephemeral3")
|
||||
|
||||
ami_id = m._conn.register_image(
|
||||
name=ami_name,
|
||||
description=description,
|
||||
architecture="x86_64",
|
||||
root_device_name="/dev/sda",
|
||||
kernel_id=aki.id,
|
||||
block_device_map=block_map)
|
||||
|
||||
print >> sys.stderr, "registered AMI {0}".format(ami_id)
|
||||
|
||||
print >> sys.stderr, "sleeping a bit..."
|
||||
time.sleep(30)
|
||||
|
||||
print >> sys.stderr, "setting image name..."
|
||||
m._conn.create_tags([ami_id], {'Name': ami_name})
|
||||
|
||||
print >> sys.stderr, "making image public..."
|
||||
image = m._conn.get_all_images(image_ids=[ami_id])[0]
|
||||
image.set_launch_permissions(user_ids=[], group_names=["all"])
|
||||
|
||||
# Do a test deployment to make sure that the AMI works.
|
||||
f = open("ebs-test.nix", "w")
|
||||
f.write(
|
||||
'''
|
||||
{{
|
||||
network.description = "NixOS EBS test";
|
||||
|
||||
resources.ec2KeyPairs.keypair.accessKeyId = "logicblox-dev";
|
||||
resources.ec2KeyPairs.keypair.region = "{0}";
|
||||
|
||||
machine = {{ config, pkgs, resources, ... }}: {{
|
||||
deployment.targetEnv = "ec2";
|
||||
deployment.ec2.accessKeyId = "logicblox-dev";
|
||||
deployment.ec2.region = "{0}";
|
||||
deployment.ec2.instanceType = "{2}";
|
||||
deployment.ec2.keyPair = resources.ec2KeyPairs.keypair.name;
|
||||
deployment.ec2.securityGroups = [ "admin" ];
|
||||
deployment.ec2.ami = "{1}";
|
||||
}};
|
||||
}}
|
||||
'''.format(args.region, ami_id, instance_type))
|
||||
f.close()
|
||||
|
||||
test_depl = deployment.create_deployment(db)
|
||||
test_depl.auto_response = "y"
|
||||
test_depl.name = "ebs-creator-test"
|
||||
test_depl.nix_exprs = [os.path.abspath("./ebs-test.nix")]
|
||||
test_depl.deploy(create_only=True)
|
||||
test_depl.machines['machine'].run_command("nixos-version")
|
||||
|
||||
if args.hvm:
|
||||
image_type = 'hvm'
|
||||
else:
|
||||
image_type = 'ebs'
|
||||
|
||||
# Log the AMI ID.
|
||||
f = open("{0}.{1}.ami-id".format(args.region, image_type), "w")
|
||||
f.write("{0}".format(ami_id))
|
||||
f.close()
|
||||
|
||||
for dest in [ 'us-east-1', 'us-west-1', 'us-west-2', 'eu-west-1']:
|
||||
if args.region != dest:
|
||||
print >> sys.stderr, "copying image from region {0} to {1}".format(args.region, dest)
|
||||
conn = boto.ec2.connect_to_region(dest)
|
||||
copy_image = conn.copy_image(args.region, ami_id, ami_name, description=None, client_token=None)
|
||||
|
||||
# Log the AMI ID.
|
||||
f = open("{0}.{1}.ami-id".format(dest, image_type), "w")
|
||||
f.write("{0}".format(copy_image.image_id))
|
||||
f.close()
|
||||
|
||||
|
||||
if not args.keep:
|
||||
test_depl.destroy_resources()
|
||||
test_depl.delete()
|
||||
|
49
nixos/maintainers/scripts/ec2/create-s3-amis.sh
Executable file
49
nixos/maintainers/scripts/ec2/create-s3-amis.sh
Executable file
@ -0,0 +1,49 @@
|
||||
#! /bin/sh -e
|
||||
|
||||
nixos=$(nix-instantiate --find-file nixos)
|
||||
export NIXOS_CONFIG=$(dirname $(readlink -f $0))/amazon-base-config.nix
|
||||
|
||||
version=$(nix-instantiate --eval-only '<nixos>' -A config.system.nixosVersion | sed s/'"'//g)
|
||||
echo "NixOS version is $version"
|
||||
|
||||
buildAndUploadFor() {
|
||||
system="$1"
|
||||
arch="$2"
|
||||
|
||||
echo "building $system image..."
|
||||
nix-build '<nixos>' \
|
||||
-A config.system.build.amazonImage --argstr system "$system" -o ec2-ami
|
||||
|
||||
ec2-bundle-image -i ./ec2-ami/nixos.img --user "$AWS_ACCOUNT" --arch "$arch" \
|
||||
-c "$EC2_CERT" -k "$EC2_PRIVATE_KEY"
|
||||
|
||||
for region in eu-west-1 us-east-1 us-west-1 us-west-2; do
|
||||
echo "uploading $system image for $region..."
|
||||
|
||||
name=nixos-$version-$arch-s3
|
||||
bucket="$(echo $name-$region | tr '[A-Z]_' '[a-z]-')"
|
||||
|
||||
if [ "$region" = eu-west-1 ]; then s3location=EU;
|
||||
elif [ "$region" = us-east-1 ]; then s3location=US;
|
||||
else s3location="$region"
|
||||
fi
|
||||
|
||||
ec2-upload-bundle -b "$bucket" -m /tmp/nixos.img.manifest.xml \
|
||||
-a "$EC2_ACCESS_KEY" -s "$EC2_SECRET_KEY" --location "$s3location" \
|
||||
--url http://s3.amazonaws.com
|
||||
|
||||
kernel=$(ec2-describe-images -o amazon --filter "manifest-location=*pv-grub-hd0_1.03-$arch*" --region "$region" | cut -f 2)
|
||||
echo "using PV-GRUB kernel $kernel"
|
||||
|
||||
ami=$(ec2-register "$bucket/nixos.img.manifest.xml" -n "$name" -d "NixOS $system r$revision" \
|
||||
--region "$region" --kernel "$kernel" | cut -f 2)
|
||||
|
||||
echo "AMI ID is $ami"
|
||||
|
||||
echo $ami >> $region.s3.ami-id
|
||||
|
||||
ec2-modify-image-attribute --region "$region" "$ami" -l -a all
|
||||
done
|
||||
}
|
||||
|
||||
buildAndUploadFor x86_64-linux x86_64
|
13
nixos/maintainers/scripts/ec2/ebs-creator.nix
Normal file
13
nixos/maintainers/scripts/ec2/ebs-creator.nix
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
network.description = "NixOS EBS creator";
|
||||
|
||||
machine =
|
||||
{ config, pkgs, resources, ... }:
|
||||
{ deployment.targetEnv = "ec2";
|
||||
deployment.ec2.instanceType = "m1.large";
|
||||
deployment.ec2.securityGroups = [ "admin" ];
|
||||
deployment.ec2.ebsBoot = false;
|
||||
deployment.ec2.keyPair = resources.ec2KeyPairs.keypair.name;
|
||||
environment.systemPackages = [ pkgs.parted ];
|
||||
};
|
||||
}
|
32
nixos/modules/config/fonts/corefonts.nix
Normal file
32
nixos/modules/config/fonts/corefonts.nix
Normal file
@ -0,0 +1,32 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
{
|
||||
|
||||
options = {
|
||||
|
||||
fonts = {
|
||||
|
||||
enableCoreFonts = mkOption {
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to include Microsoft's proprietary Core Fonts. These fonts
|
||||
are redistributable, but only verbatim, among other restrictions.
|
||||
See <link xlink:href="http://corefonts.sourceforge.net/eula.htm"/>
|
||||
for details.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
config = mkIf config.fonts.enableCoreFonts {
|
||||
|
||||
fonts.extraFonts = [ pkgs.corefonts ];
|
||||
|
||||
};
|
||||
|
||||
}
|
58
nixos/modules/config/fonts/fontconfig.nix
Normal file
58
nixos/modules/config/fonts/fontconfig.nix
Normal file
@ -0,0 +1,58 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
{
|
||||
|
||||
options = {
|
||||
|
||||
fonts = {
|
||||
|
||||
enableFontConfig = mkOption { # !!! should be enableFontconfig
|
||||
default = true;
|
||||
description = ''
|
||||
If enabled, a Fontconfig configuration file will be built
|
||||
pointing to a set of default fonts. If you don't care about
|
||||
running X11 applications or any other program that uses
|
||||
Fontconfig, you can turn this option off and prevent a
|
||||
dependency on all those fonts.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
config = mkIf config.fonts.enableFontConfig {
|
||||
|
||||
# Bring in the default (upstream) fontconfig configuration.
|
||||
environment.etc."fonts/fonts.conf".source =
|
||||
pkgs.makeFontsConf { fontDirectories = config.fonts.fonts; };
|
||||
|
||||
environment.etc."fonts/conf.d/00-nixos.conf".text =
|
||||
''
|
||||
<?xml version='1.0'?>
|
||||
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
|
||||
<fontconfig>
|
||||
|
||||
<!-- Set the default hinting style to "slight". -->
|
||||
<match target="font">
|
||||
<edit mode="assign" name="hintstyle">
|
||||
<const>hintslight</const>
|
||||
</edit>
|
||||
</match>
|
||||
|
||||
</fontconfig>
|
||||
'';
|
||||
|
||||
# FIXME: This variable is no longer needed, but we'll keep it
|
||||
# around for a while for applications linked against old
|
||||
# fontconfig builds.
|
||||
environment.variables.FONTCONFIG_FILE = "/etc/fonts/fonts.conf";
|
||||
|
||||
environment.systemPackages = [ pkgs.fontconfig ];
|
||||
|
||||
};
|
||||
|
||||
}
|
75
nixos/modules/config/fonts/fontdir.nix
Normal file
75
nixos/modules/config/fonts/fontdir.nix
Normal file
@ -0,0 +1,75 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
fontDirs = config.fonts.fonts;
|
||||
|
||||
localDefs = with pkgs.builderDefs; pkgs.builderDefs.passthru.function rec {
|
||||
src = "";/* put a fetchurl here */
|
||||
buildInputs = [pkgs.xorg.mkfontdir pkgs.xorg.mkfontscale];
|
||||
inherit fontDirs;
|
||||
installPhase = fullDepEntry ("
|
||||
list='';
|
||||
for i in ${toString fontDirs} ; do
|
||||
if [ -d \$i/ ]; then
|
||||
list=\"\$list \$i\";
|
||||
fi;
|
||||
done
|
||||
list=\$(find \$list -name fonts.dir -o -name '*.ttf' -o -name '*.otf');
|
||||
fontDirs='';
|
||||
for i in \$list ; do
|
||||
fontDirs=\"\$fontDirs \$(dirname \$i)\";
|
||||
done;
|
||||
mkdir -p \$out/share/X11-fonts/;
|
||||
find \$fontDirs -type f -o -type l | while read i; do
|
||||
j=\"\${i##*/}\"
|
||||
if ! test -e \"\$out/share/X11-fonts/\${j}\"; then
|
||||
ln -s \"\$i\" \"\$out/share/X11-fonts/\${j}\";
|
||||
fi;
|
||||
done;
|
||||
cd \$out/share/X11-fonts/
|
||||
rm fonts.dir
|
||||
rm fonts.scale
|
||||
rm fonts.alias
|
||||
mkfontdir
|
||||
mkfontscale
|
||||
cat \$( find ${pkgs.xorg.fontalias}/ -name fonts.alias) >fonts.alias
|
||||
") ["minInit" "addInputs"];
|
||||
};
|
||||
|
||||
x11Fonts = with localDefs; stdenv.mkDerivation rec {
|
||||
name = "X11-fonts";
|
||||
builder = writeScript (name + "-builder")
|
||||
(textClosure localDefs
|
||||
[installPhase doForceShare doPropagate]);
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
options = {
|
||||
|
||||
fonts = {
|
||||
|
||||
enableFontDir = mkOption {
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to create a directory with links to all fonts in
|
||||
<filename>/run/current-system/sw/share/X11-fonts</filename>.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = mkIf config.fonts.enableFontDir {
|
||||
|
||||
environment.systemPackages = [ x11Fonts ];
|
||||
|
||||
};
|
||||
|
||||
}
|
49
nixos/modules/config/fonts/fonts.nix
Normal file
49
nixos/modules/config/fonts/fonts.nix
Normal file
@ -0,0 +1,49 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
{
|
||||
|
||||
options = {
|
||||
|
||||
fonts = {
|
||||
|
||||
# TODO: find another name for it.
|
||||
fonts = mkOption {
|
||||
default = [
|
||||
# - the user's .fonts directory
|
||||
"~/.fonts"
|
||||
# - the user's current profile
|
||||
"~/.nix-profile/lib/X11/fonts"
|
||||
"~/.nix-profile/share/fonts"
|
||||
# - the default profile
|
||||
"/nix/var/nix/profiles/default/lib/X11/fonts"
|
||||
"/nix/var/nix/profiles/default/share/fonts"
|
||||
];
|
||||
description = "List of primary font paths.";
|
||||
apply = list: list ++ [
|
||||
# - a few statically built locations
|
||||
pkgs.xorg.fontbhttf
|
||||
pkgs.xorg.fontbhlucidatypewriter100dpi
|
||||
pkgs.xorg.fontbhlucidatypewriter75dpi
|
||||
pkgs.ttf_bitstream_vera
|
||||
pkgs.freefont_ttf
|
||||
pkgs.liberation_ttf
|
||||
pkgs.xorg.fontbh100dpi
|
||||
pkgs.xorg.fontmiscmisc
|
||||
pkgs.xorg.fontcursormisc
|
||||
]
|
||||
++ config.fonts.extraFonts;
|
||||
};
|
||||
|
||||
extraFonts = mkOption {
|
||||
default = [];
|
||||
example = [ pkgs.dejavu_fonts ];
|
||||
description = "List of packages with additional fonts.";
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
32
nixos/modules/config/fonts/ghostscript.nix
Normal file
32
nixos/modules/config/fonts/ghostscript.nix
Normal file
@ -0,0 +1,32 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
{
|
||||
|
||||
options = {
|
||||
|
||||
fonts = {
|
||||
|
||||
enableGhostscriptFonts = mkOption {
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to add the fonts provided by Ghostscript (such as
|
||||
various URW fonts and the “Base-14” Postscript fonts) to the
|
||||
list of system fonts, making them available to X11
|
||||
applications.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
config = mkIf config.fonts.enableGhostscriptFonts {
|
||||
|
||||
fonts.extraFonts = [ "${pkgs.ghostscript}/share/ghostscript/fonts" ];
|
||||
|
||||
};
|
||||
|
||||
}
|
45
nixos/modules/config/gnu.nix
Normal file
45
nixos/modules/config/gnu.nix
Normal file
@ -0,0 +1,45 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
{
|
||||
options = {
|
||||
gnu = mkOption {
|
||||
default = false;
|
||||
description =
|
||||
'' When enabled, GNU software is chosen by default whenever a there is
|
||||
a choice between GNU and non-GNU software (e.g., GNU lsh
|
||||
vs. OpenSSH).
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf config.gnu {
|
||||
|
||||
environment.systemPackages = with pkgs;
|
||||
# TODO: Adjust `requiredPackages' from `system-path.nix'.
|
||||
# TODO: Add Inetutils once it has the new `ifconfig'.
|
||||
[ parted
|
||||
#fdisk # XXX: GNU fdisk currently fails to build and it's redundant
|
||||
# with the `parted' command.
|
||||
nano zile
|
||||
texinfo # for the stand-alone Info reader
|
||||
]
|
||||
++ stdenv.lib.optional (!stdenv.isArm) grub2;
|
||||
|
||||
|
||||
# GNU GRUB, where available.
|
||||
boot.loader.grub.enable = !pkgs.stdenv.isArm;
|
||||
boot.loader.grub.version = 2;
|
||||
|
||||
# GNU lsh.
|
||||
services.openssh.enable = false;
|
||||
services.lshd.enable = true;
|
||||
services.xserver.startOpenSSHAgent = false;
|
||||
services.xserver.startGnuPGAgent = true;
|
||||
|
||||
# TODO: GNU dico.
|
||||
# TODO: GNU Inetutils' inetd.
|
||||
# TODO: GNU Pies.
|
||||
};
|
||||
}
|
84
nixos/modules/config/i18n.nix
Normal file
84
nixos/modules/config/i18n.nix
Normal file
@ -0,0 +1,84 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
glibcLocales = pkgs.glibcLocales.override {
|
||||
allLocales = any (x: x == "all") config.i18n.supportedLocales;
|
||||
locales = config.i18n.supportedLocales;
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
i18n = {
|
||||
defaultLocale = mkOption {
|
||||
default = "en_US.UTF-8";
|
||||
example = "nl_NL.UTF-8";
|
||||
description = "
|
||||
The default locale. It determines the language for program
|
||||
messages, the format for dates and times, sort order, and so on.
|
||||
It also determines the character set, such as UTF-8.
|
||||
";
|
||||
};
|
||||
|
||||
supportedLocales = mkOption {
|
||||
default = ["all"];
|
||||
example = ["en_US.UTF-8/UTF-8" "nl_NL.UTF-8/UTF-8" "nl_NL/ISO-8859-1"];
|
||||
description = ''
|
||||
List of locales that the system should support. The value
|
||||
<literal>"all"</literal> means that all locales supported by
|
||||
Glibc will be installed. A full list of supported locales
|
||||
can be found at <link
|
||||
xlink:href="http://sourceware.org/cgi-bin/cvsweb.cgi/libc/localedata/SUPPORTED?cvsroot=glibc"/>.
|
||||
'';
|
||||
};
|
||||
|
||||
consoleFont = mkOption {
|
||||
default = "lat9w-16";
|
||||
example = "LatArCyrHeb-16";
|
||||
description = "
|
||||
The font used for the virtual consoles. Leave empty to use
|
||||
whatever the <command>setfont</command> program considers the
|
||||
default font.
|
||||
";
|
||||
};
|
||||
|
||||
consoleKeyMap = mkOption {
|
||||
default = "us";
|
||||
example = "fr";
|
||||
description = "
|
||||
The keyboard mapping table for the virtual consoles.
|
||||
";
|
||||
type = types.uniq types.string;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = {
|
||||
|
||||
environment.systemPackages = [ glibcLocales ];
|
||||
|
||||
environment.variables.LANG = config.i18n.defaultLocale;
|
||||
|
||||
# ‘/etc/locale.conf’ is used by systemd.
|
||||
environment.etc = singleton
|
||||
{ target = "locale.conf";
|
||||
source = pkgs.writeText "locale.conf"
|
||||
''
|
||||
LANG=${config.i18n.defaultLocale}
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
}
|
204
nixos/modules/config/krb5.nix
Normal file
204
nixos/modules/config/krb5.nix
Normal file
@ -0,0 +1,204 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.krb5;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
krb5 = {
|
||||
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
description = "Whether to enable Kerberos V.";
|
||||
};
|
||||
|
||||
defaultRealm = mkOption {
|
||||
default = "ATENA.MIT.EDU";
|
||||
description = "Default realm.";
|
||||
};
|
||||
|
||||
domainRealm = mkOption {
|
||||
default = "atena.mit.edu";
|
||||
description = "Default domain realm.";
|
||||
};
|
||||
|
||||
kdc = mkOption {
|
||||
default = "kerberos.mit.edu";
|
||||
description = "Kerberos Domain Controller";
|
||||
};
|
||||
|
||||
kerberosAdminServer = mkOption {
|
||||
default = "kerberos.mit.edu";
|
||||
description = "Kerberos Admin Server";
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf config.krb5.enable {
|
||||
|
||||
environment.systemPackages = [ pkgs.krb5 ];
|
||||
|
||||
environment.etc."krb5.conf".text =
|
||||
''
|
||||
[libdefaults]
|
||||
default_realm = ${cfg.defaultRealm}
|
||||
encrypt = true
|
||||
|
||||
# The following krb5.conf variables are only for MIT Kerberos.
|
||||
krb4_config = /etc/krb.conf
|
||||
krb4_realms = /etc/krb.realms
|
||||
kdc_timesync = 1
|
||||
ccache_type = 4
|
||||
forwardable = true
|
||||
proxiable = true
|
||||
|
||||
# The following encryption type specification will be used by MIT Kerberos
|
||||
# if uncommented. In general, the defaults in the MIT Kerberos code are
|
||||
# correct and overriding these specifications only serves to disable new
|
||||
# encryption types as they are added, creating interoperability problems.
|
||||
|
||||
# default_tgs_enctypes = aes256-cts arcfour-hmac-md5 des3-hmac-sha1 des-cbc-crc des-cbc-md5
|
||||
# default_tkt_enctypes = aes256-cts arcfour-hmac-md5 des3-hmac-sha1 des-cbc-crc des-cbc-md5
|
||||
# permitted_enctypes = aes256-cts arcfour-hmac-md5 des3-hmac-sha1 des-cbc-crc des-cbc-md5
|
||||
|
||||
# The following libdefaults parameters are only for Heimdal Kerberos.
|
||||
v4_instance_resolve = false
|
||||
v4_name_convert = {
|
||||
host = {
|
||||
rcmd = host
|
||||
ftp = ftp
|
||||
}
|
||||
plain = {
|
||||
something = something-else
|
||||
}
|
||||
}
|
||||
fcc-mit-ticketflags = true
|
||||
|
||||
[realms]
|
||||
${cfg.defaultRealm} = {
|
||||
kdc = ${cfg.kdc}
|
||||
admin_server = ${cfg.kerberosAdminServer}
|
||||
#kpasswd_server = ${cfg.kerberosAdminServer}
|
||||
}
|
||||
ATHENA.MIT.EDU = {
|
||||
kdc = kerberos.mit.edu:88
|
||||
kdc = kerberos-1.mit.edu:88
|
||||
kdc = kerberos-2.mit.edu:88
|
||||
admin_server = kerberos.mit.edu
|
||||
default_domain = mit.edu
|
||||
}
|
||||
MEDIA-LAB.MIT.EDU = {
|
||||
kdc = kerberos.media.mit.edu
|
||||
admin_server = kerberos.media.mit.edu
|
||||
}
|
||||
ZONE.MIT.EDU = {
|
||||
kdc = casio.mit.edu
|
||||
kdc = seiko.mit.edu
|
||||
admin_server = casio.mit.edu
|
||||
}
|
||||
MOOF.MIT.EDU = {
|
||||
kdc = three-headed-dogcow.mit.edu:88
|
||||
kdc = three-headed-dogcow-1.mit.edu:88
|
||||
admin_server = three-headed-dogcow.mit.edu
|
||||
}
|
||||
CSAIL.MIT.EDU = {
|
||||
kdc = kerberos-1.csail.mit.edu
|
||||
kdc = kerberos-2.csail.mit.edu
|
||||
admin_server = kerberos.csail.mit.edu
|
||||
default_domain = csail.mit.edu
|
||||
krb524_server = krb524.csail.mit.edu
|
||||
}
|
||||
IHTFP.ORG = {
|
||||
kdc = kerberos.ihtfp.org
|
||||
admin_server = kerberos.ihtfp.org
|
||||
}
|
||||
GNU.ORG = {
|
||||
kdc = kerberos.gnu.org
|
||||
kdc = kerberos-2.gnu.org
|
||||
kdc = kerberos-3.gnu.org
|
||||
admin_server = kerberos.gnu.org
|
||||
}
|
||||
1TS.ORG = {
|
||||
kdc = kerberos.1ts.org
|
||||
admin_server = kerberos.1ts.org
|
||||
}
|
||||
GRATUITOUS.ORG = {
|
||||
kdc = kerberos.gratuitous.org
|
||||
admin_server = kerberos.gratuitous.org
|
||||
}
|
||||
DOOMCOM.ORG = {
|
||||
kdc = kerberos.doomcom.org
|
||||
admin_server = kerberos.doomcom.org
|
||||
}
|
||||
ANDREW.CMU.EDU = {
|
||||
kdc = vice28.fs.andrew.cmu.edu
|
||||
kdc = vice2.fs.andrew.cmu.edu
|
||||
kdc = vice11.fs.andrew.cmu.edu
|
||||
kdc = vice12.fs.andrew.cmu.edu
|
||||
admin_server = vice28.fs.andrew.cmu.edu
|
||||
default_domain = andrew.cmu.edu
|
||||
}
|
||||
CS.CMU.EDU = {
|
||||
kdc = kerberos.cs.cmu.edu
|
||||
kdc = kerberos-2.srv.cs.cmu.edu
|
||||
admin_server = kerberos.cs.cmu.edu
|
||||
}
|
||||
DEMENTIA.ORG = {
|
||||
kdc = kerberos.dementia.org
|
||||
kdc = kerberos2.dementia.org
|
||||
admin_server = kerberos.dementia.org
|
||||
}
|
||||
stanford.edu = {
|
||||
kdc = krb5auth1.stanford.edu
|
||||
kdc = krb5auth2.stanford.edu
|
||||
kdc = krb5auth3.stanford.edu
|
||||
admin_server = krb5-admin.stanford.edu
|
||||
default_domain = stanford.edu
|
||||
}
|
||||
|
||||
[domain_realm]
|
||||
.${cfg.domainRealm} = ${cfg.defaultRealm}
|
||||
${cfg.domainRealm} = ${cfg.defaultRealm}
|
||||
.mit.edu = ATHENA.MIT.EDU
|
||||
mit.edu = ATHENA.MIT.EDU
|
||||
.media.mit.edu = MEDIA-LAB.MIT.EDU
|
||||
media.mit.edu = MEDIA-LAB.MIT.EDU
|
||||
.csail.mit.edu = CSAIL.MIT.EDU
|
||||
csail.mit.edu = CSAIL.MIT.EDU
|
||||
.whoi.edu = ATHENA.MIT.EDU
|
||||
whoi.edu = ATHENA.MIT.EDU
|
||||
.stanford.edu = stanford.edu
|
||||
|
||||
[logging]
|
||||
kdc = SYSLOG:INFO:DAEMON
|
||||
admin_server = SYSLOG:INFO:DAEMON
|
||||
default = SYSLOG:INFO:DAEMON
|
||||
krb4_convert = true
|
||||
krb4_get_tickets = false
|
||||
|
||||
[appdefaults]
|
||||
pam = {
|
||||
debug = false
|
||||
ticket_lifetime = 36000
|
||||
renew_lifetime = 36000
|
||||
max_timeout = 30
|
||||
timeout_shift = 2
|
||||
initial_timeout = 1
|
||||
}
|
||||
'';
|
||||
|
||||
};
|
||||
|
||||
}
|
246
nixos/modules/config/ldap.nix
Normal file
246
nixos/modules/config/ldap.nix
Normal file
@ -0,0 +1,246 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
with pkgs;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.users.ldap;
|
||||
|
||||
# Careful: OpenLDAP seems to be very picky about the indentation of
|
||||
# this file. Directives HAVE to start in the first column!
|
||||
ldapConfig = {
|
||||
target = "ldap.conf";
|
||||
source = writeText "ldap.conf" ''
|
||||
uri ${config.users.ldap.server}
|
||||
base ${config.users.ldap.base}
|
||||
timelimit ${toString config.users.ldap.timeLimit}
|
||||
bind_timelimit ${toString config.users.ldap.bind.timeLimit}
|
||||
bind_policy ${config.users.ldap.bind.policy}
|
||||
${optionalString config.users.ldap.useTLS ''
|
||||
ssl start_tls
|
||||
tls_checkpeer no
|
||||
''}
|
||||
${optionalString (config.users.ldap.bind.distinguishedName != "") ''
|
||||
binddn ${config.users.ldap.bind.distinguishedName}
|
||||
''}
|
||||
${optionalString (cfg.extraConfig != "") cfg.extraConfig }
|
||||
'';
|
||||
};
|
||||
|
||||
nslcdConfig = {
|
||||
target = "nslcd.conf";
|
||||
source = writeText "nslcd.conf" ''
|
||||
uid nslcd
|
||||
gid nslcd
|
||||
uri ${cfg.server}
|
||||
base ${cfg.base}
|
||||
timelimit ${toString cfg.timeLimit}
|
||||
bind_timelimit ${toString cfg.bind.timeLimit}
|
||||
${optionalString (cfg.bind.distinguishedName != "")
|
||||
"binddn ${cfg.bind.distinguishedName}" }
|
||||
${optionalString (cfg.daemon.extraConfig != "") cfg.daemon.extraConfig }
|
||||
'';
|
||||
};
|
||||
|
||||
insertLdapPassword = !config.users.ldap.daemon.enable &&
|
||||
config.users.ldap.bind.distinguishedName != "";
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
users.ldap = {
|
||||
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
description = "Whether to enable authentication against an LDAP server.";
|
||||
};
|
||||
|
||||
server = mkOption {
|
||||
example = "ldap://ldap.example.org/";
|
||||
description = "The URL of the LDAP server.";
|
||||
};
|
||||
|
||||
base = mkOption {
|
||||
example = "dc=example,dc=org";
|
||||
description = "The distinguished name of the search base.";
|
||||
};
|
||||
|
||||
useTLS = mkOption {
|
||||
default = false;
|
||||
description = ''
|
||||
If enabled, use TLS (encryption) over an LDAP (port 389)
|
||||
connection. The alternative is to specify an LDAPS server (port
|
||||
636) in <option>users.ldap.server</option> or to forego
|
||||
security.
|
||||
'';
|
||||
};
|
||||
|
||||
timeLimit = mkOption {
|
||||
default = 0;
|
||||
type = types.int;
|
||||
description = ''
|
||||
Specifies the time limit (in seconds) to use when performing
|
||||
searches. A value of zero (0), which is the default, is to
|
||||
wait indefinitely for searches to be completed.
|
||||
'';
|
||||
};
|
||||
|
||||
daemon = {
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to let the nslcd daemon (nss-pam-ldapd) handle the
|
||||
LDAP lookups for NSS and PAM. This can improve performance,
|
||||
and if you need to bind to the LDAP server with a password,
|
||||
it increases security, since only the nslcd user needs to
|
||||
have access to the bindpw file, not everyone that uses NSS
|
||||
and/or PAM. If this option is enabled, a local nscd user is
|
||||
created automatically, and the nslcd service is started
|
||||
automatically when the network get up.
|
||||
'';
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
default = "";
|
||||
type = types.string;
|
||||
description = ''
|
||||
Extra configuration options that will be added verbatim at
|
||||
the end of the nslcd configuration file (nslcd.conf).
|
||||
'' ;
|
||||
} ;
|
||||
};
|
||||
|
||||
bind = {
|
||||
distinguishedName = mkOption {
|
||||
default = "";
|
||||
example = "cn=admin,dc=example,dc=com";
|
||||
type = types.string;
|
||||
description = ''
|
||||
The distinguished name to bind to the LDAP server with. If this
|
||||
is not specified, an anonymous bind will be done.
|
||||
'';
|
||||
};
|
||||
|
||||
password = mkOption {
|
||||
default = "/etc/ldap/bind.password";
|
||||
type = types.string;
|
||||
description = ''
|
||||
The path to a file containing the credentials to use when binding
|
||||
to the LDAP server (if not binding anonymously).
|
||||
'';
|
||||
};
|
||||
|
||||
timeLimit = mkOption {
|
||||
default = 30;
|
||||
type = types.int;
|
||||
description = ''
|
||||
Specifies the time limit (in seconds) to use when connecting
|
||||
to the directory server. This is distinct from the time limit
|
||||
specified in <literal>users.ldap.timeLimit</literal> and affects
|
||||
the initial server connection only.
|
||||
'';
|
||||
};
|
||||
|
||||
policy = mkOption {
|
||||
default = "hard_open";
|
||||
type = types.string;
|
||||
description = ''
|
||||
Specifies the policy to use for reconnecting to an unavailable
|
||||
LDAP server. The default is <literal>hard_open</literal>, which
|
||||
reconnects if opening the connection to the directory server
|
||||
failed. By contrast, <literal>hard_init</literal> reconnects if
|
||||
initializing the connection failed. Initializing may not
|
||||
actually contact the directory server, and it is possible that
|
||||
a malformed configuration file will trigger reconnection. If
|
||||
<literal>soft</literal> is specified, then
|
||||
<literal>nss_ldap</literal> will return immediately on server
|
||||
failure. All hard reconnect policies block with exponential
|
||||
backoff before retrying.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
default = "";
|
||||
type = types.string;
|
||||
description = ''
|
||||
Extra configuration options that will be added verbatim at
|
||||
the end of the ldap configuration file (ldap.conf).
|
||||
If <literal>users.ldap.daemon</literal> is enabled, this
|
||||
configuration will not be used. In that case, use
|
||||
<literal>users.ldap.daemon.extraConfig</literal> instead.
|
||||
'' ;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
environment.etc = if cfg.daemon.enable then [nslcdConfig] else [ldapConfig];
|
||||
|
||||
system.activationScripts = mkIf insertLdapPassword {
|
||||
ldap = stringAfter [ "etc" "groups" "users" ] ''
|
||||
if test -f "${cfg.bind.password}" ; then
|
||||
echo "bindpw "$(cat ${cfg.bind.password})"" | cat ${ldapConfig} - > /etc/ldap.conf.bindpw
|
||||
mv -fT /etc/ldap.conf.bindpw /etc/ldap.conf
|
||||
chmod 600 /etc/ldap.conf
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
system.nssModules = singleton (
|
||||
if cfg.daemon.enable then nss_pam_ldapd else nss_ldap
|
||||
);
|
||||
|
||||
users = mkIf cfg.daemon.enable {
|
||||
extraGroups.nslcd = {
|
||||
gid = config.ids.gids.nslcd;
|
||||
};
|
||||
|
||||
extraUsers.nslcd = {
|
||||
uid = config.ids.uids.nslcd;
|
||||
description = "nslcd user.";
|
||||
group = "nslcd";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services = mkIf cfg.daemon.enable {
|
||||
|
||||
nslcd = {
|
||||
wantedBy = [ "nss-user-lookup.target" ];
|
||||
before = [ "nss-user-lookup.target" ];
|
||||
after = [ "network.target" ];
|
||||
|
||||
preStart = ''
|
||||
mkdir -p /run/nslcd
|
||||
rm -f /run/nslcd/nslcd.pid;
|
||||
chown nslcd.nslcd /run/nslcd
|
||||
${optionalString (cfg.bind.distinguishedName != "") ''
|
||||
if test -s "${cfg.bind.password}" ; then
|
||||
ln -sfT "${cfg.bind.password}" /run/nslcd/bindpw
|
||||
fi
|
||||
''}
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = "${nss_pam_ldapd}/sbin/nslcd";
|
||||
Type = "forking";
|
||||
PIDFile = "/run/nslcd/nslcd.pid";
|
||||
Restart = "always";
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
}
|
88
nixos/modules/config/networking.nix
Normal file
88
nixos/modules/config/networking.nix
Normal file
@ -0,0 +1,88 @@
|
||||
# /etc files related to networking, such as /etc/services.
|
||||
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.networking;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
options = {
|
||||
|
||||
networking.extraHosts = pkgs.lib.mkOption {
|
||||
default = "";
|
||||
example = "192.168.0.1 lanlocalhost";
|
||||
description = ''
|
||||
Additional entries to be appended to <filename>/etc/hosts</filename>.
|
||||
'';
|
||||
};
|
||||
|
||||
networking.dnsSingleRequest = pkgs.lib.mkOption {
|
||||
default = false;
|
||||
description = ''
|
||||
Recent versions of glibc will issue both ipv4 (A) and ipv6 (AAAA)
|
||||
address queries at the same time, from the same port. Sometimes upstream
|
||||
routers will systemically drop the ipv4 queries. The symptom of this problem is
|
||||
that 'getent hosts example.com' only returns ipv6 (or perhaps only ipv4) addresses. The
|
||||
workaround for this is to specify the option 'single-request' in
|
||||
/etc/resolv.conf. This option enables that.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = {
|
||||
|
||||
environment.etc =
|
||||
{ # /etc/services: TCP/UDP port assignments.
|
||||
"services".source = pkgs.iana_etc + "/etc/services";
|
||||
|
||||
# /etc/protocols: IP protocol numbers.
|
||||
"protocols".source = pkgs.iana_etc + "/etc/protocols";
|
||||
|
||||
# /etc/rpc: RPC program numbers.
|
||||
"rpc".source = pkgs.glibc + "/etc/rpc";
|
||||
|
||||
# /etc/hosts: Hostname-to-IP mappings.
|
||||
"hosts".text =
|
||||
''
|
||||
127.0.0.1 localhost
|
||||
${optionalString cfg.enableIPv6 ''
|
||||
::1 localhost
|
||||
''}
|
||||
${cfg.extraHosts}
|
||||
'';
|
||||
|
||||
# /etc/resolvconf.conf: Configuration for openresolv.
|
||||
"resolvconf.conf".text =
|
||||
''
|
||||
# This is the default, but we must set it here to prevent
|
||||
# a collision with an apparently unrelated environment
|
||||
# variable with the same name exported by dhcpcd.
|
||||
interface_order='lo lo[0-9]*'
|
||||
'' + optionalString config.services.nscd.enable ''
|
||||
# Invalidate the nscd cache whenever resolv.conf is
|
||||
# regenerated.
|
||||
libc_restart='${pkgs.systemd}/bin/systemctl try-restart --no-block nscd.service'
|
||||
'' + optionalString cfg.dnsSingleRequest ''
|
||||
# only send one DNS request at a time
|
||||
resolv_conf_options='single-request'
|
||||
'' + optionalString config.services.bind.enable ''
|
||||
# This hosts runs a full-blown DNS resolver.
|
||||
name_servers='127.0.0.1'
|
||||
'';
|
||||
};
|
||||
|
||||
# The ‘ip-up’ target is started when we have IP connectivity. So
|
||||
# services that depend on IP connectivity (like ntpd) should be
|
||||
# pulled in by this target.
|
||||
systemd.targets.ip-up.description = "Services Requiring IP Connectivity";
|
||||
|
||||
};
|
||||
|
||||
}
|
23
nixos/modules/config/no-x-libs.nix
Normal file
23
nixos/modules/config/no-x-libs.nix
Normal file
@ -0,0 +1,23 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
options = {
|
||||
environment.noXlibs = pkgs.lib.mkOption {
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Switch off the options in the default configuration that require X libraries.
|
||||
Currently this includes: ssh X11 forwarding, dbus, fonts.enableCoreFonts,
|
||||
fonts.enableFontConfig
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = pkgs.lib.mkIf config.environment.noXlibs {
|
||||
programs.ssh.setXAuthLocation = false;
|
||||
fonts = {
|
||||
enableCoreFonts = false;
|
||||
enableFontConfig = false;
|
||||
};
|
||||
};
|
||||
}
|
63
nixos/modules/config/nsswitch.nix
Normal file
63
nixos/modules/config/nsswitch.nix
Normal file
@ -0,0 +1,63 @@
|
||||
# Configuration for the Name Service Switch (/etc/nsswitch.conf).
|
||||
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
inherit (config.services.avahi) nssmdns;
|
||||
inherit (config.services.samba) nsswins;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
|
||||
# NSS modules. Hacky!
|
||||
system.nssModules = mkOption {
|
||||
internal = true;
|
||||
default = [];
|
||||
description = ''
|
||||
Search path for NSS (Name Service Switch) modules. This allows
|
||||
several DNS resolution methods to be specified via
|
||||
<filename>/etc/nsswitch.conf</filename>.
|
||||
'';
|
||||
merge = mergeListOption;
|
||||
apply = list:
|
||||
{
|
||||
inherit list;
|
||||
path = makeLibraryPath list;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = {
|
||||
|
||||
environment.etc =
|
||||
[ # Name Service Switch configuration file. Required by the C library.
|
||||
# !!! Factor out the mdns stuff. The avahi module should define
|
||||
# an option used by this module.
|
||||
{ source = pkgs.writeText "nsswitch.conf"
|
||||
''
|
||||
passwd: files ldap
|
||||
group: files ldap
|
||||
shadow: files ldap
|
||||
hosts: files ${optionalString nssmdns "mdns_minimal [NOTFOUND=return]"} dns ${optionalString nssmdns "mdns"} ${optionalString nsswins "wins"} myhostname
|
||||
networks: files dns
|
||||
ethers: files
|
||||
services: files
|
||||
protocols: files
|
||||
'';
|
||||
target = "nsswitch.conf";
|
||||
}
|
||||
];
|
||||
|
||||
# Use nss-myhostname to ensure that our hostname always resolves to
|
||||
# a valid IP address. It returns all locally configured IP
|
||||
# addresses, or ::1 and 127.0.0.2 as fallbacks.
|
||||
system.nssModules = [ pkgs.systemd ];
|
||||
|
||||
};
|
||||
}
|
108
nixos/modules/config/power-management.nix
Normal file
108
nixos/modules/config/power-management.nix
Normal file
@ -0,0 +1,108 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.powerManagement;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
powerManagement = {
|
||||
|
||||
enable = mkOption {
|
||||
default = true;
|
||||
description =
|
||||
''
|
||||
Whether to enable power management. This includes support
|
||||
for suspend-to-RAM and powersave features on laptops.
|
||||
'';
|
||||
};
|
||||
|
||||
resumeCommands = mkOption {
|
||||
default = "";
|
||||
description = "Commands executed after the system resumes from suspend-to-RAM.";
|
||||
};
|
||||
|
||||
powerUpCommands = mkOption {
|
||||
default = "";
|
||||
example = "${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda";
|
||||
description =
|
||||
''
|
||||
Commands executed when the machine powers up. That is,
|
||||
they're executed both when the system first boots and when
|
||||
it resumes from suspend or hibernation.
|
||||
'';
|
||||
};
|
||||
|
||||
powerDownCommands = mkOption {
|
||||
default = "";
|
||||
example = "${pkgs.hdparm}/sbin/hdparm -B 255 /dev/sda";
|
||||
description =
|
||||
''
|
||||
Commands executed when the machine powers down. That is,
|
||||
they're executed both when the system shuts down and when
|
||||
it goes to suspend or hibernation.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
|
||||
# Enable the ACPI daemon. Not sure whether this is essential.
|
||||
services.acpid.enable = true;
|
||||
|
||||
boot.kernelModules =
|
||||
[ "acpi_cpufreq" "powernow-k8" "cpufreq_performance" "cpufreq_powersave" "cpufreq_ondemand"
|
||||
"cpufreq_conservative"
|
||||
];
|
||||
|
||||
powerManagement.cpuFreqGovernor = mkDefault "ondemand";
|
||||
powerManagement.scsiLinkPolicy = mkDefault "min_power";
|
||||
|
||||
systemd.targets.post-resume = {
|
||||
description = "Post-Resume Actions";
|
||||
requires = [ "post-resume.service" ];
|
||||
after = [ "post-resume.service" ];
|
||||
wantedBy = [ "sleep.target" ];
|
||||
unitConfig.StopWhenUnneeded = true;
|
||||
};
|
||||
|
||||
# Service executed before suspending/hibernating.
|
||||
systemd.services."pre-sleep" =
|
||||
{ description = "Pre-Sleep Actions";
|
||||
wantedBy = [ "sleep.target" ];
|
||||
before = [ "sleep.target" ];
|
||||
script =
|
||||
''
|
||||
${cfg.powerDownCommands}
|
||||
'';
|
||||
serviceConfig.Type = "oneshot";
|
||||
};
|
||||
|
||||
systemd.services."post-resume" =
|
||||
{ description = "Post-Resume Actions";
|
||||
after = [ "suspend.target" "hibernate.target" "hybrid-sleep.target" ];
|
||||
script =
|
||||
''
|
||||
${cfg.resumeCommands}
|
||||
${cfg.powerUpCommands}
|
||||
'';
|
||||
serviceConfig.Type = "oneshot";
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
148
nixos/modules/config/pulseaudio.nix
Normal file
148
nixos/modules/config/pulseaudio.nix
Normal file
@ -0,0 +1,148 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
with pkgs;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.hardware.pulseaudio;
|
||||
|
||||
uid = config.ids.uids.pulseaudio;
|
||||
gid = config.ids.gids.pulseaudio;
|
||||
|
||||
pulseRuntimePath = "/var/run/pulse";
|
||||
|
||||
# Create pulse/client.conf even if PulseAudio is disabled so
|
||||
# that we can disable the autospawn feature in programs that
|
||||
# are built with PulseAudio support (like KDE).
|
||||
clientConf = writeText "client.conf" ''
|
||||
autospawn=${if (cfg.enable && !cfg.systemWide) then "yes" else "no"}
|
||||
${optionalString (cfg.enable && !cfg.systemWide)
|
||||
"daemon-binary=${cfg.package}/bin/pulseaudio"}
|
||||
'';
|
||||
|
||||
# Write an /etc/asound.conf that causes all ALSA applications to
|
||||
# be re-routed to the PulseAudio server through ALSA's Pulse
|
||||
# plugin.
|
||||
alsaConf = writeText "asound.conf" ''
|
||||
pcm_type.pulse {
|
||||
lib ${alsaPlugins}/lib/alsa-lib/libasound_module_pcm_pulse.so
|
||||
}
|
||||
pcm.!default {
|
||||
type pulse
|
||||
hint.description "Default Audio Device (via PulseAudio)"
|
||||
}
|
||||
ctl_type.pulse {
|
||||
lib ${alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so
|
||||
}
|
||||
ctl.!default {
|
||||
type pulse
|
||||
}
|
||||
'';
|
||||
|
||||
in {
|
||||
|
||||
options = {
|
||||
|
||||
hardware.pulseaudio = {
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable the PulseAudio sound server.
|
||||
'';
|
||||
};
|
||||
|
||||
systemWide = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
If false, a PulseAudio server is launched automatically for
|
||||
each user that tries to use the sound system. The server runs
|
||||
with user privileges. This is the recommended and most secure
|
||||
way to use PulseAudio. If true, one system-wide PulseAudio
|
||||
server is launched on boot, running as the user "pulse".
|
||||
Please read the PulseAudio documentation for more details.
|
||||
'';
|
||||
};
|
||||
|
||||
configFile = mkOption {
|
||||
type = types.uniq types.path;
|
||||
default = "${pulseaudio}/etc/pulse/default.pa";
|
||||
description = ''
|
||||
The path to the configuration the PulseAudio server
|
||||
should use. By default, the "default.pa" configuration
|
||||
from the PulseAudio distribution is used.
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
default = pulseaudio;
|
||||
example = "pulseaudio.override { jackaudioSupport = true; }";
|
||||
description = ''
|
||||
The PulseAudio derivation to use. This can be used to enable
|
||||
features (such as JACK support) that are not enabled in the
|
||||
default PulseAudio in Nixpkgs.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
config = mkMerge [
|
||||
{
|
||||
environment.etc = singleton {
|
||||
target = "pulse/client.conf";
|
||||
source = clientConf;
|
||||
};
|
||||
}
|
||||
|
||||
(mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
environment.etc = singleton {
|
||||
target = "asound.conf";
|
||||
source = alsaConf;
|
||||
};
|
||||
|
||||
# Allow PulseAudio to get realtime priority using rtkit.
|
||||
security.rtkit.enable = true;
|
||||
})
|
||||
|
||||
(mkIf (cfg.enable && !cfg.systemWide) {
|
||||
environment.etc = singleton {
|
||||
target = "pulse/default.pa";
|
||||
source = cfg.configFile;
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf (cfg.enable && cfg.systemWide) {
|
||||
users.extraUsers.pulse = {
|
||||
# For some reason, PulseAudio wants UID == GID.
|
||||
uid = assert uid == gid; uid;
|
||||
group = "pulse";
|
||||
extraGroups = [ "audio" ];
|
||||
description = "PulseAudio system service user";
|
||||
home = pulseRuntimePath;
|
||||
};
|
||||
|
||||
users.extraGroups.pulse.gid = gid;
|
||||
|
||||
systemd.services.pulseaudio = {
|
||||
description = "PulseAudio system-wide server";
|
||||
wantedBy = [ "sound.target" ];
|
||||
before = [ "sound.target" ];
|
||||
path = [ cfg.package ];
|
||||
environment.PULSE_RUNTIME_PATH = pulseRuntimePath;
|
||||
preStart = ''
|
||||
mkdir -p --mode 755 ${pulseRuntimePath}
|
||||
chown -R pulse:pulse ${pulseRuntimePath}
|
||||
'';
|
||||
script = ''
|
||||
exec pulseaudio --system -n --file="${cfg.configFile}"
|
||||
'';
|
||||
};
|
||||
})
|
||||
];
|
||||
|
||||
}
|
179
nixos/modules/config/shells-environment.nix
Normal file
179
nixos/modules/config/shells-environment.nix
Normal file
@ -0,0 +1,179 @@
|
||||
# This module defines a global environment configuration and
|
||||
# a common configuration for all shells.
|
||||
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.environment;
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
options = {
|
||||
|
||||
environment.variables = mkOption {
|
||||
default = {};
|
||||
description = ''
|
||||
A set of environment variables used in the global environment.
|
||||
The value of each variable can be either a string or a list of
|
||||
strings. The latter is concatenated, interspersed with colon
|
||||
characters.
|
||||
'';
|
||||
type = types.attrsOf (mkOptionType {
|
||||
name = "a string or a list of strings";
|
||||
merge = xs:
|
||||
let xs' = evalProperties xs; in
|
||||
if isList (head xs') then concatLists xs'
|
||||
else if builtins.lessThan 1 (length xs') then abort "variable in ‘environment.variables’ has multiple values"
|
||||
else if !builtins.isString (head xs') then abort "variable in ‘environment.variables’ does not have a string value"
|
||||
else head xs';
|
||||
});
|
||||
apply = mapAttrs (n: v: if isList v then concatStringsSep ":" v else v);
|
||||
};
|
||||
|
||||
environment.profiles = mkOption {
|
||||
default = [];
|
||||
description = ''
|
||||
A list of profiles used to setup the global environment.
|
||||
'';
|
||||
type = types.listOf types.string;
|
||||
};
|
||||
|
||||
environment.profileVariables = mkOption {
|
||||
default = (p: {});
|
||||
description = ''
|
||||
A function which given a profile path should give back
|
||||
a set of environment variables for that profile.
|
||||
'';
|
||||
# !!! this should be of the following type:
|
||||
#type = types.functionTo (types.attrsOf (types.optionSet envVar));
|
||||
# and envVar should be changed to something more like environOpts.
|
||||
# Having unique `value' _or_ multiple `list' is much more useful
|
||||
# than just sticking everything together with ':' unconditionally.
|
||||
# Anyway, to have this type mentioned above
|
||||
# types.optionSet needs to be transformed into a type constructor
|
||||
# (it has a !!! mark on that in nixpkgs)
|
||||
# for now we hack all this to be
|
||||
type = types.functionTo (types.attrsOf (types.listOf types.string));
|
||||
};
|
||||
|
||||
# !!! isn't there a better way?
|
||||
environment.extraInit = mkOption {
|
||||
default = "";
|
||||
description = ''
|
||||
Shell script code called during global environment initialisation
|
||||
after all variables and profileVariables have been set.
|
||||
This code is asumed to be shell-independent, which means you should
|
||||
stick to pure sh without sh word split.
|
||||
'';
|
||||
type = types.lines;
|
||||
};
|
||||
|
||||
environment.shellInit = mkOption {
|
||||
default = "";
|
||||
description = ''
|
||||
Shell script code called during shell initialisation.
|
||||
This code is asumed to be shell-independent, which means you should
|
||||
stick to pure sh without sh word split.
|
||||
'';
|
||||
type = types.lines;
|
||||
};
|
||||
|
||||
environment.loginShellInit = mkOption {
|
||||
default = "";
|
||||
description = ''
|
||||
Shell script code called during login shell initialisation.
|
||||
This code is asumed to be shell-independent, which means you should
|
||||
stick to pure sh without sh word split.
|
||||
'';
|
||||
type = types.lines;
|
||||
};
|
||||
|
||||
environment.interactiveShellInit = mkOption {
|
||||
default = "";
|
||||
description = ''
|
||||
Shell script code called during interactive shell initialisation.
|
||||
This code is asumed to be shell-independent, which means you should
|
||||
stick to pure sh without sh word split.
|
||||
'';
|
||||
type = types.lines;
|
||||
};
|
||||
|
||||
environment.shellAliases = mkOption {
|
||||
default = {};
|
||||
example = { ll = "ls -l"; };
|
||||
description = ''
|
||||
An attribute set that maps aliases (the top level attribute names in
|
||||
this option) to command strings or directly to build outputs. The
|
||||
aliases are added to all users' shells.
|
||||
'';
|
||||
type = types.attrs; # types.attrsOf types.stringOrPath;
|
||||
};
|
||||
|
||||
environment.binsh = mkOption {
|
||||
default = "${config.system.build.binsh}/bin/sh";
|
||||
example = "\${pkgs.dash}/bin/dash";
|
||||
type = types.path;
|
||||
description = ''
|
||||
The shell executable that is linked system-wide to
|
||||
<literal>/bin/sh</literal>. Please note that NixOS assumes all
|
||||
over the place that shell to be Bash, so override the default
|
||||
setting only if you know exactly what you're doing.
|
||||
'';
|
||||
};
|
||||
|
||||
environment.shells = mkOption {
|
||||
default = [];
|
||||
example = [ "/run/current-system/sw/bin/zsh" ];
|
||||
description = ''
|
||||
A list of permissible login shells for user accounts.
|
||||
No need to mention <literal>/bin/sh</literal>
|
||||
here, it is placed into this list implicitly.
|
||||
'';
|
||||
type = types.listOf types.path;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = {
|
||||
|
||||
system.build.binsh = pkgs.bashInteractive;
|
||||
|
||||
environment.etc."shells".text =
|
||||
''
|
||||
${concatStringsSep "\n" cfg.shells}
|
||||
/bin/sh
|
||||
'';
|
||||
|
||||
system.build.setEnvironment = pkgs.writeText "set-environment"
|
||||
''
|
||||
${concatStringsSep "\n" (
|
||||
(mapAttrsToList (n: v: ''export ${n}="${concatStringsSep ":" v}"'')
|
||||
# This line is a kind of a hack because of !!! note above
|
||||
(zipAttrsWith (const concatLists) ([ (mapAttrs (n: v: [ v ]) cfg.variables) ] ++ map cfg.profileVariables cfg.profiles))))}
|
||||
|
||||
${cfg.extraInit}
|
||||
|
||||
# The setuid wrappers override other bin directories.
|
||||
export PATH="${config.security.wrapperDir}:$PATH"
|
||||
|
||||
# ~/bin if it exists overrides other bin directories.
|
||||
export PATH="$HOME/bin:$PATH"
|
||||
'';
|
||||
|
||||
system.activationScripts.binsh = stringAfter [ "stdio" ]
|
||||
''
|
||||
# Create the required /bin/sh symlink; otherwise lots of things
|
||||
# (notably the system() function) won't work.
|
||||
mkdir -m 0755 -p /bin
|
||||
ln -sfn "${cfg.binsh}" /bin/.sh.tmp
|
||||
mv /bin/.sh.tmp /bin/sh # atomically replace /bin/sh
|
||||
'';
|
||||
|
||||
};
|
||||
|
||||
}
|
124
nixos/modules/config/swap.nix
Normal file
124
nixos/modules/config/swap.nix
Normal file
@ -0,0 +1,124 @@
|
||||
{ config, pkgs, utils, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
with utils;
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
swapDevices = mkOption {
|
||||
default = [];
|
||||
example = [
|
||||
{ device = "/dev/hda7"; }
|
||||
{ device = "/var/swapfile"; }
|
||||
{ label = "bigswap"; }
|
||||
];
|
||||
description = ''
|
||||
The swap devices and swap files. These must have been
|
||||
initialised using <command>mkswap</command>. Each element
|
||||
should be an attribute set specifying either the path of the
|
||||
swap device or file (<literal>device</literal>) or the label
|
||||
of the swap device (<literal>label</literal>, see
|
||||
<command>mkswap -L</command>). Using a label is
|
||||
recommended.
|
||||
'';
|
||||
|
||||
type = types.listOf types.optionSet;
|
||||
|
||||
options = {config, options, ...}: {
|
||||
|
||||
options = {
|
||||
|
||||
device = mkOption {
|
||||
example = "/dev/sda3";
|
||||
type = types.uniq types.string;
|
||||
description = "Path of the device.";
|
||||
};
|
||||
|
||||
label = mkOption {
|
||||
example = "swap";
|
||||
type = types.uniq types.string;
|
||||
description = ''
|
||||
Label of the device. Can be used instead of <varname>device</varname>.
|
||||
'';
|
||||
};
|
||||
|
||||
size = mkOption {
|
||||
default = null;
|
||||
example = 2048;
|
||||
type = types.nullOr types.int;
|
||||
description = ''
|
||||
If this option is set, ‘device’ is interpreted as the
|
||||
path of a swapfile that will be created automatically
|
||||
with the indicated size (in megabytes) if it doesn't
|
||||
exist.
|
||||
'';
|
||||
};
|
||||
|
||||
priority = mkOption {
|
||||
default = null;
|
||||
example = 2048;
|
||||
type = types.nullOr types.int;
|
||||
description = ''
|
||||
Specify the priority of the swap device. Priority is a value between 0 and 32767.
|
||||
Higher numbers indicate higher priority.
|
||||
null lets the kernel choose a priority, which will show up as a negative value.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = {
|
||||
device =
|
||||
if options.label.isDefined then
|
||||
"/dev/disk/by-label/${config.label}"
|
||||
else
|
||||
mkNotdef;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = mkIf ((length config.swapDevices) != 0) {
|
||||
|
||||
system.requiredKernelConfig = with config.lib.kernelConfig; [
|
||||
(isYes "SWAP")
|
||||
];
|
||||
|
||||
# Create missing swapfiles.
|
||||
# FIXME: support changing the size of existing swapfiles.
|
||||
systemd.services =
|
||||
let
|
||||
|
||||
createSwapDevice = sw:
|
||||
assert sw.device != "";
|
||||
let device' = escapeSystemdPath sw.device; in
|
||||
nameValuePair "mkswap-${escapeSystemdPath sw.device}"
|
||||
{ description = "Initialisation of Swapfile ${sw.device}";
|
||||
wantedBy = [ "${device'}.swap" ];
|
||||
before = [ "${device'}.swap" ];
|
||||
path = [ pkgs.utillinux ];
|
||||
script =
|
||||
''
|
||||
if [ ! -e "${sw.device}" ]; then
|
||||
fallocate -l ${toString sw.size}M "${sw.device}" ||
|
||||
dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size}
|
||||
mkswap ${sw.device}
|
||||
fi
|
||||
'';
|
||||
unitConfig.RequiresMountsFor = [ "${dirOf sw.device}" ];
|
||||
unitConfig.DefaultDependencies = false; # needed to prevent a cycle
|
||||
serviceConfig.Type = "oneshot";
|
||||
};
|
||||
|
||||
in listToAttrs (map createSwapDevice (filter (sw: sw.size != null) config.swapDevices));
|
||||
|
||||
};
|
||||
|
||||
}
|
69
nixos/modules/config/sysctl.nix
Normal file
69
nixos/modules/config/sysctl.nix
Normal file
@ -0,0 +1,69 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
sysctlOption = mkOptionType {
|
||||
name = "sysctl option value";
|
||||
check = x: builtins.isBool x || builtins.isString x || builtins.isInt x;
|
||||
merge = xs: last xs; # FIXME: hacky way to allow overriding in configuration.nix.
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
options = {
|
||||
|
||||
boot.kernel.sysctl = mkOption {
|
||||
default = {};
|
||||
example = {
|
||||
"net.ipv4.tcp_syncookies" = false;
|
||||
"vm.swappiness" = 60;
|
||||
};
|
||||
type = types.attrsOf sysctlOption;
|
||||
description = ''
|
||||
Runtime parameters of the Linux kernel, as set by
|
||||
<citerefentry><refentrytitle>sysctl</refentrytitle>
|
||||
<manvolnum>8</manvolnum></citerefentry>. Note that sysctl
|
||||
parameters names must be enclosed in quotes
|
||||
(e.g. <literal>"vm.swappiness"</literal> instead of
|
||||
<literal>vm.swappiness</literal>). The value of each parameter
|
||||
may be a string, integer or Boolean.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = {
|
||||
|
||||
environment.etc."sysctl.d/nixos.conf".text =
|
||||
concatStrings (mapAttrsToList (n: v: "${n}=${if v == false then "0" else toString v}\n") config.boot.kernel.sysctl);
|
||||
|
||||
systemd.services.systemd-sysctl =
|
||||
{ description = "Apply Kernel Variables";
|
||||
before = [ "sysinit.target" "shutdown.target" ];
|
||||
wantedBy = [ "sysinit.target" "multi-user.target" ];
|
||||
restartTriggers = [ config.environment.etc."sysctl.d/nixos.conf".source ];
|
||||
unitConfig.DefaultDependencies = false; # needed to prevent a cycle
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecStart = "${config.systemd.package}/lib/systemd/systemd-sysctl";
|
||||
};
|
||||
};
|
||||
|
||||
# Enable hardlink and symlink restrictions. See
|
||||
# https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=800179c9b8a1e796e441674776d11cd4c05d61d7
|
||||
# for details.
|
||||
boot.kernel.sysctl."fs.protected_hardlinks" = true;
|
||||
boot.kernel.sysctl."fs.protected_symlinks" = true;
|
||||
|
||||
# Hide kernel pointers (e.g. in /proc/modules) for unprivileged
|
||||
# users as these make it easier to exploit kernel vulnerabilities.
|
||||
boot.kernel.sysctl."kernel.kptr_restrict" = 1;
|
||||
|
||||
};
|
||||
|
||||
}
|
142
nixos/modules/config/system-path.nix
Normal file
142
nixos/modules/config/system-path.nix
Normal file
@ -0,0 +1,142 @@
|
||||
# This module defines the packages that appear in
|
||||
# /run/current-system/sw.
|
||||
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
cfg = config.environment;
|
||||
|
||||
extraManpages = pkgs.runCommand "extra-manpages" { buildInputs = [ pkgs.help2man ]; }
|
||||
''
|
||||
mkdir -p $out/share/man/man1
|
||||
help2man ${pkgs.gnutar}/bin/tar > $out/share/man/man1/tar.1
|
||||
'';
|
||||
|
||||
requiredPackages =
|
||||
[ config.environment.nix
|
||||
pkgs.acl
|
||||
pkgs.attr
|
||||
pkgs.bashInteractive # bash with ncurses support
|
||||
pkgs.bzip2
|
||||
pkgs.coreutils
|
||||
pkgs.cpio
|
||||
pkgs.curl
|
||||
pkgs.diffutils
|
||||
pkgs.eject # HAL depends on it anyway
|
||||
pkgs.findutils
|
||||
pkgs.gawk
|
||||
pkgs.glibc # for ldd, getent
|
||||
pkgs.gnugrep
|
||||
pkgs.gnupatch
|
||||
pkgs.gnused
|
||||
pkgs.gnutar
|
||||
pkgs.gzip
|
||||
pkgs.xz
|
||||
pkgs.less
|
||||
pkgs.libcap
|
||||
pkgs.man
|
||||
pkgs.nano
|
||||
pkgs.ncurses
|
||||
pkgs.netcat
|
||||
pkgs.openssh
|
||||
pkgs.pciutils
|
||||
pkgs.perl
|
||||
pkgs.procps
|
||||
pkgs.rsync
|
||||
pkgs.strace
|
||||
pkgs.sysvtools
|
||||
pkgs.time
|
||||
pkgs.usbutils
|
||||
pkgs.utillinux
|
||||
extraManpages
|
||||
];
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
options = {
|
||||
|
||||
environment = {
|
||||
|
||||
systemPackages = mkOption {
|
||||
default = [];
|
||||
example = "[ pkgs.icecat3 pkgs.thunderbird ]";
|
||||
description = ''
|
||||
The set of packages that appear in
|
||||
/run/current-system/sw. These packages are
|
||||
automatically available to all users, and are
|
||||
automatically updated every time you rebuild the system
|
||||
configuration. (The latter is the main difference with
|
||||
installing them in the default profile,
|
||||
<filename>/nix/var/nix/profiles/default</filename>.
|
||||
'';
|
||||
};
|
||||
|
||||
pathsToLink = mkOption {
|
||||
# Note: We need `/lib' to be among `pathsToLink' for NSS modules
|
||||
# to work.
|
||||
default = [];
|
||||
example = ["/"];
|
||||
description = "List of directories to be symlinked in `/run/current-system/sw'.";
|
||||
};
|
||||
};
|
||||
|
||||
system = {
|
||||
|
||||
path = mkOption {
|
||||
default = cfg.systemPackages;
|
||||
description = ''
|
||||
The packages you want in the boot environment.
|
||||
'';
|
||||
|
||||
apply = list: pkgs.buildEnv {
|
||||
name = "system-path";
|
||||
paths = list;
|
||||
inherit (cfg) pathsToLink;
|
||||
ignoreCollisions = true;
|
||||
# !!! Hacky, should modularise.
|
||||
postBuild =
|
||||
''
|
||||
if [ -x $out/bin/update-mime-database -a -w $out/share/mime/packages ]; then
|
||||
$out/bin/update-mime-database -V $out/share/mime
|
||||
fi
|
||||
|
||||
if [ -x $out/bin/gtk-update-icon-cache -a -f $out/share/icons/hicolor/index.theme ]; then
|
||||
$out/bin/gtk-update-icon-cache $out/share/icons/hicolor
|
||||
fi
|
||||
|
||||
if [ -x $out/bin/glib-compile-schemas -a -w $out/share/glib-2.0/schemas ]; then
|
||||
$out/bin/glib-compile-schemas $out/share/glib-2.0/schemas
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = {
|
||||
|
||||
environment.systemPackages = requiredPackages;
|
||||
|
||||
environment.pathsToLink =
|
||||
[ "/bin"
|
||||
"/etc/xdg"
|
||||
"/info"
|
||||
"/lib"
|
||||
"/man"
|
||||
"/sbin"
|
||||
"/share/emacs"
|
||||
"/share/org"
|
||||
"/share/info"
|
||||
"/share/terminfo"
|
||||
"/share/man"
|
||||
];
|
||||
|
||||
};
|
||||
}
|
36
nixos/modules/config/timezone.nix
Normal file
36
nixos/modules/config/timezone.nix
Normal file
@ -0,0 +1,36 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
{
|
||||
options = {
|
||||
|
||||
time = {
|
||||
|
||||
timeZone = mkOption {
|
||||
default = "CET";
|
||||
type = with types; uniq string;
|
||||
example = "America/New_York";
|
||||
description = "The time zone used when displaying times and dates.";
|
||||
};
|
||||
|
||||
hardwareClockInLocalTime = mkOption {
|
||||
default = false;
|
||||
description = "If set, keep the hardware clock in local time instead of UTC.";
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
|
||||
environment.variables.TZDIR = "/etc/zoneinfo";
|
||||
environment.variables.TZ = config.time.timeZone;
|
||||
|
||||
environment.etc.localtime.source = "${pkgs.tzdata}/share/zoneinfo/${config.time.timeZone}";
|
||||
|
||||
environment.etc.zoneinfo.source = "${pkgs.tzdata}/share/zoneinfo";
|
||||
|
||||
};
|
||||
|
||||
}
|
34
nixos/modules/config/unix-odbc-drivers.nix
Normal file
34
nixos/modules/config/unix-odbc-drivers.nix
Normal file
@ -0,0 +1,34 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
# unixODBC drivers (this solution is not perfect.. Because the user has to
|
||||
# ask the admin to add a driver.. but it's simple and works
|
||||
|
||||
{
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
environment.unixODBCDrivers = mkOption {
|
||||
default = [];
|
||||
example = literalExample "map (x : x.ini) (with pkgs.unixODBCDrivers; [ mysql psql psqlng ] )";
|
||||
description = ''
|
||||
Specifies Unix ODBC drivers to be registered in
|
||||
<filename>/etc/odbcinst.ini</filename>. You may also want to
|
||||
add <literal>pkgs.unixODBC</literal> to the system path to get
|
||||
a command line client to connnect to ODBC databases.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf (config.environment.unixODBCDrivers != []) {
|
||||
|
||||
environment.etc."odbcinst.ini".text =
|
||||
let inis = config.environment.unixODBCDrivers;
|
||||
in pkgs.lib.concatStringsSep "\n" inis;
|
||||
|
||||
};
|
||||
|
||||
}
|
315
nixos/modules/config/users-groups.nix
Normal file
315
nixos/modules/config/users-groups.nix
Normal file
@ -0,0 +1,315 @@
|
||||
{pkgs, config, ...}:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
ids = config.ids;
|
||||
users = config.users;
|
||||
|
||||
userOpts = { name, config, ... }: {
|
||||
|
||||
options = {
|
||||
|
||||
name = mkOption {
|
||||
type = with types; uniq string;
|
||||
description = "The name of the user account. If undefined, the name of the attribute set will be used.";
|
||||
};
|
||||
|
||||
description = mkOption {
|
||||
type = with types; uniq string;
|
||||
default = "";
|
||||
description = "A short description of the user account.";
|
||||
};
|
||||
|
||||
uid = mkOption {
|
||||
type = with types; uniq (nullOr int);
|
||||
default = null;
|
||||
description = "The account UID. If undefined, NixOS will select a free UID.";
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = with types; uniq string;
|
||||
default = "nogroup";
|
||||
description = "The user's primary group.";
|
||||
};
|
||||
|
||||
extraGroups = mkOption {
|
||||
type = types.listOf types.string;
|
||||
default = [];
|
||||
description = "The user's auxiliary groups.";
|
||||
};
|
||||
|
||||
home = mkOption {
|
||||
type = with types; uniq string;
|
||||
default = "/var/empty";
|
||||
description = "The user's home directory.";
|
||||
};
|
||||
|
||||
shell = mkOption {
|
||||
type = with types; uniq string;
|
||||
default = "/run/current-system/sw/sbin/nologin";
|
||||
description = "The path to the user's shell.";
|
||||
};
|
||||
|
||||
createHome = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "If true, the home directory will be created automatically.";
|
||||
};
|
||||
|
||||
useDefaultShell = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "If true, the user's shell will be set to <literal>users.defaultUserShell</literal>.";
|
||||
};
|
||||
|
||||
password = mkOption {
|
||||
type = with types; uniq (nullOr string);
|
||||
default = null;
|
||||
description = "The user's password. If undefined, no password is set for the user. Warning: do not set confidential information here because this data would be readable by all. This option should only be used for public account such as guest.";
|
||||
};
|
||||
|
||||
isSystemUser = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Indicates if the user is a system user or not.";
|
||||
};
|
||||
|
||||
createUser = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "
|
||||
Indicates if the user should be created automatically as a local user.
|
||||
Set this to false if the user for instance is an LDAP user. NixOS will
|
||||
then not modify any of the basic properties for the user account.
|
||||
";
|
||||
};
|
||||
|
||||
isAlias = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "If true, the UID of this user is not required to be unique and can thus alias another user.";
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = {
|
||||
name = mkDefault name;
|
||||
uid = mkDefault (attrByPath [name] null ids.uids);
|
||||
shell = mkIf config.useDefaultShell (mkDefault users.defaultUserShell);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
groupOpts = { name, config, ... }: {
|
||||
|
||||
options = {
|
||||
|
||||
name = mkOption {
|
||||
type = with types; uniq string;
|
||||
description = "The name of the group. If undefined, the name of the attribute set will be used.";
|
||||
};
|
||||
|
||||
gid = mkOption {
|
||||
type = with types; uniq (nullOr int);
|
||||
default = null;
|
||||
description = "The GID of the group. If undefined, NixOS will select a free GID.";
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = {
|
||||
name = mkDefault name;
|
||||
gid = mkDefault (attrByPath [name] null ids.gids);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
# Note: the 'X' in front of the password is to distinguish between
|
||||
# having an empty password, and not having a password.
|
||||
serializedUser = u: "${u.name}\n${u.description}\n${if u.uid != null then toString u.uid else ""}\n${u.group}\n${toString (concatStringsSep "," u.extraGroups)}\n${u.home}\n${u.shell}\n${toString u.createHome}\n${if u.password != null then "X" + u.password else ""}\n${toString u.isSystemUser}\n${toString u.createUser}\n${toString u.isAlias}\n";
|
||||
|
||||
usersFile = pkgs.writeText "users" (
|
||||
let
|
||||
p = partition (u: u.isAlias) (attrValues config.users.extraUsers);
|
||||
in concatStrings (map serializedUser p.wrong ++ map serializedUser p.right));
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
users.extraUsers = mkOption {
|
||||
default = {};
|
||||
type = types.loaOf types.optionSet;
|
||||
example = {
|
||||
alice = {
|
||||
uid = 1234;
|
||||
description = "Alice";
|
||||
home = "/home/alice";
|
||||
createHome = true;
|
||||
group = "users";
|
||||
extraGroups = ["wheel"];
|
||||
shell = "/bin/sh";
|
||||
password = "foobar";
|
||||
};
|
||||
};
|
||||
description = ''
|
||||
Additional user accounts to be created automatically by the system.
|
||||
This can also be used to set options for root.
|
||||
'';
|
||||
options = [ userOpts ];
|
||||
};
|
||||
|
||||
users.extraGroups = mkOption {
|
||||
default = {};
|
||||
example =
|
||||
{ students.gid = 1001;
|
||||
hackers = { };
|
||||
};
|
||||
type = types.loaOf types.optionSet;
|
||||
description = ''
|
||||
Additional groups to be created automatically by the system.
|
||||
'';
|
||||
options = [ groupOpts ];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = {
|
||||
|
||||
users.extraUsers = {
|
||||
root = {
|
||||
description = "System administrator";
|
||||
home = "/root";
|
||||
shell = config.users.defaultUserShell;
|
||||
group = "root";
|
||||
};
|
||||
nobody = {
|
||||
description = "Unprivileged account (don't use!)";
|
||||
};
|
||||
};
|
||||
|
||||
users.extraGroups = {
|
||||
root = { };
|
||||
wheel = { };
|
||||
disk = { };
|
||||
kmem = { };
|
||||
tty = { };
|
||||
floppy = { };
|
||||
uucp = { };
|
||||
lp = { };
|
||||
cdrom = { };
|
||||
tape = { };
|
||||
audio = { };
|
||||
video = { };
|
||||
dialout = { };
|
||||
nogroup = { };
|
||||
users = { };
|
||||
nixbld = { };
|
||||
utmp = { };
|
||||
adm = { }; # expected by journald
|
||||
};
|
||||
|
||||
system.activationScripts.rootPasswd = stringAfter [ "etc" ]
|
||||
''
|
||||
# If there is no password file yet, create a root account with an
|
||||
# empty password.
|
||||
if ! test -e /etc/passwd; then
|
||||
rootHome=/root
|
||||
touch /etc/passwd; chmod 0644 /etc/passwd
|
||||
touch /etc/group; chmod 0644 /etc/group
|
||||
touch /etc/shadow; chmod 0600 /etc/shadow
|
||||
# Can't use useradd, since it complains that it doesn't know us
|
||||
# (bootstrap problem!).
|
||||
echo "root:x:0:0:System administrator:$rootHome:${config.users.defaultUserShell}" >> /etc/passwd
|
||||
echo "root::::::::" >> /etc/shadow
|
||||
fi
|
||||
'';
|
||||
|
||||
system.activationScripts.users = stringAfter [ "groups" ]
|
||||
''
|
||||
echo "updating users..."
|
||||
|
||||
cat ${usersFile} | while true; do
|
||||
read name || break
|
||||
read description
|
||||
read uid
|
||||
read group
|
||||
read extraGroups
|
||||
read home
|
||||
read shell
|
||||
read createHome
|
||||
read password
|
||||
read isSystemUser
|
||||
read createUser
|
||||
read isAlias
|
||||
|
||||
if [ -z "$createUser" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! curEnt=$(getent passwd "$name"); then
|
||||
useradd ''${isSystemUser:+--system} \
|
||||
--comment "$description" \
|
||||
''${uid:+--uid $uid} \
|
||||
--gid "$group" \
|
||||
--groups "$extraGroups" \
|
||||
--home "$home" \
|
||||
--shell "$shell" \
|
||||
''${createHome:+--create-home} \
|
||||
''${isAlias:+--non-unique} \
|
||||
"$name"
|
||||
if test "''${password:0:1}" = 'X'; then
|
||||
(echo "''${password:1}"; echo "''${password:1}") | ${pkgs.shadow}/bin/passwd "$name"
|
||||
fi
|
||||
else
|
||||
#echo "updating user $name..."
|
||||
oldIFS="$IFS"; IFS=:; set -- $curEnt; IFS="$oldIFS"
|
||||
prevUid=$3
|
||||
prevHome=$6
|
||||
# Don't change the home directory if it's the same to prevent
|
||||
# unnecessary warnings about logged in users.
|
||||
if test "$prevHome" = "$home"; then unset home; fi
|
||||
usermod \
|
||||
--comment "$description" \
|
||||
--gid "$group" \
|
||||
--groups "$extraGroups" \
|
||||
''${home:+--home "$home"} \
|
||||
--shell "$shell" \
|
||||
"$name"
|
||||
fi
|
||||
|
||||
done
|
||||
'';
|
||||
|
||||
system.activationScripts.groups = stringAfter [ "rootPasswd" "binsh" "etc" "var" ]
|
||||
''
|
||||
echo "updating groups..."
|
||||
|
||||
createGroup() {
|
||||
name="$1"
|
||||
gid="$2"
|
||||
|
||||
if ! curEnt=$(getent group "$name"); then
|
||||
groupadd --system \
|
||||
''${gid:+--gid $gid} \
|
||||
"$name"
|
||||
fi
|
||||
}
|
||||
|
||||
${flip concatMapStrings (attrValues config.users.extraGroups) (g: ''
|
||||
createGroup '${g.name}' '${toString g.gid}'
|
||||
'')}
|
||||
'';
|
||||
|
||||
};
|
||||
|
||||
}
|
26
nixos/modules/hardware/all-firmware.nix
Normal file
26
nixos/modules/hardware/all-firmware.nix
Normal file
@ -0,0 +1,26 @@
|
||||
{pkgs, config, ...}:
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
hardware.enableAllFirmware = pkgs.lib.mkOption {
|
||||
default = false;
|
||||
type = pkgs.lib.types.bool;
|
||||
description = ''
|
||||
Turn on this option if you want to enable all the firmware shipped with Debian/Ubuntu.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = pkgs.lib.mkIf config.hardware.enableAllFirmware {
|
||||
hardware.firmware = [ "${pkgs.firmwareLinuxNonfree}/lib/firmware" ];
|
||||
};
|
||||
|
||||
}
|
29
nixos/modules/hardware/cpu/amd-microcode.nix
Normal file
29
nixos/modules/hardware/cpu/amd-microcode.nix
Normal file
@ -0,0 +1,29 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
hardware.cpu.amd.updateMicrocode = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Update the CPU microcode for AMD processors.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf config.hardware.cpu.amd.updateMicrocode {
|
||||
hardware.firmware = [ "${pkgs.amdUcode}/lib/firmware" ];
|
||||
boot.kernelModules = [ "microcode" ];
|
||||
};
|
||||
|
||||
}
|
29
nixos/modules/hardware/cpu/intel-microcode.nix
Normal file
29
nixos/modules/hardware/cpu/intel-microcode.nix
Normal file
@ -0,0 +1,29 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
hardware.cpu.intel.updateMicrocode = mkOption {
|
||||
default = false;
|
||||
type = types.bool;
|
||||
description = ''
|
||||
Update the CPU microcode for Intel processors.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf config.hardware.cpu.intel.updateMicrocode {
|
||||
hardware.firmware = [ "${pkgs.microcodeIntel}/lib/firmware" ];
|
||||
boot.kernelModules = [ "microcode" ];
|
||||
};
|
||||
|
||||
}
|
32
nixos/modules/hardware/network/b43.nix
Normal file
32
nixos/modules/hardware/network/b43.nix
Normal file
@ -0,0 +1,32 @@
|
||||
{pkgs, config, ...}:
|
||||
|
||||
let kernelVersion = config.boot.kernelPackages.kernel.version; in
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
networking.enableB43Firmware = pkgs.lib.mkOption {
|
||||
default = false;
|
||||
type = pkgs.lib.types.bool;
|
||||
description = ''
|
||||
Turn on this option if you want firmware for the NICs supported by the b43 module.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = pkgs.lib.mkIf config.networking.enableB43Firmware {
|
||||
assertions = [ {
|
||||
assertion = builtins.lessThan 0 (builtins.compareVersions kernelVersion "3.2");
|
||||
message = "b43 firmware for kernels older than 3.2 not packaged yet!";
|
||||
} ];
|
||||
hardware.firmware = [ pkgs.b43Firmware_5_1_138 ];
|
||||
};
|
||||
|
||||
}
|
3
nixos/modules/hardware/network/broadcom-43xx.nix
Normal file
3
nixos/modules/hardware/network/broadcom-43xx.nix
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
hardware.enableAllFirmware = true;
|
||||
}
|
3
nixos/modules/hardware/network/intel-2030.nix
Normal file
3
nixos/modules/hardware/network/intel-2030.nix
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
hardware.enableAllFirmware = true;
|
||||
}
|
30
nixos/modules/hardware/network/intel-2100bg.nix
Normal file
30
nixos/modules/hardware/network/intel-2100bg.nix
Normal file
@ -0,0 +1,30 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
networking.enableIntel2100BGFirmware = pkgs.lib.mkOption {
|
||||
default = false;
|
||||
type = pkgs.lib.types.bool;
|
||||
description = ''
|
||||
Turn on this option if you want firmware for the Intel
|
||||
PRO/Wireless 2100BG to be loaded automatically. This is
|
||||
required if you want to use this device.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = pkgs.lib.mkIf config.networking.enableIntel2100BGFirmware {
|
||||
|
||||
hardware.enableAllFirmware = true;
|
||||
|
||||
};
|
||||
|
||||
}
|
30
nixos/modules/hardware/network/intel-2200bg.nix
Normal file
30
nixos/modules/hardware/network/intel-2200bg.nix
Normal file
@ -0,0 +1,30 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
networking.enableIntel2200BGFirmware = pkgs.lib.mkOption {
|
||||
default = false;
|
||||
type = pkgs.lib.types.bool;
|
||||
description = ''
|
||||
Turn on this option if you want firmware for the Intel
|
||||
PRO/Wireless 2200BG to be loaded automatically. This is
|
||||
required if you want to use this device.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = pkgs.lib.mkIf config.networking.enableIntel2200BGFirmware {
|
||||
|
||||
hardware.enableAllFirmware = true;
|
||||
|
||||
};
|
||||
|
||||
}
|
29
nixos/modules/hardware/network/intel-3945abg.nix
Normal file
29
nixos/modules/hardware/network/intel-3945abg.nix
Normal file
@ -0,0 +1,29 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
networking.enableIntel3945ABGFirmware = pkgs.lib.mkOption {
|
||||
default = false;
|
||||
type = pkgs.lib.types.bool;
|
||||
description = ''
|
||||
This option enables automatic loading of the firmware for the Intel
|
||||
PRO/Wireless 3945ABG.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = pkgs.lib.mkIf config.networking.enableIntel3945ABGFirmware {
|
||||
|
||||
hardware.enableAllFirmware = true;
|
||||
|
||||
};
|
||||
|
||||
}
|
3
nixos/modules/hardware/network/intel-4965agn.nix
Normal file
3
nixos/modules/hardware/network/intel-4965agn.nix
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
hardware.enableAllFirmware = true;
|
||||
}
|
3
nixos/modules/hardware/network/intel-5000.nix
Normal file
3
nixos/modules/hardware/network/intel-5000.nix
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
hardware.enableAllFirmware = true;
|
||||
}
|
3
nixos/modules/hardware/network/intel-5150.nix
Normal file
3
nixos/modules/hardware/network/intel-5150.nix
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
hardware.enableAllFirmware = true;
|
||||
}
|
3
nixos/modules/hardware/network/intel-6000.nix
Normal file
3
nixos/modules/hardware/network/intel-6000.nix
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
hardware.enableAllFirmware = true;
|
||||
}
|
3
nixos/modules/hardware/network/intel-6000g2a.nix
Normal file
3
nixos/modules/hardware/network/intel-6000g2a.nix
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
hardware.enableAllFirmware = true;
|
||||
}
|
3
nixos/modules/hardware/network/intel-6000g2b.nix
Normal file
3
nixos/modules/hardware/network/intel-6000g2b.nix
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
hardware.enableAllFirmware = true;
|
||||
}
|
26
nixos/modules/hardware/network/ralink.nix
Normal file
26
nixos/modules/hardware/network/ralink.nix
Normal file
@ -0,0 +1,26 @@
|
||||
{pkgs, config, ...}:
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
networking.enableRalinkFirmware = pkgs.lib.mkOption {
|
||||
default = false;
|
||||
type = pkgs.lib.types.bool;
|
||||
description = ''
|
||||
Turn on this option if you want firmware for the RT73 NIC.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = pkgs.lib.mkIf config.networking.enableRalinkFirmware {
|
||||
hardware.enableAllFirmware = true;
|
||||
};
|
||||
|
||||
}
|
26
nixos/modules/hardware/network/rtl8192c.nix
Normal file
26
nixos/modules/hardware/network/rtl8192c.nix
Normal file
@ -0,0 +1,26 @@
|
||||
{pkgs, config, ...}:
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
networking.enableRTL8192cFirmware = pkgs.lib.mkOption {
|
||||
default = false;
|
||||
type = pkgs.lib.types.bool;
|
||||
description = ''
|
||||
Turn on this option if you want firmware for the RTL8192c (and related) NICs.
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
###### implementation
|
||||
|
||||
config = pkgs.lib.mkIf config.networking.enableRTL8192cFirmware {
|
||||
hardware.enableAllFirmware = true;
|
||||
};
|
||||
|
||||
}
|
9
nixos/modules/hardware/network/smc-2632w/default.nix
Normal file
9
nixos/modules/hardware/network/smc-2632w/default.nix
Normal file
@ -0,0 +1,9 @@
|
||||
{pkgs, config, ...}:
|
||||
|
||||
{
|
||||
hardware = {
|
||||
pcmcia = {
|
||||
firmware = [ (pkgs.lib.cleanSource ./firmware) ];
|
||||
};
|
||||
};
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
vers_1 5.0, "SMC", "SMC2632W", "Version 01.02", ""
|
||||
manfid 0x0156, 0x0002
|
||||
funcid network_adapter
|
||||
cftable_entry 0x01 [default]
|
||||
Vcc Vmin 3000mV Vmax 3300mV Iavg 300mA Ipeak 300mA
|
||||
Idown 10mA
|
||||
io 0x0000-0x003f [lines=6] [16bit]
|
||||
irq mask 0xffff [level] [pulse]
|
5
nixos/modules/hardware/network/zydas-zd1211.nix
Normal file
5
nixos/modules/hardware/network/zydas-zd1211.nix
Normal file
@ -0,0 +1,5 @@
|
||||
{pkgs, config, ...}:
|
||||
|
||||
{
|
||||
hardware.firmware = [ pkgs.zd1211fw ];
|
||||
}
|
59
nixos/modules/hardware/pcmcia.nix
Normal file
59
nixos/modules/hardware/pcmcia.nix
Normal file
@ -0,0 +1,59 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
with pkgs.lib;
|
||||
|
||||
let
|
||||
|
||||
pcmciaUtils = pkgs.pcmciaUtils.passthru.function {
|
||||
inherit (config.hardware.pcmcia) firmware config;
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
|
||||
{
|
||||
###### interface
|
||||
|
||||
options = {
|
||||
|
||||
hardware.pcmcia = {
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
merge = mergeEnableOption;
|
||||
description = ''
|
||||
Enable this option to support PCMCIA card.
|
||||
'';
|
||||
};
|
||||
|
||||
firmware = mkOption {
|
||||
default = [];
|
||||
merge = mergeListOption;
|
||||
description = ''
|
||||
List of firmware used to handle specific PCMCIA card.
|
||||
'';
|
||||
};
|
||||
|
||||
config = mkOption {
|
||||
default = null;
|
||||
description = ''
|
||||
Path to the configuration file which map the memory, irq
|
||||
and ports used by the PCMCIA hardware.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
###### implementation
|
||||
|
||||
config = mkIf config.hardware.pcmcia.enable {
|
||||
|
||||
boot.kernelModules = [ "pcmcia" ];
|
||||
|
||||
services.udev.packages = [ pcmciaUtils ];
|
||||
|
||||
environment.systemPackages = [ pcmciaUtils ];
|
||||
|
||||
};
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user