Manual: Clarify NixOS modules.
svn path=/nixos/trunk/; revision=27070
This commit is contained in:
parent
4aa86107fd
commit
1c69051ba8
@ -7,42 +7,209 @@
|
||||
NixOS.</para>
|
||||
|
||||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section>
|
||||
|
||||
<title>Extending NixOS</title>
|
||||
|
||||
<para>A unique syntax is used to express all system, hardware, computer and
|
||||
service configurations. This syntax helps for reading and writing new
|
||||
configuration files. It is coming with some extra strategies defined in
|
||||
NixPkgs which are used to merge and evaluate all configuration files.</para>
|
||||
<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 configuration file is the same as your own computer
|
||||
configuration.</para>
|
||||
<para>A module is a file which handles one specific part of the
|
||||
configuration. This part of the configuration could correspond to an
|
||||
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>
|
||||
|
||||
<example xml:id='conf-syntax'><title>Usual configuration file</title>
|
||||
<!-- 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, modulesPath, pkgs, ...}: <co xml:id='conf-syntax-1' />
|
||||
{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>, <varname>mkAlways</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. <varname>mkAlways</varname>
|
||||
is used to ignore all the <varname>mkIf</varname>
|
||||
and <varname>mkAssert</varname> which have been made
|
||||
previously. <varname>mkAlways</varname> and <varname>mkAssert</varname>
|
||||
are often used together to set an option value and to ensure that it has
|
||||
not been masked by another one.</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
|
||||
inherit (pkgs.lib) mkOption mkIf mkThenElse types; <co xml:id='conf-syntax-2' />
|
||||
|
||||
cfg = config.services.locate; <co xml:id='conf-syntax-4' />
|
||||
cfg = config.services.locate;
|
||||
locatedb = "/var/cache/locatedb";
|
||||
logfile = "/var/log/updatedb";
|
||||
cmd = "root updatedb --localuser=nobody --output=${locatedb} > ${logfile}";
|
||||
cmd =''root updatedb --localuser=nobody --output=${locatedb} > ${logfile}'';
|
||||
|
||||
mkCheck = x:
|
||||
mkIf cfg.enable (
|
||||
mkAssert config.services.cron.enable ''
|
||||
The cron daemon is not enabled, required by services.locate.enable.
|
||||
''
|
||||
x
|
||||
)
|
||||
in
|
||||
|
||||
{
|
||||
imports = [ <co xml:id='conf-syntax-6' />
|
||||
(modulesPath + /services/scheduling/cron.nix)
|
||||
imports = [
|
||||
/etc/nixos/nixos/modules/services/scheduling/cron.nix
|
||||
];
|
||||
|
||||
options = { <co xml:id='conf-syntax-3' />
|
||||
options = {
|
||||
services.locate = {
|
||||
enable = mkOption {
|
||||
default = false;
|
||||
example = true;
|
||||
type = types.bool;
|
||||
type = with types; bool;
|
||||
description = ''
|
||||
If enabled, NixOS will periodically update the database of
|
||||
files used by the <command>locate</command> command.
|
||||
@ -51,7 +218,7 @@ in
|
||||
|
||||
period = mkOption {
|
||||
default = "15 02 * * *";
|
||||
type = types.uniq type.string;
|
||||
type = with types; uniq string;
|
||||
description = ''
|
||||
This option defines (in the format used by cron) when the
|
||||
locate database is updated.
|
||||
@ -61,165 +228,30 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable { <co xml:id='conf-syntax-5' />
|
||||
config = mkCheck {
|
||||
services.cron = {
|
||||
systemCronJobs = mkThenElse { <co xml:id='conf-syntax-7' />
|
||||
thenPart = "${cfg.period} root ${cmd}";
|
||||
elsePart = "";
|
||||
};
|
||||
enable = mkAlways cfg.enable;
|
||||
systemCronJobs = "${cfg.period} root ${cmd}";
|
||||
};
|
||||
};
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para><xref linkend='conf-syntax' /> shows the <emphasis>configuration
|
||||
file</emphasis> for the locate service which uses cron to update the
|
||||
database at some dates which can be defined by the user. This nix
|
||||
expression is coming
|
||||
from <filename>upstart-jobs/cron/locate.nix</filename>. It shows a simple
|
||||
example of a service that can be either distributed on many computer that
|
||||
are using the same configuration or to shared with the community. This
|
||||
file is divided in two with the interface and the implementation. Both
|
||||
the interface and the implementation declare a <emphasis>configuration
|
||||
set</emphasis>.
|
||||
|
||||
<calloutlist>
|
||||
|
||||
<callout arearefs='conf-syntax-1'>
|
||||
|
||||
<para>This line declares the arguments of the configuration file. You
|
||||
can omit this line if there is no reference to <varname>pkgs</varname>
|
||||
and <varname>config</varname> inside the configuration file.</para>
|
||||
|
||||
<para>The argument <varname>pkgs</varname> refers to NixPkgs and allow
|
||||
you to access all attributes contained inside it. In this
|
||||
example <varname>pkgs</varname> is used to retrieve common functions to
|
||||
ease the writing of configuration files
|
||||
like <varname>mkOption</varname>, <varname>mkIf</varname>
|
||||
and <varname>mkThenElse</varname>.</para>
|
||||
|
||||
<para>The argument <varname>config</varname> corresponds to the whole
|
||||
NixOS configuration. This is a set which is build by merging all
|
||||
configuration files imported to set up the system. Thus all options
|
||||
declared are contained inside this variable. In this
|
||||
example <varname>config</varname> is used to retrieve the status of
|
||||
the <varname>enable</varname> flag. The important point of this
|
||||
argument is that it contains either the result of the merge of different
|
||||
settings or the default value, therefore you cannot assume
|
||||
that <option>config.services.locate.enable</option> is always false
|
||||
because it may have been defined in another configuration file.</para>
|
||||
|
||||
</callout>
|
||||
|
||||
<callout arearefs='conf-syntax-2'>
|
||||
|
||||
<para>This line is used to import a functions that are useful for
|
||||
writing this configuration file.</para>
|
||||
|
||||
</callout>
|
||||
|
||||
<callout arearefs='conf-syntax-3'>
|
||||
|
||||
<para>The variable <varname>options</varname> is
|
||||
a <emphasis>configuration set</emphasis> which is only used to declare
|
||||
options with the function <varname>mkOption</varname> imported
|
||||
from <filename>pkgs/lib/default.nix</filename>. Options may contained
|
||||
any attribute but only the following have a special
|
||||
meaning: <varname>default</varname>, <varname>example</varname>,
|
||||
<varname>description</varname>, <varname>merge</varname>
|
||||
and <varname>apply</varname>.</para>
|
||||
|
||||
<para>The <varname>merge</varname> attribute is used to merge all values
|
||||
defined in all configuration files and this function return a value
|
||||
which has the same type as the default value. If the merge function is
|
||||
not defined, then a default function
|
||||
(<varname>pkgs.lib.mergeDefaultOption</varname>) is used to merge
|
||||
values. The <varname>merge</varname> attribute is a function which
|
||||
expect two arguments: the location of the option and the list of values
|
||||
which have to be merged.</para>
|
||||
|
||||
<para>The <varname>apply</varname> attribute is a function used to
|
||||
process the option. Thus the value return
|
||||
by <option>config.<replaceable>option</replaceable></option> would be
|
||||
the result of the <varname>apply</varname> function called with either
|
||||
the <varname>default</varname> value or the result of
|
||||
the <varname>merge</varname> function.</para>
|
||||
|
||||
</callout>
|
||||
|
||||
<callout arearefs='conf-syntax-4'>
|
||||
|
||||
<para>This line is a common trick used to reduce the amount of
|
||||
writing. In this case <varname>cfg</varname> is just a sugar over
|
||||
<option>config.services.locate</option></para>
|
||||
|
||||
</callout>
|
||||
|
||||
<callout arearefs='conf-syntax-5'>
|
||||
|
||||
<para>This line is used to declare a special <emphasis>IF</emphasis>
|
||||
statement. If you had put a usual <emphasis>IF</emphasis> statement
|
||||
here, with the same condition, then you will get an infinite loop. The
|
||||
reason is that your condition ask for the value of the
|
||||
option <option>config.services.locate.enable</option> but in order to
|
||||
get this value you have to evaluate all configuration sets including the
|
||||
configuration set contained inside your file.</para>
|
||||
|
||||
<para>To remove this extra complexity, <varname>mkIf</varname> has been
|
||||
introduced to get rid of possible infinite loop and to factor your
|
||||
writing.</para>
|
||||
|
||||
</callout>
|
||||
|
||||
<callout arearefs='conf-syntax-6'>
|
||||
|
||||
<para>The attribute <varname>imports</varname> contains a list of other
|
||||
module location. These modules should provide option declarations for
|
||||
the current module in order to be evaluated safely.</para>
|
||||
|
||||
<para>When a dependence on a NixOS module has to be made, then you
|
||||
should use the argument <varname>modulesPath</varname> to prefix the
|
||||
location of your NixOS repository.</para>
|
||||
|
||||
</callout>
|
||||
|
||||
<callout arearefs='conf-syntax-7'>
|
||||
|
||||
<para>The attribute <varname>config</varname>, which should not be
|
||||
confused with the argument of the same name, contains a set of option
|
||||
definitions defined by this module. When there is
|
||||
neither <varname>imports</varname> nor <varname>options</varname>, then
|
||||
this attribute set can be return without any enclosing. This feature
|
||||
allow you to write your <filename>configuration.nix</filename> as a
|
||||
module which does not contains any option declarations.</para>
|
||||
|
||||
<para>As <varname>mkIf</varname> does not need
|
||||
any <emphasis>then</emphasis> part or <emphasis>else</emphasis> part,
|
||||
then you can specify one on each option definition with the
|
||||
function <varname>mkThenElse</varname>.</para>
|
||||
|
||||
<para>To avoid a lot of <varname>mkThenElse</varname> with empty
|
||||
<emphasis>else</emphasis> part, a sugar has been added to infer the
|
||||
corresponding <emphasis>empty</emphasis>-value of your option when the
|
||||
function <varname>mkThenElse</varname> is not used.</para>
|
||||
|
||||
<para>If your <emphasis>then</emphasis> part
|
||||
and <emphasis>else</emphasis> part are identical, then you should use
|
||||
the function <varname>mkAlways</varname> to ignore the condition.</para>
|
||||
|
||||
<para>If you need to add another condition, then you can add <varname>mkIf</varname> to on
|
||||
the appropriate location. Thus the <emphasis>then</emphasis> part will
|
||||
only be used if all conditions declared with <varname>mkIf</varname>
|
||||
are satisfied.</para>
|
||||
|
||||
</callout>
|
||||
|
||||
</calloutlist>
|
||||
|
||||
</para>
|
||||
<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>
|
||||
@ -271,6 +303,8 @@ config.system.build</command>
|
||||
</section>
|
||||
|
||||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section>
|
||||
|
||||
<title>Building your own NixOS CD</title>
|
||||
@ -323,6 +357,8 @@ $ ./result/bin/nixos-install</screen>
|
||||
</section>
|
||||
|
||||
|
||||
<!--===============================================================-->
|
||||
|
||||
<section>
|
||||
|
||||
<title>Testing the <literal>initrd</literal></title>
|
||||
|
Loading…
Reference in New Issue
Block a user