diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index e01f90744..ddc9e5170 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -80,7 +80,7 @@ nav: - macOS: guides/macos.md - Reference: - Overview: reference/index.md - - Clan Services: + - Services: - Overview: reference/clanServices/index.md - reference/clanServices/admin.md - reference/clanServices/auto-upgrade.md @@ -92,7 +92,8 @@ nav: - reference/clanServices/hello-world.md - reference/clanServices/wifi.md - reference/clanServices/zerotier.md - - Clan Modules: + - Interface for making Services: reference/clanServices/clan-service-author-interface.md + - Modules: - Overview: reference/clanModules/index.md - reference/clanModules/frontmatter/index.md # TODO: display the docs of the clan.service modules diff --git a/docs/nix/flake-module.nix b/docs/nix/flake-module.nix index bfba3e72b..7b7b1fb67 100644 --- a/docs/nix/flake-module.nix +++ b/docs/nix/flake-module.nix @@ -90,6 +90,7 @@ export CLAN_MODULES_VIA_ROLES=${clanModulesViaRoles} export CLAN_MODULES_VIA_SERVICE=${clanModulesViaService} export CLAN_MODULES_VIA_NIX=${clanModulesViaNix} + export CLAN_SERVICE_INTERFACE=${self'.legacyPackages.clan-service-module-interface}/share/doc/nixos/options.json # Frontmatter format for clanModules export CLAN_MODULES_FRONTMATTER_DOCS=${clanModulesFrontmatter}/share/doc/nixos/options.json diff --git a/docs/nix/render_options/__init__.py b/docs/nix/render_options/__init__.py index b66de4f13..ae80b0635 100644 --- a/docs/nix/render_options/__init__.py +++ b/docs/nix/render_options/__init__.py @@ -49,6 +49,10 @@ CLAN_MODULES_VIA_NIX = os.environ.get("CLAN_MODULES_VIA_NIX") # Some modules can be imported via inventory CLAN_MODULES_VIA_ROLES = os.environ.get("CLAN_MODULES_VIA_ROLES") +# Options how to author clan.modules +# perInstance, perMachine, ... +CLAN_SERVICE_INTERFACE = os.environ.get("CLAN_SERVICE_INTERFACE") + CLAN_MODULES_VIA_SERVICE = os.environ.get("CLAN_MODULES_VIA_SERVICE") OUT = os.environ.get("out") @@ -309,7 +313,7 @@ def produce_clan_core_docs() -> None: core_outputs[indexfile] += """!!! info "Submodules"\n""" for submodule_name, split_options in split.items(): - root = options_to_tree(split_options, debug=True) + root = options_to_tree(split_options) module = root.suboptions[0] module_type = module.info.get("type") if module_type is not None and "submodule" not in module_type: @@ -798,6 +802,44 @@ def split_options_by_root(options: dict[str, Any]) -> dict[str, dict[str, Any]]: return res +def produce_clan_service_author_docs() -> None: + if not CLAN_SERVICE_INTERFACE: + msg = f"Environment variables are not set correctly: CLAN_SERVICE_INTERFACE={CLAN_SERVICE_INTERFACE}. Expected a path to the optionsJSON" + raise ClanError(msg) + + if not OUT: + msg = f"Environment variables are not set correctly: $out={OUT}" + raise ClanError(msg) + + output = """ +This document describes the structure and configurable attributes of a `clan.service` module. + +Typically needed by module authors to define roles, behavior and metadata for distributed services. + +!!! Note + This is not a user-facing documentation, but rather meant as a reference for *module authors* + + See: [clanService Authoring Guide](../../guides/authoring/clanServices/index.md) +""" + # Inventory options are already included under the buildClan attribute + # We just omitted them in the buildClan docs, because we want a separate output for the inventory model + with Path(CLAN_SERVICE_INTERFACE).open() as f: + options: dict[str, dict[str, Any]] = json.load(f) + + options_tree = options_to_tree(options, debug=True) + # Find the inventory options + + # Render the inventory options + # This for loop excludes the root node + # for option in options_tree.suboptions: + output += options_docs_from_tree(options_tree, init_level=2) + + outfile = Path(OUT) / "clanServices/clan-service-author-interface.md" + outfile.parent.mkdir(parents=True, exist_ok=True) + with Path.open(outfile, "w") as of: + of.write(output) + + @dataclass class Option: name: str @@ -959,6 +1001,8 @@ if __name__ == "__main__": # produce_build_clan_docs() produce_inventory_docs() + produce_clan_service_author_docs() + produce_clan_modules_docs() produce_clan_service_docs() diff --git a/docs/site/guides/authoring/clanServices/index.md b/docs/site/guides/authoring/clanServices/index.md index 4cf98b193..319e29e44 100644 --- a/docs/site/guides/authoring/clanServices/index.md +++ b/docs/site/guides/authoring/clanServices/index.md @@ -8,7 +8,9 @@ ## Service Module Specification This section explains how to author a clan service module. -We discussed the initial architecture in [01-clan-service-modules](../../../decisions/01-ClanModules.md) and decided to rework the format as follows: +We discussed the initial architecture in [01-clan-service-modules](../../../decisions/01-ClanModules.md) and decided to rework the format. + +For the full specification and current state see: **[Service Author Reference](../../../reference/clanServices/clan-service-author-interface.md)** ### A Minimal module @@ -49,6 +51,8 @@ The imported module file must fulfill at least the following requirements: } ``` +For more attributes see: **[Service Author Reference](../../../reference/clanServices/clan-service-author-interface.md)** + ### Adding functionality to the module While the very minimal module is valid in itself it has no way of adding any machines to it, because it doesn't specify any roles. @@ -254,3 +258,11 @@ outputs = inputs: flake-parts.lib.mkFlake { inherit inputs; } ({self, lib, ...}: ``` The benefit of this approach is that downstream users can override the value of `myClan` by using `mkForce` or other priority modifiers. + +--- + +## Further + +- [Reference Documentation for Service Authors](../../../reference/clanServices/clan-service-author-interface.md) +- [Migration Guide from ClanModules to ClanServices](../../migrations/migrate-inventory-services.md) +- [Decision that lead to ClanServices](../../../decisions/01-ClanModules.md)