Can't include variable from other file?

Why can’t I reuse a variable from another module?

I have a source file (interfaces.json) that I use as input to generate service definitions (corerad, avahi, dnsmasq…), which is working well but there’s a lot of repetition with variables between files.

Data should flow something like this: interfaces.jsoninterfaces.nixcorerad.nix

# First attempt, this is working today, but gen is redefined in 
# every service file I have
{ lib, ... }:
let
  # this line in particular gets repeated in all files
  gen = builtins.fromJSON (builtins.readFile ../interfaces.json);

  # file specific functions
  guess_prefix = (addr: "${(lib.strings.removeSuffix "1/64" addr)}/64");
  prefixAttr = (prefix: { prefix = prefix; });

  intDefs = ({ name, ipv6, advertise ? false, ... }: {
    name = name;
    advertise = advertise;
    rdnss = [{ servers = ["::"]; lifetime = "auto"; }];
    prefix = builtins.map
      (addr: prefixAttr (guess_prefix addr))
      (builtins.attrValues ipv6);
  });
in
{
  services.corerad.enable = true;
  services.corerad.settings = {
    interfaces = builtins.map intDefs gen.interfaces;
  };
}

So I then tried to create a file called interfaces.nix and define the gen variable there instead (but now calling it vars due to reaons):

{ lib, ... }:
let
  vars = builtins.fromJSON (builtins.readFile ./interfaces.json);
  interfaceNames = lib.catAttrs "name" vars.interfaces;
  ifAvahiAllowed = [ "eth0" "eth1" "eth2" ];
in {
  inherit vars;
  inherit interfaceNames;
  inherit ifAvahiAllowed;
}

Then I tried to just use the vars variable in corerad.nix:

{lib, ... }:
let
  # vars = import ../interfaces.nix {inherit lib;};                                                                                                             
  # interfaces = with vars; [interfaces];                                                                                                                       
  # vars = pkgs.callPackage ../interfaces.nix {};                                                                                                               
  # interfaces = vars.interfaces;                                                                                                                               
  # ints = with vars; [interfaces];                                                                                                                             
  # ints = (import ../interfaces.nix interfaces);                                                                                                               

  # inherit (import ../interfaces.nix) vars;                                                                                                                    

  varFile = import ../interfaces.nix;
  vars = varFile.vars;
  # vars = varFile.vars;                                                                                                                                        
  # inherit (import ../interfaces.nix) interfaces;                                                                                                              
in {
 # inherit vars;                                                                                                                                               
  services.corerad.enable = true;
  services.corerad.settings = {
    interfaces = builtins.map intDefs vars.interfaces;
  };
}

…but getting this error message:

nixos-rebuild build
building Nix...
building the system configuration...
error:
       … while calling the 'head' builtin

         at /nix/store/53j9ijd4fgwj214wfpahkvf2ym97g8qg-nixos-23.11/nixos/lib/attrsets.nix:922:11:

          921|         || pred here (elemAt values 1) (head values) then
          922|           head values
             |           ^
          923|         else

       … while evaluating the attribute 'value'

         at /nix/store/53j9ijd4fgwj214wfpahkvf2ym97g8qg-nixos-23.11/nixos/lib/modules.nix:807:9:

          806|     in warnDeprecation opt //
          807|       { value = builtins.addErrorContext "while evaluating the option `${showOption loc}':" value;
             |         ^
          808|         inherit (res.defsFinal') highestPrio;

       (stack trace truncated; use '--show-trace' to show the full trace)

       error: value is a function while a set was expected

What am I missing?

Also, this is an example of interfaces.json:

{
    "interfaces": [
	{
	    "name": "example",
	    "vid": 100,
	    "ipv4": "192.168.0.1/24",
	    "ipv6": {
		"ula": "fd0b:7c3c:2594::1/64",
		"gua": "2001:db8:3333:4444:5555:6666:7777:8888"
	    },
	    "subnet": "192.168.0.0/24",
	    "dhcp-range": "192.168.0.100-192.168.0.200",
	    "domain": "home.arpa"
	}
    ]
}

You defined interfaces.nix as a function of an attrset with one mandatory attribute, lib:

{ lib, ... }:

Try passing an attrset at the import site:

varFile = import ../interfaces.nix { inherit lib; };

If you want to reuse these values in multiple modules, you should declare them as an option and let nix pass lib when merging the modules.

2 Likes

Thank you very much!