[Nix-dev] NixOS module assertions

Nicolas Pierron nicolas.b.pierron at gmail.com
Tue Mar 29 11:11:11 CEST 2011


Hi,

On Mon, Mar 28, 2011 at 17:33, Ludovic Courtès <ludo at gnu.org> wrote:
> Currently setting ‘boot.kernelPackages = linuxPackages_2_6_34;’ results
> in the oh-so-clear error message below:
>
>  value is null while an attribute set was expected
>
> The reason is that ‘linuxPackages_2_6_34’ doesn’t have the fbcondecor
> patch, and thus ‘kernelPackages.splashutils’ is null.
> ‘tty-backgrounds.nix’ then references ‘splashutils’, hence the error.

Thanks for finding this issue.

> There’s an assertion in ‘tty-backgrounds.nix’, which checks whether
> ‘splashutils’ is null.  However, that assertion is apparently not
> checked by the time ‘splashutils’ is referenced in ‘preStart’ and
> ‘postStop’.
>
> Why is that?  How should we work around it?

We should not work around it.  the "assertions" option is lazy as all
options used in NixOS, which means if you don't evaluate it it won't
break.  This is not nice and I understand that you want to work around
it.  I think, when assertions option has been added we forgot to think
about the list of option impacted by the assertion.

Taking the tty-background.nix as an example:

 config = mkIf config.services.ttyBackgrounds.enable {

   assertions = singleton
     { assertion = kernelPackages.splashutils != null;
       message = "The kernelPackages does not provide splashutils, as
required by ttyBackgrounds. " +
         "Either provide kernelPackages with splashutils, or disable
ttyBackgrounds.";
     };

   services.ttyBackgrounds.specificThemes = singleton { ... };
   environment.etc =  singleton { ... };
   jobs.ttyBackgrounds = { ... };
 };

illustrate that the assertion does not touch the value of the
configuration, but the assertion is handled later while serializing
the environment (which is hacky) which may not be related.

So the assertion should be applied to all options which may be
impacted if the assertion is not verified.  In the tty-background.nix
file, we already have a similar construct, which is the mkIf property.
 Thus, the solution to our problem is to provide a similar property
which handle assertions ;)  This would be less hacky and would avoid
such errors in the future.

 config =
  mkIf config.services.ttyBackgrounds.enable (
  mkAssert kernelPackages.splashutils != null "
    The kernelPackages does not provide splashutils, as required by
ttyBackgrounds.
    Either provide kernelPackages with splashutils, or disable ttyBackgrounds.
  " {
   services.ttyBackgrounds.specificThemes = singleton { ... };
   environment.etc =  singleton { ... };
   jobs.ttyBackgrounds = { ... };
 });

We can remark that an mkAssert property will act identically as the
mkIf property, thus we can write the mkAssert property as:

 mkAssert = assertion: message: content:
   mkIf
     (if assertion then true else throw "\nFailed assertion: ${message}")
     content;

The only disadvantage is that you won't see multiple assertions
failing at once.  On the other side, you will always see when an
assertion is failing and this implementation is cleaner.

--
Nicolas Pierron
http://www.linkedin.com/in/nicolasbpierron - http://nbp.name/



More information about the nix-dev mailing list