mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-01-07 21:43:32 +00:00
767d80099c
Previously the .enable option was used to encode the condition as well, which lead to some oddness: - In order to encode an assertion, one had to invert it - To disable a check, one had to mkForce it By introducing a separate .check option this is solved because: - It can be used to encode assertions - Disabling is done separately with .enable option, whose default can be overridden without a mkForce
158 lines
5.1 KiB
XML
158 lines
5.1 KiB
XML
<section xmlns="http://docbook.org/ns/docbook"
|
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
|
version="5.0"
|
|
xml:id="sec-assertions">
|
|
<title>Evaluation Checks</title>
|
|
|
|
<para>
|
|
When configuration problems are detectable in a module, it is a good idea to
|
|
write a check for catching it early. Doing so can provide clear feedback to
|
|
the user and can prevent errors before the build.
|
|
</para>
|
|
|
|
<para>
|
|
Although Nix has the <literal>abort</literal> and
|
|
<literal>builtins.trace</literal>
|
|
<link xlink:href="https://nixos.org/nix/manual/#ssec-builtins">functions</link>
|
|
to perform such tasks generally, they are not ideally suited for NixOS
|
|
modules. Instead of these functions, you can declare your evaluation checks
|
|
using the NixOS module system.
|
|
</para>
|
|
|
|
<section xml:id="sec-assertions-define">
|
|
<title>Defining Checks</title>
|
|
|
|
<para>
|
|
Checks can be defined using the <xref linkend="opt-_module.checks"/> option.
|
|
Each check needs an attribute name, under which you can define a trigger
|
|
assertion using <xref linkend="opt-_module.checks._name_.check"/> and a
|
|
message using <xref linkend="opt-_module.checks._name_.message"/>.
|
|
For the message, you can add
|
|
<literal>options</literal> to the module arguments and use
|
|
<literal>${options.path.to.option}</literal> to print a context-aware string
|
|
representation of an option path. Here is an example showing how this can be
|
|
done.
|
|
</para>
|
|
|
|
<programlisting>
|
|
{ config, options, ... }: {
|
|
_module.checks.gpgSshAgent = {
|
|
check = config.programs.gnupg.agent.enableSSHSupport -> !config.programs.ssh.startAgent;
|
|
message = "If you have ${options.programs.gnupg.agent.enableSSHSupport} enabled,"
|
|
+ " you can't enable ${options.programs.ssh.startAgent} as well!";
|
|
};
|
|
|
|
_module.checks.grafanaPassword = {
|
|
check = config.services.grafana.database.password == "";
|
|
message = "The grafana password defined with ${options.services.grafana.database.password}"
|
|
+ " will be stored as plaintext in the Nix store!";
|
|
# This is a non-fatal warning
|
|
type = "warning";
|
|
};
|
|
}
|
|
</programlisting>
|
|
|
|
</section>
|
|
|
|
<section xml:id="sec-assertions-ignoring">
|
|
<title>Ignoring Checks</title>
|
|
|
|
<para>
|
|
Sometimes you can get failing checks that don't apply to your specific case
|
|
and you wish to ignore them, or at least make errors non-fatal. You can do so
|
|
for all checks defined using <xref linkend="opt-_module.checks"/> by
|
|
using the attribute name of the definition, which is conveniently printed
|
|
using <literal>[...]</literal> when the check is triggered. For above
|
|
example, the evaluation output when the checks are triggered looks as
|
|
follows:
|
|
</para>
|
|
|
|
<programlisting>
|
|
trace: warning: [grafanaPassword] The grafana password defined with
|
|
services.grafana.database.password will be stored as plaintext in the Nix store!
|
|
error: Failed checks:
|
|
- [gpgSshAgent] If you have programs.gnupg.agent.enableSSHSupport
|
|
enabled, you can't enable programs.ssh.startAgent as well!
|
|
</programlisting>
|
|
|
|
<para>
|
|
The <literal>[grafanaPassword]</literal> and <literal>[gpgSshAgent]</literal>
|
|
strings tell you that these were defined under the <literal>grafanaPassword
|
|
</literal> and <literal>gpgSshAgent</literal> attributes of
|
|
<xref linkend="opt-_module.checks"/> respectively. With this knowledge
|
|
you can adjust them to your liking:
|
|
</para>
|
|
|
|
<programlisting>
|
|
{
|
|
# Change the error into a non-fatal warning
|
|
_module.checks.gpgSshAgent.type = "warning";
|
|
|
|
# We don't care about this warning, disable it
|
|
_module.checks.grafanaPassword.enable = false;
|
|
}
|
|
</programlisting>
|
|
|
|
|
|
</section>
|
|
<section xml:id="sec-assertions-submodules">
|
|
<title>Checks in Submodules</title>
|
|
|
|
<para>
|
|
Evaluation checks can be defined within submodules in the same way. Here is an example:
|
|
</para>
|
|
|
|
<programlisting>
|
|
{ lib, ... }: {
|
|
|
|
options.myServices = lib.mkOption {
|
|
type = lib.types.attrsOf (lib.types.submodule ({ config, options, ... }: {
|
|
options.port = lib.mkOption {};
|
|
|
|
config._module.checks.portConflict = {
|
|
check = config.port != 80;
|
|
message = "Port ${toString config.port} defined using"
|
|
+ " ${options.port} is usually used for HTTP";
|
|
type = "warning";
|
|
};
|
|
}));
|
|
};
|
|
|
|
}
|
|
</programlisting>
|
|
|
|
<para>
|
|
When this check is triggered, it shows both the submodule path along with
|
|
the check attribute within that submodule, joined by a
|
|
<literal>/</literal>. Note also how <literal>${options.port}</literal>
|
|
correctly shows the context of the option.
|
|
</para>
|
|
|
|
<programlisting>
|
|
trace: warning: [myServices.foo/portConflict] Port 80 defined using
|
|
myServices.foo.port is usually used for HTTP
|
|
</programlisting>
|
|
|
|
<para>
|
|
Therefore to disable such a check, you can do so by changing the
|
|
<xref linkend="opt-_module.checks"/> option within the
|
|
<literal>myServices.foo</literal> submodule:
|
|
</para>
|
|
|
|
<programlisting>
|
|
{
|
|
myServices.foo._module.checks.portConflict.enable = false;
|
|
}
|
|
</programlisting>
|
|
|
|
<note>
|
|
<para>
|
|
Checks defined in submodules under <literal>types.listOf</literal> can't be
|
|
ignored, since there's no way to change previously defined list items.
|
|
</para>
|
|
</note>
|
|
|
|
</section>
|
|
</section>
|