NixOS / nixops

NixOps is a tool for deploying to NixOS machines in a network or cloud.
https://nixos.org/nixops
GNU Lesser General Public License v3.0
1.84k stars 363 forks source link

Pass inputs in addition to nodes/resources to NixOS modules when using Flake #1494

Open vincentbernat opened 2 years ago

vincentbernat commented 2 years ago

Hey!

When using flakes, it would be convenient to have access to inputs, like this is the case for nodes. Currently, we need to pass it to every module manually. There is modulesPath as an alternative for some case. When using NixOS directly, this can be done by using pkgs.lib.nixosSystem { specialArgs = { inherit inputs; }; }.

PsychoLlama commented 2 years ago

NixOS 22.05 introduced something that might help: _module.args I can't try it myself, my infrastructure is still stuck on 21.11, but I'd be curious if anyone else has success with it.

roberth commented 2 years ago

_module.args is older than specialArgs, so you can already use it. https://github.com/NixOS/nixpkgs/pull/8204

This should work

{ /* network attrset */
  defaults = { /* a NixOS module */
    _module.args.inputs = inputs;
  }
}

After https://github.com/NixOS/nixops/pull/1508, you can expose them at the network level as well

{ /* network module */
  _module.args.inputs = inputs;
}

We should consider setting inputs by default when evaluating a flake.

PsychoLlama commented 2 years ago

I got some time to try it. You were right @roberth, that works perfectly. Thanks for the tip!

scottbot95 commented 2 years ago

Using _module.args to inject inputs goes a long way, but ultimately I feel it would be insufficient. _module.args is evaluated as part of the config and thus values injected by this mechanism cannot be used in imports (since imports happen statically before evaluation of the main config value). This is precisely what specialArgs is for. Unfortunately, so far as I can tell, there is not currently a mechanism to pass specialArgs into module evaluation call.

n8henrie commented 7 months ago

Using NixOps 2.0.0-pre-fc9b55c, I'm unable to get this to work passing inputs via _module.args, I'm assuming because I'm using inputs in a function that is called as part of calculating imports (though I expected an infinite recursion error, and instead it's just not finding inputs).

The module is working fine for nixosConfigurations but fails for nixops:

{
  config,
  pkgs,
  lib,
  ...
} @ args: {
  imports = let
    defaultModulesFrom = map (input: args.inputs.${input}.nixosModules.default);
  in
    [
      ../.
      ./services
    ]
    ++ (defaultModulesFrom [
      "agenix"
      "home-manager"
    ]);
}
# flake.nix
nixopsConfigurations.default = { 
    inherit nixpkgs; 
    network.storage.legacy = {}; 
    defaults._module.args.inputs = inputs;
    myMachine = { imports = [ ./the-module-above.nix ]; ...};
};
$ nixops deploy
...
   error: attribute 'inputs' missing
       at /nix/store/bl7rfpl59r40idj093ap5bgi1dli1p44-source/modules/linux/default.nix:14:38:
           13|   imports = let
           14|     defaultModulesFrom = map (input: args.inputs.${input}.nixosModules.default);
             |                                      ^
           15|   in
error: evaluation of the deployment specification failed

I've tried putting the defaults._module.args.inputs = inputs; at a few different levels in that attrset, but I think this is correct (based on this), and none of the others worked.