175 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
		
		
			
		
	
	
			175 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			XML
		
	
	
	
	
	
| 
								 | 
							
								<chapter xmlns="http://docbook.org/ns/docbook"
							 | 
						|||
| 
								 | 
							
								        xmlns:xlink="http://www.w3.org/1999/xlink"
							 | 
						|||
| 
								 | 
							
								        xmlns:xi="http://www.w3.org/2001/XInclude"
							 | 
						|||
| 
								 | 
							
								        version="5.0"
							 | 
						|||
| 
								 | 
							
								        xml:id="sec-writing-modules">
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								<title>Writing NixOS Modules</title>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								<para>NixOS has a modular system for declarative configuration.  This
							 | 
						|||
| 
								 | 
							
								system combines multiple <emphasis>modules</emphasis> to produce the
							 | 
						|||
| 
								 | 
							
								full system configuration.  One of the modules that constitute the
							 | 
						|||
| 
								 | 
							
								configuration is <filename>/etc/nixos/configuration.nix</filename>.
							 | 
						|||
| 
								 | 
							
								Most of the others live in the <link
							 | 
						|||
| 
								 | 
							
								xlink:href="https://github.com/NixOS/nixpkgs/tree/master/nixos/modules"><filename>nixos/modules</filename></link>
							 | 
						|||
| 
								 | 
							
								subdirectory of the Nixpkgs tree.</para>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								<para>Each NixOS module is a file that handles one logical aspect of
							 | 
						|||
| 
								 | 
							
								the configuration, such as a specific kind of hardware, a service, or
							 | 
						|||
| 
								 | 
							
								network settings.  A module configuration does not have to handle
							 | 
						|||
| 
								 | 
							
								everything from scratch; it can use the functionality provided by
							 | 
						|||
| 
								 | 
							
								other modules for its implementation.  Thus a module can
							 | 
						|||
| 
								 | 
							
								<emphasis>declare</emphasis> options that can be used by other
							 | 
						|||
| 
								 | 
							
								modules, and conversely can <emphasis>define</emphasis> options
							 | 
						|||
| 
								 | 
							
								provided by other modules in its own implementation.  For example, the
							 | 
						|||
| 
								 | 
							
								module <link
							 | 
						|||
| 
								 | 
							
								xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/security/pam.nix"><filename>pam.nix</filename></link>
							 | 
						|||
| 
								 | 
							
								declares the option <option>security.pam.services</option> that allows
							 | 
						|||
