I want to make a variant of the wpa_supplicant module, which is exactly the same and inherits all configuration, except that the ExecStart of the systemd service is prefixed with ip netns exec foo (which launches the process inside a network namespace). I want the original wpa_supplicant service to continue existing, so that I can switch between them with systemctl rather than with nixos-rebuild.
Is this possible? Would it have to be in an overlay? Or can I do something along the lines of
This is probably doable, but it will hardly be elegant. Not only you will need to change ExecStart, you will also need to replace the name of the systemd service.
So I think that an easier and more reliable option would be to just copy the module file to the directory you control, change it the way you like, and import this new module.
You could add a directory for the service inside /etc/systemd/system directory named foo.service.d (if the service you want to redefine is foo.service) and add a .conf file in there with the added parameters as explained in man systemd.unit (lookup Along with a unit file foo.service, a "drop-in" directory foo.service.d/ may exist.) I think you can use the etc subtree in NixOS conf to achieve that.
The name of the systemd service doesn’t have to be changed. The best way I know of the top of my head is using including <nixpkgs/nixos/modules/services/networking/wpa_supplicant.nix> in disabledModules while importing the revised new module.
I’m pretty sure this function in <nixpkgs/lib/modules.nix> does exactly what you want:
538 # Convenient property used to transfer all definitions and their
539 # properties from one option to another. This property is useful for
540 # renaming options, and also for including properties from another module
541 # system, including sub-modules.
542 #
543 # { config, options, ... }:
544 #
545 # {
546 # # 'bar' might not always be defined in the current module-set.
547 # config.foo.enable = mkAliasDefinitions (options.bar.enable or {});
548 #
549 # # 'barbaz' has to be defined in the current module-set.
550 # config.foobar.paths = mkAliasDefinitions options.barbaz.paths;
551 # }
552 #
553 # Note, this is different than taking the value of the option and using it
554 # as a definition, as the new definition will not keep the mkOverride /
555 # mkDefault properties of the previous option.
556 #
557 mkAliasDefinitions = mkAliasAndWrapDefinitions id;
558 mkAliasAndWrapDefinitions = wrap: option:
559 mkIf (isOption option && option.isDefined) (wrap (mkMerge option.definitions));