Suppose a stock NixOS module, one of whose settings is an open attrset which defaults to a large set of things. From one of the modules defining my system configuration, I want to remove one or more of the entries in the default attrset, leaving the rest of it alone. What is the preferred way to do that?
For concreteness, the attrset I’m trying to mess with is services.postfix.settings.master, and it is insufficient to clobber the value of the attribute I want gone, e.g. neither of these has the desired effect:
# error: A definition for option `services.postfix.settings.master.local'
# is not of type `submodule'
services.postfix.settings.master.local = lib.mkForce null;
# compiles fine but there's still an entry in the generated
# master.cf for 'local'
services.postfix.settings.master.local = lib.mkForce {};
services.postfix.settings.master = lib.mkForce {
local = {};
};
Just adding this to my config where postfix is not used, I do get an error so you’ll likely need to re-add the necessary options. It does prove that your desired effect seems to be achieved though.
error: The option `services.postfix.settings.master.local.chroot' was accessed but has no value defined. Try setting the option.
I think you may have misunderstood what I was going for.
Your suggestion clobbers the value of the ‘local’ entry of the attrset to a blank submodule, and also throws away all the other entries in the attrset (the list is quite long, in this particular case). As you saw for yourself, this completely breaks the postfix module (and would break the actual daemon as well if it got that far).
What I want is to throw away only the ‘local’ entry (make it not be present at all – not the same as setting its value to {}) and keep all the other entries, with their normal default values.
The usual way to remove a attribute from an attrset is builtins.removeAttrs, but you will get an infinite recursion error when trying to apply it on the same attrset as in services.postfix.settings.master = lib.mkForce (builtins.removeAttrs config.services.postfix.settings.master ["local"]);
One way around it would be to fork nixpkgs and remove the reference to local (lines 1128-1130 of nixos/modules/services/mail/postfix.nix). It should do the trick, but if you need the change long term, you will need to keep rebasing your branch on top of the latest changes to nixpkgs.
There is also the option of upstreaming a version of the module that permits what you want, perhaps after using it downstream like @waffle8946 suggests - you can use disabledModules to escape most of the maintenance burden.
Though typically if this isn’t possible it’s likely something you should not want, so the final option is to review your use case and think about whether you’re deep into an XY problem. I don’t know enough about postfix to do more than play rubber duck for that option, unfortunately.
Yeah, bad enough for me to have proposed an API extension to cover this case, once upon a time. If you have a current use case for it, feel free to pick it up and I’ll help out as much as I can.