I’m using terranix (I don’t think this is terranix specific) to create a module that spawns resources. I have an option that is something like:
{config, lib, ...}:
options = {
talos.clusters = lib.mkOption {
default = {};
type = lib.types.attrsOf (lib.types.submodule {
options = {
enable = lib.mkEnableOption "Enable a cluster";
loadbalancer = lib.mkOption {
default = { enable = false; };
type = lib.types.submodule {
options.enable = lib.mkEnableOption "Enable the loadbalancer";
};
};
# ... and many, many more options
};
});
};
};
config = { /* ... below */ };
}
So I have to iterate over each cluster and pull in lots of options into config blocks that end up looking like this:
config = lib.mkMerge [
{
resource.digitalocean_loadbalancer =
let directives = lib.map (cluster: { ... }) (lib.attrValues config.talos.clusters)
in collapseList directives # a utility function that turns a list of objects into a single object
}
];
This works, but its unwieldy. For one I have to collapse a list myself into a single object, for another thing the clusters get deep, each cluster may have applications with plugins etc and so the mapping function has to deal with everything all at once. Furthermore other blocks often reference each other for dependency management, so I find myself iterating over the same lists over and over for slightly different purposes. I thought it would be really nice to just map over each cluster one at a time and then let nix merge all the blocks back together.
config = lib.mkMerge (
lib.map
(cluster: { resource.digitalocean_loadbalancer = {}; })
(lib.attrValues config.talos.clusters)
);
All I have to do is supply a list of objects with the right shape, right? But attempting to iterate over a config option in any way, shape, or form this causes the following error:
error: infinite recursion encountered
at /nix/store/m68ikm8045fj7ys7qvgr608z9l70hh1k-source/lib/modules.nix:245:34:
244| (regularModules ++ [ internalModule ])
245| ({ inherit lib options config specialArgs; } // specialArgs);
| ^
246| in mergeModules prefix (reverseList collected);
I don’t understand why I can’t construct a list of objects for mkMerge to merge back together. It seems like there must be some magic going on in there that I don’t understand.