NixOS modules: Difference between revisions
imported>Growpotkin No edit summary |
imported>Mth m Mth moved page NixOS Modules to Module |
||
(No difference)
|
Revision as of 16:07, 9 June 2019
NixOS has modules to have non-intrusive extensions. Modules are made to avoid manipulating the core of NixOS while allowing the user to separate their configuration.nix
file into multiple sub-file which are specific to a device or a service configuration. Such separation permits the creation of services which can be tested for a while before being merged in the main line of NixOS.
This page describes how you can create a module. If you want a pratical view, you should have a look into this small tutorial.
Vocabulary
- Declaration: All options which are used with the
mkOption
function are declared. Declared options should at least have adescription
attribute which contains a multiple-line text for describing the effect of the option. - Definition: All options which are set to plain values are considered as definitions. The plain value may vary depending on the expected type of the option.
- Use: All result of options which are used to compute values of other option are option usages.
- Properties: These are option definition modifiers. Properties may change the influence of an option definition in the computation of an option result.
To find all files which are defining or declaring an option, you may refer to the generated NixOS manual or to the man
page of configuration.nix
.
Syntax
Modules are declared with the following syntax:
{
imports = [
# list of path to other modules.
];
options = {
# attribute set of option declarations.
};
config = {
# attribute set of option definitions.
};
}
Another syntax exists for cases where no option declaration are necessary:
{
require = [
# list of path to other modules.
];
# attribute set of option definitions.
}
Both of the previous syntax can be refined with an attribute set argument added on top:
{config, pkgs, ...}:
{
# ...
}
The following arguments can be retrieved from this attribute set:
config
: The configuration of the entire system.options
: All option declarations refined with all definition and declaration references.pkgs
: The attribute set extracted from the Nix package collection and enhanced with thenixpkgs.config
option.modulesPath
: The location of themodule
directory of NixOS.
For more information, you should refer to NixOS sources, with more insight into nixos/lib/eval-config.nix
.
More computation or organisation can be necessary to enhance modules. In which case, you can add a let .. in ..
statement between the argument and the attribute set.
{config, pkgs, ...}:
let
# intermediate result.
in
{
# ...
}
Example Module
put into hello.nix
in the same folder as your configuration.nix
.
{ lib, pkgs, config, ... }:
with lib;
let
cfg = config.services.hello;
in {
options.services.hello = {
enable = mkEnableOption "hello service";
greeter = mkOption {
type = types.string;
default = "world";
};
};
config = lib.mkIf cfg.enable {
systemd.services.hello = {
wantedBy = [ "multi-user.target" ];
serviceConfig.ExecStart = "${pkgs.hello}/bin/hello -g'Hello, ${escapeShellArg cfg.greeter}!'";
};
};
}
Add the following to your configuration.nix
{
imports = [ ./hello.nix ];
...
services.hello = {
enable = true;
greeter = "Bob";
};
}
Advanced Use Cases
Compatibility Issues with Different Nixpkgs Versions
Module options between Nixpkgs revisions can sometimes change in incompatible ways.
For example, the option services.nginx.virtualHosts.*.port
in nixpkgs-17.03 was replaced by services.nginx.virtualHosts.*.listen
in nixpkgs-17.09. If configuration.nix has to accommodate both variants, options
can be inspected:
{ options, ... }: {
services.nginx.virtualHosts.somehost = { /* common configuration */ }
// (if builtins.hasAttr "port" (builtins.head options.services.nginx.virtualHosts.type.getSubModules).submodule.options
then { port = 8000; }
else { listen = [ { addr = "0.0.0.0"; port = 8000; } ]; });
}
Abstract imports
To import a module that's stored somewhere (but for which you have neither an absolute nor a relative path), you can use NIX_PATH elements or specialArgs
from nixos/lib/eval-config.nix
.
This is useful for e.g. pulling modules from a git repository without adding it as a channel, or if you just prefer using paths relative to a root you can change (as opposed to the current file, which could move in the future).
let
inherit (import <nixpkgs> {}) writeShellScriptBin fetchgit;
yourModules = fetchgit { ... };
in rec {
nixos = import <nixpkgs/nixos/lib/eval-config.nix> {
modules = [ ./configuration.nix ];
specialArgs.mod = name: "${yourModules}/${name}";
};
/* use nixos here, e.g. for deployment or building an image */
}
{ config, lib, pkgs, mod, ... }: {
imports = [
(mod "foo.nix")
];
...
}
More complex usages
The examples below contain:
- a child `mkOption` inherits their default from a parent `mkOption`
- reading default values from neighbouring `mkOption`(s) for conditional defaults
- passing in the config, to read the hostName from a submodule (email system)
- setting default values from attrset (email system)
- generating documentation for custom modules (outside of nixpkgs). See here
Source:
- https://github.com/nixcloud/nixcloud-webservices/blob/master/modules/services/reverse-proxy/default.nix
- https://github.com/nixcloud/nixcloud-webservices/blob/master/modules/services/reverse-proxy/options.nix
- https://github.com/nixcloud/nixcloud-webservices/blob/master/modules/services/TLS/default.nix
- https://github.com/nixcloud/nixcloud-webservices/blob/master/modules/services/email/nixcloud-email.nix#L59
(sorry, dont' have more time to make this into a nice little guide yet, but this links should be pretty good introductions into more advanced module system usages) qknight
References
Related Work
- Debian Config::Model:
target configuration upgrades by abstracting the option of the configuration. Each file is a tree structure where leaves are values defined with an interpreted type. The interpreters are defined for each meta-configuration files name *.conf. Configuration files does not seems to interact with each other to make consistent configuration. They provide an UI for editing their configuration file.