From 72f79dee37db1263c99160d233227bb3156272a6 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Mon, 16 Sep 2024 13:19:50 +0200 Subject: [PATCH 1/3] Inventory: docs improvements --- clanModules/admin/README.md | 3 +- clanModules/admin/roles/default.nix | 1 - clanModules/borgbackup-static/README.md | 5 + clanModules/borgbackup/README.md | 3 +- clanModules/disk-id/README.md | 1 + clanModules/disk-id/roles/default.nix | 1 - clanModules/iwd/README.md | 1 + clanModules/iwd/roles/default.nix | 1 - clanModules/machine-id/README.md | 1 + clanModules/machine-id/roles/default.nix | 1 - clanModules/mumble/README.md | 4 +- clanModules/packages/README.md | 3 +- clanModules/packages/roles/default.nix | 1 - clanModules/single-disk/README.md | 3 +- clanModules/single-disk/roles/default.nix | 1 - clanModules/state-version/README.md | 3 +- clanModules/state-version/roles/default.nix | 1 - docs/mkdocs.yml | 3 +- docs/nix/render_options/__init__.py | 55 +++++----- docs/site/guides/add-machines.md | 50 +++++++++ docs/site/guides/index.md | 1 + docs/site/guides/inventory.md | 103 +++++-------------- lib/build-clan/module.nix | 5 +- lib/description.nix | 21 ++-- lib/inventory/build-inventory/assertions.nix | 1 + lib/inventory/build-inventory/default.nix | 72 ++++++------- lib/inventory/tests/default.nix | 31 +----- pkgs/clan-cli/clan_cli/api/modules.py | 43 +++++++- pkgs/schemas/flake-module.nix | 13 ++- 29 files changed, 237 insertions(+), 195 deletions(-) delete mode 100644 clanModules/admin/roles/default.nix delete mode 100644 clanModules/disk-id/roles/default.nix delete mode 100644 clanModules/iwd/roles/default.nix delete mode 100644 clanModules/machine-id/roles/default.nix delete mode 100644 clanModules/packages/roles/default.nix delete mode 100644 clanModules/single-disk/roles/default.nix delete mode 100644 clanModules/state-version/roles/default.nix create mode 100644 docs/site/guides/add-machines.md diff --git a/clanModules/admin/README.md b/clanModules/admin/README.md index e9cfbb04f..c48600866 100644 --- a/clanModules/admin/README.md +++ b/clanModules/admin/README.md @@ -1,4 +1,5 @@ --- description = "Convenient Administration for the Clan App" -categories = ["administration"] +categories = ["Utility"] +features = [ "inventory" ] --- diff --git a/clanModules/admin/roles/default.nix b/clanModules/admin/roles/default.nix deleted file mode 100644 index ffcd4415b..000000000 --- a/clanModules/admin/roles/default.nix +++ /dev/null @@ -1 +0,0 @@ -{ } diff --git a/clanModules/borgbackup-static/README.md b/clanModules/borgbackup-static/README.md index 2e52cfef7..a0dda99da 100644 --- a/clanModules/borgbackup-static/README.md +++ b/clanModules/borgbackup-static/README.md @@ -1,6 +1,11 @@ --- description = "Statically configure borgbackup with sane defaults." --- +!!! Danger "Deprecated" + Use [borgbackup](borgbackup.md) instead. + + Don't use borgbackup-static through [inventory](../../guides/inventory.md). + This module implements the `borgbackup` backend and implements sane defaults for backup management through `borgbackup` for members of the clan. diff --git a/clanModules/borgbackup/README.md b/clanModules/borgbackup/README.md index 8fbf0e181..ef4649210 100644 --- a/clanModules/borgbackup/README.md +++ b/clanModules/borgbackup/README.md @@ -1,6 +1,7 @@ --- description = "Efficient, deduplicating backup program with optional compression and secure encryption." -categories = ["backup"] +categories = ["System"] +features = [ "inventory" ] --- BorgBackup (short: Borg) gives you: diff --git a/clanModules/disk-id/README.md b/clanModules/disk-id/README.md index 29069f002..6ddb41e42 100644 --- a/clanModules/disk-id/README.md +++ b/clanModules/disk-id/README.md @@ -1,3 +1,4 @@ --- description = "Generates a uuid for use in disk device naming" +features = [ "inventory" ] --- diff --git a/clanModules/disk-id/roles/default.nix b/clanModules/disk-id/roles/default.nix deleted file mode 100644 index ffcd4415b..000000000 --- a/clanModules/disk-id/roles/default.nix +++ /dev/null @@ -1 +0,0 @@ -{ } diff --git a/clanModules/iwd/README.md b/clanModules/iwd/README.md index ae33274da..117a679de 100644 --- a/clanModules/iwd/README.md +++ b/clanModules/iwd/README.md @@ -1,5 +1,6 @@ --- description = "Automatically provisions wifi credentials" +features = [ "inventory" ] --- !!! Warning diff --git a/clanModules/iwd/roles/default.nix b/clanModules/iwd/roles/default.nix deleted file mode 100644 index ffcd4415b..000000000 --- a/clanModules/iwd/roles/default.nix +++ /dev/null @@ -1 +0,0 @@ -{ } diff --git a/clanModules/machine-id/README.md b/clanModules/machine-id/README.md index f07b8fb4b..226b69738 100644 --- a/clanModules/machine-id/README.md +++ b/clanModules/machine-id/README.md @@ -1,3 +1,4 @@ --- description = "Sets the /etc/machine-id and exposes it as a nix option" +features = [ "inventory" ] --- diff --git a/clanModules/machine-id/roles/default.nix b/clanModules/machine-id/roles/default.nix deleted file mode 100644 index ffcd4415b..000000000 --- a/clanModules/machine-id/roles/default.nix +++ /dev/null @@ -1 +0,0 @@ -{ } diff --git a/clanModules/mumble/README.md b/clanModules/mumble/README.md index 38b62f239..552a9e2d1 100644 --- a/clanModules/mumble/README.md +++ b/clanModules/mumble/README.md @@ -1,6 +1,6 @@ --- description = "Open Source, Low Latency, High Quality Voice Chat." -categories = ["chat", "voice"] +categories = ["Audio", "Social"] --- The mumble clan module gives you: @@ -10,5 +10,5 @@ The mumble clan module gives you: - Backed by a large and active open-source community. This all set up in a way that allows peer-to-peer hosting. -Every machine inside the clan can be a host for mumble, +Every machine inside the clan can be a host for mumble, and thus it doesn't matter who in the network is online - as long as two people are online they are able to chat with each other. diff --git a/clanModules/packages/README.md b/clanModules/packages/README.md index 9512a2801..0bff44396 100644 --- a/clanModules/packages/README.md +++ b/clanModules/packages/README.md @@ -1,4 +1,5 @@ --- description = "Define package sets from nixpkgs and install them on one or more machines" -categories = ["packages"] +categories = ["System"] +features = [ "inventory" ] --- diff --git a/clanModules/packages/roles/default.nix b/clanModules/packages/roles/default.nix deleted file mode 100644 index ffcd4415b..000000000 --- a/clanModules/packages/roles/default.nix +++ /dev/null @@ -1 +0,0 @@ -{ } diff --git a/clanModules/single-disk/README.md b/clanModules/single-disk/README.md index 9aa6e4f98..163ce6360 100644 --- a/clanModules/single-disk/README.md +++ b/clanModules/single-disk/README.md @@ -1,6 +1,7 @@ --- description = "Configures partitioning of the main disk" -categories = ["disk-layout"] +categories = ["System"] +features = [ "inventory" ] --- # Primary Disk Layout diff --git a/clanModules/single-disk/roles/default.nix b/clanModules/single-disk/roles/default.nix deleted file mode 100644 index ffcd4415b..000000000 --- a/clanModules/single-disk/roles/default.nix +++ /dev/null @@ -1 +0,0 @@ -{ } diff --git a/clanModules/state-version/README.md b/clanModules/state-version/README.md index 84d85844c..e40476e5e 100644 --- a/clanModules/state-version/README.md +++ b/clanModules/state-version/README.md @@ -1,12 +1,13 @@ --- description = "Automatically generate the state version of the nixos installation." +features = [ "inventory" ] --- This module generates the `system.stateVersion` of the nixos installation automatically. Options: [system.stateVersion](https://search.nixos.org/options?channel=unstable&show=system.stateVersion&from=0&size=50&sort=relevance&type=packages&query=stateVersion) -Migration: +Migration: If you are already setting `system.stateVersion`, then import the module and then either let the automatic generation happen, or trigger the generation manually for the machine. The module will take the specified version, if one is already supplied through the config. To manually generate the version for a specified machine run: diff --git a/clanModules/state-version/roles/default.nix b/clanModules/state-version/roles/default.nix deleted file mode 100644 index ffcd4415b..000000000 --- a/clanModules/state-version/roles/default.nix +++ /dev/null @@ -1 +0,0 @@ -{ } diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 33303f627..b83d45a8f 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -51,10 +51,12 @@ nav: - Flake-parts: getting-started/flake-parts.md - Guides: - guides/index.md + - Adding Machines: guides/add-machines.md - Inventory: guides/inventory.md - Reference: - reference/index.md - Clan Modules: + - reference/clanModules/index.md - reference/clanModules/admin.md - reference/clanModules/borgbackup-static.md - reference/clanModules/borgbackup.md @@ -65,7 +67,6 @@ nav: - reference/clanModules/garage.md - reference/clanModules/golem-provider.md - reference/clanModules/heisenbridge.md - - reference/clanModules/index.md - reference/clanModules/iwd.md - reference/clanModules/localbackup.md - reference/clanModules/localsend.md diff --git a/docs/nix/render_options/__init__.py b/docs/nix/render_options/__init__.py index 3e11ae118..073a0852f 100644 --- a/docs/nix/render_options/__init__.py +++ b/docs/nix/render_options/__init__.py @@ -28,7 +28,7 @@ import os from pathlib import Path from typing import Any -from clan_cli.api.modules import Frontmatter, extract_frontmatter +from clan_cli.api.modules import Frontmatter, extract_frontmatter, get_roles from clan_cli.errors import ClanError # Get environment variables @@ -125,14 +125,15 @@ def render_option(name: str, option: dict[str, Any], level: int = 3) -> str: return res -def module_header(module_name: str) -> str: - return f"# {module_name}\n\n" +def module_header(module_name: str, has_inventory_feature: bool = False) -> str: + indicator = " 🔹" if has_inventory_feature else "" + return f"# {module_name}{indicator}\n\n" def module_usage(module_name: str) -> str: return f"""## Usage -To use this module, import it like this: +To use this module, import it like th: ```nix {{config, lib, inputs, ...}}: {{ @@ -198,25 +199,13 @@ def render_roles(roles: list[str] | None, module_name: str) -> str: if roles: roles_list = "\n".join([f" - `{r}`" for r in roles]) return f""" -???+ tip "Inventory usage" +## Inventory Roles - Predefined roles: +Predefined roles {roles_list} - Usage: - - ```{{.nix hl_lines="4"}} - buildClan {{ - inventory.services = {{ - {module_name}.instance_1 = {{ - roles.{roles[0]}.machines = [ "sara_machine" ]; - # ... - }}; - }}; - }} - ``` - +For more information, see the [inventory guide](../../../guides/inventory/). """ return "" @@ -226,6 +215,21 @@ clan_modules_descr = """Clan modules are [NixOS modules](https://wiki.nixos.org/ """ +def render_categories(categories: list[str], frontmatter: Frontmatter) -> str: + cat_info = frontmatter.categories_info + res = """
""" + for cat in categories: + color = cat_info[cat]["color"] + # description = cat_info[cat]["description"] + res += f""" +
+ {cat} +
+""" + res += "
" + return res + + def produce_clan_modules_docs() -> None: if not CLAN_MODULES: msg = f"Environment variables are not set correctly: $out={CLAN_MODULES}" @@ -270,16 +274,21 @@ def produce_clan_modules_docs() -> None: with (Path(options_file) / "share/doc/nixos/options.json").open() as f: options: dict[str, dict[str, Any]] = json.load(f) print(f"Rendering options for {module_name}...") - output = module_header(module_name) + output = module_header(module_name, "inventory" in frontmatter.features) if frontmatter.description: output += f"**{frontmatter.description}**\n\n" + + output += "## Categories\n\n" + output += render_categories(frontmatter.categories, frontmatter) + output += "\n---\n\n" + output += f"{readme_content}\n" # get_roles(str) -> list[str] | None - # roles = get_roles(CLAN_CORE_PATH / "clanModules" / module_name) - # if roles: - # output += render_roles(roles, module_name) + roles = get_roles(CLAN_CORE_PATH / "clanModules" / module_name) + if roles: + output += render_roles(roles, module_name) output += module_usage(module_name) diff --git a/docs/site/guides/add-machines.md b/docs/site/guides/add-machines.md new file mode 100644 index 000000000..1aa089ab2 --- /dev/null +++ b/docs/site/guides/add-machines.md @@ -0,0 +1,50 @@ +# How to add machines + +Clan has two general methods of adding machines + +- **Automatic**: Detects every folder in the `machines` folder. +- **Declarative**: Explicit declarations in nix. + +## Automatic register + +Every machine of the form `machines/{machineName}` will be registered automatically. + +Automatically imported: + +- [x] ``machines/{machineName}/configuration.nix` +- [x] ``machines/{machineName}/hardware-configuration.nix` +- [x] ``machines/{machineName}/facter.json` Automatically configured, for further information see [nixos-facter](../blog/posts/nixos-facter.md) + +## Manual declaration + +Machines can also be added manually under `buildClan`, `clan.*` in flake-parts or via [`inventory`](../guides/inventory.md). + +!!! Note + It is possible to use `inventory` and `buildClan` together at the same time. + +=== "**Individual Machine Configuration**" + + ```{.nix} + buildClan { + machines = { + "jon" = { + # Any valid nixos config + }; + }; + } + ``` + +=== "**Inventory Configuration**" + + ```{.nix} + buildClan { + inventory = { + machines = { + "jon" = { + # Inventory machines can set tags + tags = [ "zone1" ]; + }; + }; + }; + } + ``` diff --git a/docs/site/guides/index.md b/docs/site/guides/index.md index b4a625c49..3c3397f52 100644 --- a/docs/site/guides/index.md +++ b/docs/site/guides/index.md @@ -2,4 +2,5 @@ Detailed guides into the following subtopics: +- [Adding Machines](./add-machines.md): How to add machines. - [Inventory](./inventory.md): Configuring Services across machine boundaries diff --git a/docs/site/guides/inventory.md b/docs/site/guides/inventory.md index 1bb2f96c5..2ff2130a8 100644 --- a/docs/site/guides/inventory.md +++ b/docs/site/guides/inventory.md @@ -4,73 +4,36 @@ See [Inventory API Documentation](../reference/nix-api/inventory.md) -This guide will walk you through setting up a backup-service, where the inventory becomes useful. +This guide will walk you through setting up a backup service, where the inventory becomes useful. -## Prerequisites Meta (optional) +!!! example "Experimental status" + The inventory implementation is not considered stable yet. + We are actively soliciting feedback from users. -Metadata about the clan, will be displayed upfront in the upcomming clan-app, make sure to choose a unique name. + Stabilizing the API is a priority. -Make sure to set `name` either via `inventory.meta` OR via `clan.meta`. +## Categories -```{.nix hl_lines="3-8"} -buildClan { - inventory = { - meta = { - name = "Superclan" - description = "Awesome backups and family stuff" - }; - }; -} -``` +
+ +
+ Light Coral +
+ +
+ Baby Blue +
+
-## How to add machines +## Prerequisites -Every machine of the form `machines/{machineName}/configuration.nix` will be registered automatically. - -Machines can also be manually added under `inventory.machines` OR via `buildClan` directly. - -!!! Note - It doesn't matter where the machine gets introduced to buildClan - All delarations are valid, duplications are merged. - - However the clan-app (UI) will create machines in the inventory, because it cannot create arbitrary nix code or nixos configs. - -In the following example `backup_server` is one machine - it may specify parts of its configuration in different places. - -```{.nix hl_lines="3-5 12-20"} -buildClan { - machines = { - "backup_server" = { - # Any valid nixos config - }; - "jon" = { - # Any valid nixos config - }; - }; - inventory = { - machines = { - "backup_server" = { - # Don't include any nixos config here. - # See the Inventory API Docs for the available attributes. - }; - "jon" = { - # Same as above - }; - }; - }; -} -``` +- [x] [Add machines](./add-machines.md) to your clan. ## Services -### Available clanModules +The inventory defines `services`. Membership of `machines` is defined via roles exclusively. -Currently the inventory interface is implemented by the following clanModules - -- [borgbackup](../reference/clanModules/borgbackup.md) -- [packages](../reference/clanModules/packages.md) -- [single-disk](../reference/clanModules/single-disk.md) - -See the respective module documentation for available roles. +See the each [module documentation](../reference/clanModules/index.md) for available roles. !!! Note It is possible to use any [clanModule](../reference/clanModules/index.md) in the inventory and add machines via @@ -95,21 +58,12 @@ Each service can still be customized and configured according to the modules opt See also: [Multiple Service Instances](#multiple-service-instances) - ```{.nix hl_lines="14-17"} + ```{.nix hl_lines="6-7"} buildClan { inventory = { - machines = { - "backup_server" = { - # Don't include any nixos config here - # See inventory.Machines for available options - }; - "jon" = { - # Don't include any nixos config here - # See inventory.Machines for available options - }; - }; services = { borgbackup.instance_1 = { + # Machines can be added here. roles.client.machines = [ "jon" ]; roles.server.machines = [ "backup_server" ]; }; @@ -120,24 +74,23 @@ Each service can still be customized and configured according to the modules opt ### Scaling the Backup -It is possible to add services to multiple machines via tags. The service instance gets added in the specified role. In this case `role = "client"` +The inventory allows machines to set Tags + +It is possible to add services to multiple machines via tags as shown !!! Example "Tags Example" - ```{.nix hl_lines="9 12 17"} + ```{.nix hl_lines="5 8 14"} buildClan { inventory = { machines = { - "backup_server" = { - # Don't include any nixos config here - # See inventory.Machines for available options - }; "jon" = { tags = [ "backup" ]; }; "sara" = { tags = [ "backup" ]; }; + # ... }; services = { borgbackup.instance_1 = { @@ -172,7 +125,7 @@ It is possible to add services to multiple machines via tags. The service instan roles.client.machines = [ "jon" ]; roles.server.machines = [ "backup_server" ]; }; - borgbackup.instance_1 = { + borgbackup.instance_2 = { roles.client.machines = [ "backup_server" ]; roles.server.machines = [ "backup_backup_server" ]; }; diff --git a/lib/build-clan/module.nix b/lib/build-clan/module.nix index b05dfdc85..9f92ca691 100644 --- a/lib/build-clan/module.nix +++ b/lib/build-clan/module.nix @@ -68,7 +68,7 @@ let hwConfig = "${directory}/machines/${name}/hardware-configuration.nix"; facterModules = lib.optionals (builtins.pathExists facterJson) [ - "${clan-core.inputs.nixos-facter-modules}/modules/nixos/facter.nix" + clan-core.inputs.nixos-facter-modules.nixosModules.facter { config.facter.reportPath = facterJson; } ]; in @@ -231,6 +231,9 @@ in ) ); } + { + inventory.machines = lib.mapAttrs (_n: _: { }) config.machines; + } # Merge the meta attributes from the buildClan function { inventory.meta = if config.meta != null then config.meta else { }; } ]; diff --git a/lib/description.nix b/lib/description.nix index 4e4ad0817..e18bcded4 100644 --- a/lib/description.nix +++ b/lib/description.nix @@ -12,7 +12,7 @@ rec { in readmeContents; - getShortDescription = + getFrontmatter = modulename: let content = getReadme modulename; @@ -21,14 +21,21 @@ rec { parsed = builtins.partition ({ index, ... }: if index >= 2 then false else true) ( lib.filter ({ index, ... }: index != 0) (lib.imap0 (index: part: { inherit index part; }) parts) ); - - # Use this if the content is needed - # readmeContent = lib.concatMapStrings (v: "---" + v.part) parsed.wrong; - meta = builtins.fromTOML (builtins.head parsed.right).part; in if (builtins.length parts >= 3) then - meta.description + meta else - throw "Short description delimiter `---` not found in README.md for module ${modulename}"; + throw '' + TOML Frontmatter not found in README.md for module ${modulename} + + Please add the following to the top of your README.md: + + --- + description = "Your description here" + categories = [ "Your categories here" ] + features = [ "inventory" ] + --- + ...rest of your README.md... + ''; } diff --git a/lib/inventory/build-inventory/assertions.nix b/lib/inventory/build-inventory/assertions.nix index 102e0c851..5326f4a74 100644 --- a/lib/inventory/build-inventory/assertions.nix +++ b/lib/inventory/build-inventory/assertions.nix @@ -74,4 +74,5 @@ ) [ ] config.services; } ]; + } diff --git a/lib/inventory/build-inventory/default.nix b/lib/inventory/build-inventory/default.nix index d3d0e3ec0..003c0c654 100644 --- a/lib/inventory/build-inventory/default.nix +++ b/lib/inventory/build-inventory/default.nix @@ -37,44 +37,18 @@ let ) [ ] members.tags or [ ]); }; + checkService = + serviceName: + let + frontmatter = clan-core.lib.modules.getFrontmatter serviceName; + in + if builtins.elem "inventory" frontmatter.features or [ ] then true else false; + /* Returns a NixOS configuration for every machine in the inventory. machinesFromInventory :: Inventory -> { ${machine_name} :: NixOSConfiguration } */ - - # { client_1_machine = { tags = [ "backup" ]; }; client_2_machine = { tags = [ "backup" ]; }; not_used_machine = { }; } - getAllMachines = - inventory: - lib.foldlAttrs ( - res: serviceName: serviceConfigs: - (lib.foldlAttrs ( - res: instanceName: serviceConfig: - lib.foldlAttrs ( - res: roleName: members: - let - resolved = resolveTags { - inherit - serviceName - instanceName - roleName - inventory - members - ; - }; - in - res - // builtins.listToAttrs ( - builtins.map (m: { - name = m; - value = { }; - }) resolved.machines - ) - ) res serviceConfig.roles - ) res serviceConfigs) - ) { } (inventory.services or { }) - // inventory.machines or { }; - buildInventory = { inventory, directory }: # For every machine in the inventory, build a NixOS configuration @@ -178,7 +152,7 @@ let ] else acc2 - ) [ ] serviceConfigs) + ) [ ] (serviceConfigs)) ) [ ] inventory.services # Append each machine config ++ [ @@ -188,9 +162,35 @@ let (lib.optionalAttrs (machineConfig.deploy.targetHost or null != null) { config.clan.core.networking.targetHost = machineConfig.deploy.targetHost; }) + { + assertions = lib.foldlAttrs ( + acc: serviceName: _: + acc + ++ [ + { + assertion = checkService serviceName; + message = '' + Service ${serviceName} cannot be used in inventory. It does not declare the 'inventory' feature. + + + To allow it add the following to the beginning of the README.md of the module: + + --- + ... + + features = [ "inventory" ] + --- + + Also make sure to test the module with the 'inventory' feature enabled. + + ''; + } + ] + ) [ ] inventory.services; + } ] - ) (getAllMachines inventory); + ) inventory.machines; in { - inherit buildInventory getAllMachines; + inherit buildInventory; } diff --git a/lib/inventory/tests/default.nix b/lib/inventory/tests/default.nix index dbc60448b..e48768f8d 100644 --- a/lib/inventory/tests/default.nix +++ b/lib/inventory/tests/default.nix @@ -1,37 +1,8 @@ { inventory, clan-core, ... }: let - inherit (inventory) buildInventory getAllMachines; + inherit (inventory) buildInventory; in { - test_get_all_used_machines = { - # Test that all machines are returned - expr = getAllMachines { - machines = { - machine_3 = { - tags = [ "tag_3" ]; - }; - }; - services = { - borgbackup.instance_1 = { - roles.server.machines = [ "backup_server" ]; - roles.client.machines = [ - "client_1_machine" - "client_2_machine" - ]; - roles.client.tags = [ "tag_3" ]; - }; - }; - }; - expected = { - backup_server = { }; - client_1_machine = { }; - client_2_machine = { }; - machine_3 = { - tags = [ "tag_3" ]; - }; - }; - }; - test_inventory_empty = { # Empty inventory should return an empty module expr = buildInventory { diff --git a/pkgs/clan-cli/clan_cli/api/modules.py b/pkgs/clan-cli/clan_cli/api/modules.py index 2cf51abac..6fc9cac93 100644 --- a/pkgs/clan-cli/clan_cli/api/modules.py +++ b/pkgs/clan-cli/clan_cli/api/modules.py @@ -1,9 +1,9 @@ import json import re import tomllib -from dataclasses import dataclass +from dataclasses import dataclass, field from pathlib import Path -from typing import Any, get_args, get_type_hints +from typing import Any, TypedDict, get_args, get_type_hints from clan_cli.cmd import run_no_stdout from clan_cli.errors import ClanCmdError, ClanError @@ -15,10 +15,47 @@ from . import API from .serde import from_dict +class CategoryInfo(TypedDict): + color: str + description: str + + @dataclass class Frontmatter: description: str - categories: list[str] | None = None + categories: list[str] = field(default_factory=lambda: ["Uncategorized"]) + features: list[str] = field(default_factory=list) + + @property + def categories_info(self) -> dict[str, CategoryInfo]: + category_map: dict[str, CategoryInfo] = { + "AudioVideo": { + "color": "#AEC6CF", + "description": "Applications for presenting, creating, or processing multimedia (audio/video)", + }, + "Audio": {"color": "#CFCFC4", "description": "Audio"}, + "Video": {"color": "#FFD1DC", "description": "Video"}, + "Development": {"color": "#F49AC2", "description": "Development"}, + "Education": {"color": "#B39EB5", "description": "Education"}, + "Game": {"color": "#FFB347", "description": "Game"}, + "Graphics": {"color": "#FF6961", "description": "Graphics"}, + "Social": {"color": "#76D7C4", "description": "Social"}, + "Network": {"color": "#77DD77", "description": "Network"}, + "Office": {"color": "#85C1E9", "description": "Office"}, + "Science": {"color": "#779ECB", "description": "Science"}, + "System": {"color": "#F5C3C0", "description": "System"}, + "Settings": {"color": "#03C03C", "description": "Settings"}, + "Utility": {"color": "#B19CD9", "description": "Utility"}, + "Uncategorized": {"color": "#C23B22", "description": "Uncategorized"}, + } + + return category_map + + def __post_init__(self) -> None: + for category in self.categories: + if category not in self.categories_info: + msg = f"Invalid category: {category}" + raise ValueError(msg) def extract_frontmatter(readme_content: str, err_scope: str) -> tuple[Frontmatter, str]: diff --git a/pkgs/schemas/flake-module.nix b/pkgs/schemas/flake-module.nix index 8b81a15f7..f0e92a0f0 100644 --- a/pkgs/schemas/flake-module.nix +++ b/pkgs/schemas/flake-module.nix @@ -23,11 +23,14 @@ modulename: _: jsonLib.parseOptions (optionsFromModule modulename) { } ) clanModules; - clanModuleFunctionSchemas = lib.mapAttrsFlatten (modulename: _: { - name = modulename; - description = self.lib.modules.getShortDescription modulename; - parameters = jsonLib.parseOptions (optionsFromModule modulename) { }; - }) clanModules; + clanModuleFunctionSchemas = lib.mapAttrsFlatten ( + modulename: _: + (self.lib.modules.getFrontmatter modulename) + // { + name = modulename; + parameters = jsonLib.parseOptions (optionsFromModule modulename) { }; + } + ) clanModules; in rec { checks = { From d4123a14d27175a9a078948b16f94bace68a8f5e Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Mon, 16 Sep 2024 22:13:45 +0200 Subject: [PATCH 2/3] Inventory: fix eval tests --- lib/inventory/build-inventory/default.nix | 2 +- lib/inventory/tests/default.nix | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/inventory/build-inventory/default.nix b/lib/inventory/build-inventory/default.nix index 003c0c654..eac2416ae 100644 --- a/lib/inventory/build-inventory/default.nix +++ b/lib/inventory/build-inventory/default.nix @@ -189,7 +189,7 @@ let ) [ ] inventory.services; } ] - ) inventory.machines; + ) (inventory.machines or { }); in { inherit buildInventory; diff --git a/lib/inventory/tests/default.nix b/lib/inventory/tests/default.nix index e48768f8d..faab5eda9 100644 --- a/lib/inventory/tests/default.nix +++ b/lib/inventory/tests/default.nix @@ -88,9 +88,9 @@ in not_used_machine = builtins.length configs.not_used_machine; }; expected = { - client_1_machine = 5; - client_2_machine = 5; - not_used_machine = 2; + client_1_machine = 6; + client_2_machine = 6; + not_used_machine = 3; }; }; From 3721fc43403187f2de4bae81b0cb6e204f616266 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Mon, 16 Sep 2024 22:50:32 +0200 Subject: [PATCH 3/3] Inventory: fix doc typo --- docs/nix/render_options/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/nix/render_options/__init__.py b/docs/nix/render_options/__init__.py index 073a0852f..a5717a0dc 100644 --- a/docs/nix/render_options/__init__.py +++ b/docs/nix/render_options/__init__.py @@ -205,7 +205,7 @@ Predefined roles {roles_list} -For more information, see the [inventory guide](../../../guides/inventory/). +For more information, see the [inventory guide](../../guides/inventory.md). """ return ""