Use mapAttrs with NixOS modules

Hello,
I am trying to set an option for all attributes of an attrset, something like

networking.interfaces = builtins.mapAttrs (n: _: { useDHCP=true; }) config.networking.interfaces;

This unfortunately fails with error: infinite recursion encountered, which is totally reasonable, but I can’t think of a different other way.

Is there any? Or how do you handle this kind of requirements?

1 Like

For your concrete use-case: I’m relatively sure that you don’t want to enable DHCP on each interface, but only on your uplink interfaces (i.e. ethernet interfaces and on e.g. a laptop wireless interfaces).
What you probably want to do is networking.useDHCP = true; (which is not deprecated anymore for scripted networking, the current default in NixOS).

When using networkd, you can work with wildcards to enable DHCP on multiple interfaces. Please note that only one network unit will be used to configure an interface though.

It’s a fairly frequent use case to want to make changes to all instances of submodules. This can be done by adding another option declaration with the same base type but your own submodule, like this:

{ lib, ... }: {
  options.networking.interfaces = lib.mkOption {
    type = lib.types.attrsOf (lib.types.submodule ({ config, ... }: {
      config.useDHCP = true;
    }));
  };
}

You can even use the config value there to condition the definitions on any value of the current submodule instance.

3 Likes

For you immediate need there is:

networking.useDHCP
    Whether to use DHCP to obtain an IP address and other configuration for all network interfaces that are not manually configured.

    Type: boolean

    Default: true

    Declared by:
    <nixpkgs/nixos/modules/tasks/network-interfaces.nix> 

Thank you all very much. I used networking.interfaces.<>.useDHCP just as an example, it was easier than explaining my use case in depth.

@Infinisil’s solution looks very promising, I’ll check that.

In the meantime, guys on Matrix uncovered to me you can pass a function to lib.submodule allowing you to set defaults based on what other options are set in this particular submodule instance, which is a handy workaround to this issue, at least when you are the module author (which is my case).

1 Like