diff --git a/docs/nix/flake-module.nix b/docs/nix/flake-module.nix index ec079d0a7..0efb47bbb 100644 --- a/docs/nix/flake-module.nix +++ b/docs/nix/flake-module.nix @@ -13,8 +13,14 @@ # { clanCore = «derivation JSON»; clanModules = { ${name} = «derivation JSON» }; } jsonDocs = pkgs.callPackage ./get-module-docs.nix { inherit (self) clanModules; + clan-core = self; + inherit pkgs; evalClanModules = self.lib.evalClan.evalClanModules; - modulesRolesOptions = self.lib.evalClan.evalClanModulesWithRoles self.clanModules; + modulesRolesOptions = self.lib.evalClan.evalClanModulesWithRoles { + allModules = self.clanModules; + inherit pkgs; + clan-core = self; + }; }; # Frontmatter for clanModules diff --git a/docs/nix/get-module-docs.nix b/docs/nix/get-module-docs.nix index 3f4972e85..076a7f650 100644 --- a/docs/nix/get-module-docs.nix +++ b/docs/nix/get-module-docs.nix @@ -4,6 +4,8 @@ clanModules, evalClanModules, lib, + pkgs, + clan-core, }: { # clanModules docs @@ -11,7 +13,12 @@ name: module: if builtins.pathExists (module + "/default.nix") then (nixosOptionsDoc { - options = ((evalClanModules [ module ]).options).clan.${name} or { }; + options = + ((evalClanModules { + modules = [ module ]; + inherit pkgs clan-core; + }).options + ).clan.${name} or { }; warningsAreErrors = true; }).optionsJSON else @@ -31,7 +38,12 @@ clanCore = (nixosOptionsDoc { - options = ((evalClanModules [ ]).options).clan.core or { }; + options = + ((evalClanModules { + modules = [ ]; + inherit pkgs clan-core; + }).options + ).clan.core or { }; warningsAreErrors = true; }).optionsJSON; } diff --git a/docs/site/manual/distributed-services.md b/docs/site/manual/distributed-services.md index a9c91569b..d8867e6cd 100644 --- a/docs/site/manual/distributed-services.md +++ b/docs/site/manual/distributed-services.md @@ -280,3 +280,40 @@ Next we need to define the settings and the behavior of these distinct roles. # ... } ``` + +## Using values from a NixOS machine inside the module + +!!! Example "Experimental Status" + This feature is experimental and should be used with care. + +Sometimes a settings value depends on something within a machines `config`. + +Since the `interface` is defined completely machine-agnostic this means values from a machine cannot be set in the traditional way. + +The following example shows how to create a local instance of machine specific settings. + +```nix title="someservice.nix" +{ + # Maps over all instances and produces one result per instance. + perInstance = { instanceName, extendSettings, machine, roles, ... }: { + nixosModule = { config, ... }: + let + # Create new settings with + # 'ipRanges' defaulting to 'config.network.ip.range' from this machine + # This only works if there is no 'default' already. + localSettings = extendSettings { + ipRanges = lib.mkDefault config.network.ip.range; + }; + in + { + # ... + }; + }; +} +``` + +!!! Danger + `localSettings` are a local attribute. Other machines cannot access it. + If calling extendSettings is done that doesn't change the original `settings` this means if a different machine tries to access i.e `roles.client.settings` it would *NOT* contain your changes. + + Exposing the changed settings to other machines would come with a huge performance penalty, thats why we don't want to offer it. diff --git a/lib/default.nix b/lib/default.nix index ada137e8b..fc01e3ffe 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -9,25 +9,21 @@ # 'clanLib' attribute set # Wrapped with fix, so we can depend on other clanLib functions without passing the whole flake lib.fix (clanLib: { - # TODO: - # SSome bad lib functions that depend on something in 'self'. - # We should reduce the dependency on 'self' aka the 'flake' object - # This makes it easier to test - # most of the time passing the whole flake is unnecessary + /** + Like callPackage, but doesn't try to automatically detect arguments + 'lib' and 'clanLib' are always passed, plus the additional arguments + */ callLib = file: args: import file ({ inherit lib clanLib; } // args); - evalClan = import ./inventory/eval-clan-modules { - inherit lib; - clan-core = self; - pkgs = nixpkgs.legacyPackages.x86_64-linux; - }; - buildClanModule = clanLib.callLib ./build-clan { inherit nixpkgs nix-darwin; }; - buildClan = clanLib.buildClanModule.buildClanWith { clan-core = self; }; # ------------------------------------ - # Lib functions that don't depend on 'self' + # ClanLib functions + evalClan = clanLib.callLib ./inventory/eval-clan-modules { }; + buildClanModule = clanLib.callLib ./build-clan { inherit nixpkgs nix-darwin; }; inventory = clanLib.callLib ./inventory { }; modules = clanLib.callLib ./inventory/frontmatter { }; + + # Plain imports. values = import ./introspection { inherit lib; }; jsonschema = import ./jsonschema { inherit lib; }; select = import select/default.nix; diff --git a/lib/inventory/eval-clan-modules/default.nix b/lib/inventory/eval-clan-modules/default.nix index 04354e8db..2aed71757 100644 --- a/lib/inventory/eval-clan-modules/default.nix +++ b/lib/inventory/eval-clan-modules/default.nix @@ -1,10 +1,11 @@ { - clan-core, lib, - pkgs, + clanLib, }: let baseModule = + { pkgs }: + # Module { config, ... }: { imports = (import (pkgs.path + "/nixos/modules/module-list.nix")); @@ -20,11 +21,15 @@ let # This function takes a list of module names and evaluates them # [ module ] -> { config, options, ... } evalClanModulesLegacy = - modules: + { + modules, + pkgs, + clan-core, + }: let evaled = lib.evalModules { modules = [ - baseModule + (baseModule { inherit pkgs; }) { clan.core.settings.directory = clan-core; } @@ -56,16 +61,20 @@ let } */ evalClanModulesWithRoles = - allModules: + { + allModules, + clan-core, + pkgs, + }: let res = builtins.mapAttrs ( moduleName: module: let - frontmatter = clan-core.lib.modules.getFrontmatter allModules.${moduleName} moduleName; + frontmatter = clanLib.modules.getFrontmatter allModules.${moduleName} moduleName; roles = if builtins.elem "inventory" frontmatter.features or [ ] then assert lib.isPath module; - clan-core.lib.modules.getRoles allModules moduleName + clanLib.modules.getRoles allModules moduleName else [ ]; in @@ -75,7 +84,7 @@ let value = (lib.evalModules { modules = [ - baseModule + (baseModule { inherit pkgs; }) clan-core.nixosModules.clanCore { clan.core.settings.directory = clan-core; diff --git a/lib/inventory/frontmatter/default.nix b/lib/inventory/frontmatter/default.nix index 1beeb21ac..fee0e29ed 100644 --- a/lib/inventory/frontmatter/default.nix +++ b/lib/inventory/frontmatter/default.nix @@ -9,11 +9,22 @@ let }; getModulesSchema = - modules: - lib.mapAttrs ( - _moduleName: rolesOptions: - lib.mapAttrs (_roleName: options: jsonWithoutHeader.parseOptions options { }) rolesOptions - ) (clanLib.evalClan.evalClanModulesWithRoles modules); + { + modules, + clan-core, + pkgs, + }: + lib.mapAttrs + ( + _moduleName: rolesOptions: + lib.mapAttrs (_roleName: options: jsonWithoutHeader.parseOptions options { }) rolesOptions + ) + ( + clanLib.evalClan.evalClanModulesWithRoles { + allModules = modules; + inherit pkgs clan-core; + } + ); evalFrontmatter = { diff --git a/lib/inventory/schemas/default.nix b/lib/inventory/schemas/default.nix index f6a6660a1..4ebde390e 100644 --- a/lib/inventory/schemas/default.nix +++ b/lib/inventory/schemas/default.nix @@ -6,7 +6,11 @@ }: let - modulesSchema = self.lib.modules.getModulesSchema self.clanModules; + modulesSchema = self.lib.modules.getModulesSchema { + modules = self.clanModules; + inherit pkgs; + clan-core = self; + }; jsonLib = self.lib.jsonschema { inherit includeDefaults; }; includeDefaults = true;