| 
								 | 
							
								other modules (e.g. <link
							 | 
						|||
| 
								 | 
							
								xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/ssh/sshd.nix"><filename>sshd.nix</filename></link>)
							 | 
						|||
| 
								 | 
							
								to define PAM services; and it defines the option
							 | 
						|||
| 
								 | 
							
								<option>environment.etc</option> (declared by <link
							 | 
						|||
| 
								 | 
							
								xlink:href="https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/system/etc/etc.nix"><filename>etc.nix</filename></link>)
							 | 
						|||
| 
								 | 
							
								to cause files to be created in
							 | 
						|||
| 
								 | 
							
								<filename>/etc/pam.d</filename>.</para>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								<para xml:id="para-module-syn">In <xref
							 | 
						|||
| 
								 | 
							
								linkend="sec-configuration-syntax"/>, we saw the following structure
							 | 
						|||
| 
								 | 
							
								of NixOS modules:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								<programlisting>
							 | 
						|||
| 
								 | 
							
								{ config, pkgs, ... }:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								{ <replaceable>option definitions</replaceable>
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								</programlisting>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								This is actually an <emphasis>abbreviated</emphasis> form of module
							 | 
						|||
| 
								 | 
							
								that only defines options, but does not declare any.  The structure of
							 | 
						|||
| 
								 | 
							
								full NixOS modules is shown in <xref linkend='ex-module-syntax' />.</para>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								<example xml:id='ex-module-syntax'><title>Structure of NixOS Modules</title>
							 | 
						|||
| 
								 | 
							
								<programlisting>
							 | 
						|||
| 
								 | 
							
								{ config, pkgs, ... }: <co xml:id='module-syntax-1' />
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								  imports =
							 | 
						|||
| 
								 | 
							
								    [ <replaceable>paths of other modules</replaceable> <co xml:id='module-syntax-2' />
							 | 
						|||
| 
								 | 
							
								    ];
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								  options = {
							 | 
						|||
| 
								 | 
							
								    <replaceable>option declarations</replaceable> <co xml:id='module-syntax-3' />
							 | 
						|||
| 
								 | 
							
								  };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								  config = {
							 | 
						|||
| 
								 | 
							
								    <replaceable>option definitions</replaceable> <co xml:id='module-syntax-4' />
							 | 
						|||
| 
								 | 
							
								  };
							 | 
						|||
| 
								 | 
							
								}</programlisting>
							 | 
						|||
| 
								 | 
							
								</example>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								<para>The meaning of each part is as follows.
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								<calloutlist>
							 | 
						|||
| 
								 | 
							
								  <callout arearefs='module-syntax-1'>
							 | 
						|||
| 
								 | 
							
								    <para>This line makes the current Nix expression a function.  The
							 | 
						|||
| 
								 | 
							
								    variable <varname>pkgs</varname> contains Nixpkgs, while
							 | 
						|||
| 
								 | 
							
								    <varname>config</varname> contains the full system configuration.
							 | 
						|||
| 
								 | 
							
								    This line can be omitted if there is no reference to
							 | 
						|||
| 
								 | 
							
								    <varname>pkgs</varname> and <varname>config</varname> inside the
							 | 
						|||
| 
								 | 
							
								    module.</para>
							 | 
						|||
| 
								 | 
							
								  </callout>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								  <callout arearefs='module-syntax-2'>
							 | 
						|||
| 
								 | 
							
								    <para>This list enumerates the paths to other NixOS modules that
							 | 
						|||
| 
								 | 
							
								    should be included in the evaluation of the system configuration.
							 | 
						|||
| 
								 | 
							
								    A default set of modules is defined in the file
							 | 
						|||
| 
								 | 
							
								    <filename>modules/module-list.nix</filename>.  These don't need to
							 | 
						|||
| 
								 | 
							
								    be added in the import list.</para>
							 | 
						|||
| 
								 | 
							
								  </callout>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								  <callout arearefs='module-syntax-3'>
							 | 
						|||
| 
								 | 
							
								    <para>The attribute <varname>options</varname> is a nested set of
							 | 
						|||
| 
								 | 
							
								    <emphasis>option declarations</emphasis> (described below).</para>
							 | 
						|||
| 
								 | 
							
								  </callout>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								  <callout arearefs='module-syntax-4'>
							 | 
						|||
| 
								 | 
							
								    <para>The attribute <varname>config</varname> is a nested set of
							 | 
						|||
| 
								 | 
							
								    <emphasis>option definitions</emphasis> (also described
							 | 
						|||
| 
								 | 
							
								    below).</para>
							 | 
						|||
| 
								 | 
							
								  </callout>
							 | 
						|||
| 
								 | 
							
								</calloutlist>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								</para>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								<para><xref linkend='locate-example' /> shows a module that handles
							 | 
						|||
| 
								 | 
							
								the regular update of the “locate” database, an index of all files in
							 | 
						|||
| 
								 | 
							
								the file system.  This module declares two options that can be defined
							 | 
						|||
| 
								 | 
							
								by other modules (typically the user’s
							 | 
						|||
| 
								 | 
							
								<filename>configuration.nix</filename>):
							 | 
						|||
| 
								 | 
							
								<option>services.locate.enable</option> (whether the database should
							 | 
						|||
| 
								 | 
							
								be updated) and <option>services.locate.period</option> (when the
							 | 
						|||
| 
								 | 
							
								update should be done).  It implements its functionality by defining
							 | 
						|||
| 
								 | 
							
								two options declared by other modules:
							 | 
						|||
| 
								 | 
							
								<option>systemd.services</option> (the set of all systemd services)
							 | 
						|||
| 
								 | 
							
								and <option>services.cron.systemCronJobs</option> (the list of
							 | 
						|||
| 
								 | 
							
								commands to be executed periodically by <command>cron</command>).</para>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								<example xml:id='locate-example'><title>NixOS Module for the “locate” Service</title>
							 | 
						|||
| 
								 | 
							
								<programlisting>
							 | 
						|||
| 
								 | 
							
								{ config, lib, pkgs, ... }:
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								with lib;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								let locatedb = "/var/cache/locatedb"; in
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
								  options = {
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    services.locate = {
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								      enable = mkOption {
							 | 
						|||
| 
								 | 
							
								        type = types.bool;
							 | 
						|||
| 
								 | 
							
								        default = false;
							 | 
						|||
| 
								 | 
							
								        description = ''
							 | 
						|||
| 
								 | 
							
								          If enabled, NixOS will periodically update the database of
							 | 
						|||
| 
								 | 
							
								          files used by the <command>locate</command> command.
							 | 
						|||
| 
								 | 
							
								        '';
							 | 
						|||
| 
								 | 
							
								      };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								      period = mkOption {
							 | 
						|||
| 
								 | 
							
								        type = types.str;
							 | 
						|||
| 
								 | 
							
								        default = "15 02 * * *";
							 | 
						|||
| 
								 | 
							
								        description = ''
							 | 
						|||
| 
								 | 
							
								          This option defines (in the format used by cron) when the
							 | 
						|||
| 
								 | 
							
								          locate database is updated.  The default is to update at
							 | 
						|||
| 
								 | 
							
								          02:15 at night every day.
							 | 
						|||
| 
								 | 
							
								        '';
							 | 
						|||
| 
								 | 
							
								      };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								  };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								  config = {
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    systemd.services.update-locatedb =
							 | 
						|||
| 
								 | 
							
								      { description = "Update Locate Database";
							 | 
						|||
| 
								 | 
							
								        path  = [ pkgs.su ];
							 | 
						|||
| 
								 | 
							
								        script =
							 | 
						|||
| 
								 | 
							
								          ''
							 | 
						|||
| 
								 | 
							
								            mkdir -m 0755 -p $(dirname ${locatedb})
							 | 
						|||
| 
								 | 
							
								            exec updatedb --localuser=nobody --output=${locatedb} --prunepaths='/tmp /var/tmp /media /run'
							 | 
						|||
| 
								 | 
							
								          '';
							 | 
						|||
| 
								 | 
							
								      };
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    services.cron.systemCronJobs = optional config.services.locate.enable
							 | 
						|||
| 
								 | 
							
								      "${config.services.locate.period} root ${config.systemd.package}/bin/systemctl start update-locatedb.service";
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								  };
							 | 
						|||
| 
								 | 
							
								}</programlisting>
							 | 
						|||
| 
								 | 
							
								</example>
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								<xi:include href="option-declarations.xml" />
							 | 
						|||
| 
								 | 
							
								<xi:include href="option-def.xml" />
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								</chapter>
							 |