Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NixOS - Module imports with arguments

Tags:

nixos

Let's say I have my NixOS configuration.nix set up as follows:

{config, pkgs, ...}:
{
  services.openssh.enable = true;
}

I now want to have a second file called networking.nix which sets my hostname based on an argument.

{config, pkgs, hostname, ...}:
{
  networking.hostName = hostname
}

Is this possible? How can I include the file. I already tried doing it by using imports = [ ./networking.nix { hostname = "helloworld"; } ]; but that didn't work.

Thanks.

like image 513
lschuermann Avatar asked Dec 05 '17 10:12

lschuermann


3 Answers

A 'NixOS configuration file' is simply a module that doesn't define options, so there is really no distinction. A configuration.nix file is just a module, and typically it does not define any options, so it can be written in the abbreviated form.

Defining options is the normal way for NixOS modules to pass information around, so that's the most idiomatic way to go about.

However, if you really must, for some very special reason, because you're doing very unusual things with NixOS, you can put arbitrary functions in imports. But you shouldn't, because it doesn't work well with the module system's custom error messages and potentially other aspects that rely on knowing where a module is defined. If you do so, do make sure it is an actual function. In your case, that would imply modifying the first line of networking.nix to make it a curried function:

hostname: {config, pkgs, ...}:

Not very pretty in my opinion. Although it is very explicit about what is going on, it deviates from what is to be expected of a NixOS module.

like image 79
Robert Hensing Avatar answered Nov 01 '22 12:11

Robert Hensing


I encountered this problem today and came up with a fairly simple solution recommended in the manual.

foobar.nix

{ lib, withFoo ? "bar", ... }:

# simple error checking to ensure garbage isn't passed in
assert lib.asserts.assertOneOf "withFoo" withFoo [
  "bar"
  "baz"
  # other valid choices ...
];

{
  # ...
}

configuration.nix

args@{ ... }:
{
  imports = [
    # ...
    (
      import ./foobar.nix (
        args
        // { withFoo = "baz"; }
      )
    )
    # ...
  ];
}

This is ideal for 'one off' options in your configurations.

like image 31
nrdxp Avatar answered Nov 01 '22 13:11

nrdxp


You should be able to use the _module.argsoption [1] to do that. So your configuration.nix would be like:

{config, pkgs, ...}:
{
  _module.args.hostname = "ahostname";
  services.openssh.enable = true;
}

However where the values are very simple it will probably be much easier to just set them directly, e.g. just define networking.hostname in configuration.nix. This section of the manual re. merging and priorities may be helpful also [2].


Further discussion:

The value of _module.args is indeed applied to all imported configurations (though the value will only be used in modules that directly refer to it, such as the pkgs value, the ... represents all the values that aren't referenced).

For passing arguments to modules it seems a good approach to me, but from your comments perhaps a different approach might be more suitable.

Another solution could be to flip the relationship in the imports: rather than a single common config that passes multiple different arguments instead multiple different configs import the common configuration. E.g.

$cat ./common.nix
{ services.openssh.enable = true; }
$cat ./ahostname.nix
{ imports = [ ./common.nix ]; networking.hostname = "ahostname"; }

The NixOS config in this Reddit comment looks like it uses this approach. There are quite a few other NixOS configurations that people have shared publicly online so you might find some useful ideas there. The points in the answer from Robert Hensing are very useful to bear in mind as well.

However it's hard to say what might be a better solution in your case without knowing a bit more about the context in which you want to use it. You could create a new SO question with some more information on that which might make it easier to see a more appropriate solution.

like image 6
brocking Avatar answered Nov 01 '22 13:11

brocking