diff --git a/clanModules/borgbackup/default.nix b/clanModules/borgbackup/default.nix index c5f61b3c..b46624be 100644 --- a/clanModules/borgbackup/default.nix +++ b/clanModules/borgbackup/default.nix @@ -45,6 +45,13 @@ let # Maybe load from readme.md metaInfoOption = lib.mkOption { readOnly = true; + description = '' + Meta is used to retrieve information about this module. + + - `availableRoles` is a list of roles that can be assigned via the inventory. + - `category` is used to group services in the clan marketplace. + - `description` is a short description of the service for the clan marketplace. + ''; default = { description = "Borgbackup is a backup program. Optionally, it supports compression and authenticated encryption."; availableRoles = roles; diff --git a/docs/nix/scripts/renderOptions.py b/docs/nix/scripts/renderOptions.py index 096fbe32..909d6108 100644 --- a/docs/nix/scripts/renderOptions.py +++ b/docs/nix/scripts/renderOptions.py @@ -78,7 +78,9 @@ def render_option(name: str, option: dict[str, Any], level: int = 3) -> str: res = f""" {"#" * level} {sanitize(name)} -{"Readonly" if read_only else ""} + +{"**Readonly**" if read_only else ""} + {option.get("description", "No description available.")} **Type**: `{option["type"]}` @@ -190,6 +192,35 @@ def produce_clan_core_docs() -> None: of.write(output) +def render_meta(meta: dict[str, Any], module_name: str) -> str: + roles = meta.get("availableRoles", None) + + if roles: + roles_list = "\n".join([f" - `{r}`" for r in roles]) + return f""" +???+ tip "Inventory (WIP)" + + Predefined roles: + +{roles_list} + + Usage: + + ```{{.nix hl_lines="4"}} + buildClan {{ + inventory.services = {{ + {module_name}.instance_1 = {{ + roles.{roles[0]}.machines = [ "sara_machine" ]; + # ... + }}; + }}; + }} + ``` + +""" + return "" + + def produce_clan_modules_docs() -> None: if not CLAN_MODULES: raise ValueError( @@ -218,38 +249,6 @@ def produce_clan_modules_docs() -> None: meta_map: dict[str, Any] = json.load(f) print(meta_map) - def render_meta(meta: dict[str, Any], module_name: str) -> str: - roles = meta.get("availableRoles", None) - - if roles: - roles_list = "\n".join([f" - `{r}`" for r in roles]) - return f""" -???+ tip "Inventory (WIP)" - - Predefined roles: - -{roles_list} - - Usage: - - ```{{.nix hl_lines="4"}} - buildClan {{ - inventory.services = {{ - {module_name}.instance_1 = {{ - roles.{roles[0]}.machines = [ "sara_machine" ]; - # ... - }}; - }}; - }} - ``` - -""" - return """ -???+ example "Inventory (WIP)" - This module does not support the inventory yet. - - """ - # {'borgbackup': '/nix/store/hi17dwgy7963ddd4ijh81fv0c9sbh8sw-options.json', ... } for module_name, options_file in links.items(): with open(Path(options_file) / "share/doc/nixos/options.json") as f: @@ -262,7 +261,8 @@ def produce_clan_modules_docs() -> None: # Add meta information: # - Inventory implementation status - output += render_meta(meta_map.get(module_name, {}), module_name) + if meta_map.get(module_name, None): + output += render_meta(meta_map.get(module_name, {}), module_name) output += module_usage(module_name) diff --git a/lib/build-clan/default.nix b/lib/build-clan/default.nix index 8861c3f8..0425930a 100644 --- a/lib/build-clan/default.nix +++ b/lib/build-clan/default.nix @@ -70,6 +70,8 @@ let } ) machines; } + # Will be deprecated + # {machines = lib.mapAttrs (n: _: {}) machinesDirs;} # Deprecated interface (if clanName != null then { meta.name = clanName; } else { }) @@ -83,6 +85,25 @@ let # { ${machineName} :: Config } serviceConfigs = buildInventory mergedInventory; + # machinesDirs = lib.optionalAttrs (builtins.pathExists "${directory}/machines") ( + # builtins.readDir (directory + /machines) + # ); + + machineSettings = + machineName: + # CLAN_MACHINE_SETTINGS_FILE allows to override the settings file temporarily + # This is useful for doing a dry-run before writing changes into the settings.json + # Using CLAN_MACHINE_SETTINGS_FILE requires passing --impure to nix eval + if builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE" != "" then + builtins.fromJSON (builtins.readFile (builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE")) + else + lib.optionalAttrs (builtins.pathExists "${directory}/machines/${machineName}/settings.json") ( + builtins.fromJSON (builtins.readFile (directory + /machines/${machineName}/settings.json)) + ); + + machineImports = + machineSettings: map (module: clan-core.clanModules.${module}) (machineSettings.clanImports or [ ]); + deprecationWarnings = [ (lib.warnIf ( clanName != null @@ -99,35 +120,40 @@ let extraConfig ? { }, }: nixpkgs.lib.nixosSystem { - modules = [ - clan-core.nixosModules.clanCore - extraConfig - (machines.${name} or { }) - # Inherit the inventory assertions ? - { inherit (mergedInventory) assertions; } - { imports = serviceConfigs.${name} or { }; } - ( - { - # Settings - clan.core.clanDir = directory; - # Inherited from clan wide settings - clan.core.clanName = meta.name or clanName; - clan.core.clanIcon = meta.icon or clanIcon; + modules = + let + settings = machineSettings name; + in + (machineImports settings) + ++ [ + clan-core.nixosModules.clanCore + extraConfig + (machines.${name} or { }) + # Inherit the inventory assertions ? + { inherit (mergedInventory) assertions; } + { imports = serviceConfigs.${name} or { }; } + ( + { + # Settings + clan.core.clanDir = directory; + # Inherited from clan wide settings + clan.core.clanName = meta.name or clanName; + clan.core.clanIcon = meta.icon or clanIcon; - # Machine specific settings - clan.core.machineName = name; - networking.hostName = lib.mkDefault name; - nixpkgs.hostPlatform = lib.mkDefault system; + # Machine specific settings + clan.core.machineName = name; + networking.hostName = lib.mkDefault name; + nixpkgs.hostPlatform = lib.mkDefault system; - # speeds up nix commands by using the nixpkgs from the host system (especially useful in VMs) - nix.registry.nixpkgs.to = { - type = "path"; - path = lib.mkDefault nixpkgs; - }; - } - // lib.optionalAttrs (pkgs != null) { nixpkgs.pkgs = lib.mkForce pkgs; } - ) - ]; + # speeds up nix commands by using the nixpkgs from the host system (especially useful in VMs) + nix.registry.nixpkgs.to = { + type = "path"; + path = lib.mkDefault nixpkgs; + }; + } + // lib.optionalAttrs (pkgs != null) { nixpkgs.pkgs = lib.mkForce pkgs; } + ) + ]; specialArgs = { inherit clan-core; } // specialArgs; diff --git a/lib/flake-module.nix b/lib/flake-module.nix index ef93467b..0785872a 100644 --- a/lib/flake-module.nix +++ b/lib/flake-module.nix @@ -5,7 +5,10 @@ ... }: { - imports = [ ./jsonschema/flake-module.nix ]; + imports = [ + ./jsonschema/flake-module.nix + ./inventory/flake-module.nix + ]; flake.lib = import ./default.nix { inherit lib inputs; inherit (inputs) nixpkgs; diff --git a/lib/inventory/_old_default.nix b/lib/inventory/_old_default.nix deleted file mode 100644 index 2ca5ac00..00000000 --- a/lib/inventory/_old_default.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ self, lib, ... }: -let - clan-core = self; -in -{ - clan = clan-core.lib.buildClan { - meta.name = "kenjis clan"; - # Should usually point to the directory of flake.nix - directory = self; - - inventory = { - services = { - borgbackup.instance_1 = { - roles.server.machines = [ "vyr_machine" ]; - roles.client.tags = [ "laptop" ]; - }; - }; - }; - - # merged with - machines = { - "vyr_machine" = { }; - "vi_machine" = { - clan.tags = [ "laptop" ]; - }; - "camina_machine" = { - clan.tags = [ "laptop" ]; - clan.meta.name = "camina"; - }; - }; - }; -} diff --git a/lib/inventory/example.nix b/lib/inventory/example.nix new file mode 100644 index 00000000..50b41792 --- /dev/null +++ b/lib/inventory/example.nix @@ -0,0 +1,38 @@ +{ self, ... }: +self.lib.buildClan { + # Name of the clan in the UI, should be unique + meta.name = "Inventory clan"; + + # Should usually point to the directory of flake.nix + directory = self; + + inventory = { + services = { + borgbackup.instance_1 = { + roles.server.machines = [ "backup_server" ]; + roles.client.tags = [ "backup" ]; + }; + }; + }; + + # merged with + machines = { + "backup_server" = { + clan.tags = [ "all" ]; + }; + "client_1_machine" = { + clan.tags = [ + "all" + "backup" + ]; + }; + "client_2_machine" = { + clan.tags = [ + "all" + "backup" + ]; + # Name of the machine in the UI + clan.meta.name = "camina"; + }; + }; +} diff --git a/lib/inventory/flake-module.nix b/lib/inventory/flake-module.nix index 11a5ce9f..8778e465 100644 --- a/lib/inventory/flake-module.nix +++ b/lib/inventory/flake-module.nix @@ -1,6 +1,5 @@ { ... }: { - # flake.inventory = import ./default.nix { inherit inputs self lib; }; perSystem = { pkgs, config, ... }: { diff --git a/templates/flake-module.nix b/templates/flake-module.nix index e1c9f774..aa1eaf39 100644 --- a/templates/flake-module.nix +++ b/templates/flake-module.nix @@ -1,4 +1,4 @@ -{ self, ... }: +{ self, inputs, ... }: { flake.templates = { new-clan = { @@ -15,4 +15,25 @@ path = ./minimal; }; }; + flake.checks.x86_64-linux.template-minimal = + let + path = self.templates.minimal.path; + initialized = inputs.nixpkgs.legacyPackages.x86_64-linux.runCommand "minimal-clan-flake" { } '' + mkdir $out + cp -r ${path}/* $out + mkdir -p $out/machines/foo + echo '{ "nixpkgs": { "hostPlatform": "x86_64-linux" } }' > $out/machines/foo/settings.json + ''; + evaled = (import "${initialized}/flake.nix").outputs { + self = evaled // { + outPath = initialized; + }; + clan-core = self; + }; + in + { + type = "derivation"; + name = "minimal-clan-flake-check"; + inherit (evaled.nixosConfigurations.foo.config.system.build.vm) drvPath outPath; + }; }