Docs: improve module author guide code examples, code structuring

This commit is contained in:
Johannes Kirschbauer
2024-10-09 10:28:30 +02:00
parent 2f28bbdf7a
commit 824c737055

View File

@@ -6,13 +6,17 @@ This site will guide you through authoring your first module. Explaining which c
Under construction
:fontawesome-solid-road-barrier: :fontawesome-solid-road-barrier: :fontawesome-solid-road-barrier:
!!! Note
Currently ClanModules should be contributed to the [clan-core repository](https://git.clan.lol/clan/clan-core) via a PR.
Ad-hoc loading of custom modules is not recommended / supported yet.
## Bootstrapping the `clanModule`
A ClanModule is a specific subset of a [NixOS Module](https://nix.dev/tutorials/module-system/index.html), but it has some constraints and might be used via the [Inventory](../manual/inventory.md) interface.
In fact a `ClanModule` can be thought of as a layer of abstraction on-top of NixOS and/or other ClanModules. It may configure sane defaults and provide an ergonomic interface that is easy to use and can also be used via a UI that is under development currently.
Because ClanModules should be configurable via `json` all of its interface (`options`) must be serializable.
Currently ClanModules should be contributed to the [clan-core repository](https://git.clan.lol/clan/clan-core). Ad-hoc loading of custom modules is not recommended / supported yet.
Because ClanModules should be configurable via `json`/`API` all of its interface (`options`) must be serializable.
!!! Tip
ClanModules interface can be checked by running the json schema converter as follows.
@@ -35,10 +39,11 @@ clanModules/borgbackup
```
!!! Tip
This format is strictly required for `features = [ "inventory" ]`.
Some module authors might decide to opt-out of [inventory](../manual/inventory.md) usage.
`README.md` is always required. See section [Readme](#readme) for further details.
The next step is to register the module via the `clanModules` attribute.
The `roles` folder is strictly required for `features = [ "inventory" ]`.
The clanModule must be registered via the `clanModules` attribute in `clan-core`
```nix title="clanModules/flake-module.nix"
--8<-- "clanModules/flake-module.nix:0:6"
@@ -48,7 +53,7 @@ The next step is to register the module via the `clanModules` attribute.
## Readme
The `README.md` is a required file. It MUST contain frontmatter in [`toml`](https://toml.io) format.
The `README.md` is a required file for all modules. It MUST contain frontmatter in [`toml`](https://toml.io) format.
```markdown
---
@@ -62,9 +67,11 @@ See the [frontmatter reference](#frontmatter-reference) for all supported attrib
## Roles
Each `.nix` file in the `roles` directory is added as a role to the service.
If the module declares to implement `features = [ "inventory" ]` then it MUST contain a roles directory.
Other files can be placed alongside the `.nix` files
Each `.nix` file in the `roles` directory is added as a role to the inventory service.
Other files can also be placed alongside the `.nix` files
```sh
└── roles
@@ -74,6 +81,37 @@ Other files can be placed alongside the `.nix` files
Adds the roles: `client` and `server`
??? Tip "Good to know"
Sometimes a `ClanModule` should be usable via both clan's `inventory` concept but also natively as a NixOS module.
> In the long term, we want most modules to implement support for the inventory,
> but we are also aware that there are certain low-level modules that always serve as a backend for other higher-level inventory modules.
> These modules may not want to implement inventory interfaces as they are always used directly by other modules.
This can be achieved by placing an additional `default.nix` into the root of the ClanModules directory as shown:
```sh
# ModuleA
├── README.md
├── default.nix
└── roles
└── default.nix
```
```nix title="default.nix"
{...}:{
imports = [ ./roles/default.nix ];
}
```
By utilizing this pattern the module (`moduleA`) can then be imported into any regular NixOS module via:
```nix
{...}:{
imports = [ clanModules.moduleA ];
}
```
## Organizing the ClanModule
Each `{role}.nix` is included into the machine if the machine is declared to have the role.
@@ -86,6 +124,32 @@ roles.client.machines = ["MachineA"];
Then `roles/client.nix` will be added to the machine `MachineA`.
This behavior makes it possible to split the interface and common code paths when using multiple roles.
In the concrete example of `borgbackup` this allows a `server` to declare a different interface than the corresponding `client`.
The client offers configuration option, to exclude certain local directories from being backed up:
```nix title="roles/client.nix"
# Example client interface
options.clan.borgbackup.exclude = ...
```
The server doesn't offer any configuration option. Because everything is set-up automatically.
```nix title="roles/server.nix"
# Example server interface
options.clan.borgbackup = {};
```
Assuming that there is a common code path or a common interface between `server` and `client` this can be structured as:
```nix title="roles/server.nix, roles/client.nix"
{...}: {
# ...
imports = [ ../common.nix ];
}
```
## Frontmatter Reference
`description` (**Required** `String`)
@@ -125,4 +189,6 @@ Then `roles/client.nix` will be added to the machine `MachineA`.
!!! warning "Important"
Every ClanModule, that specifies `features = [ "inventory" ]` MUST have at least one role.
Many modules use `roles/default.nix` which registers the role `default`
Many modules use `roles/default.nix` which registers the role `default`.
If you are a clan module author and your module has only one role where you cannot determine the name, then we would like you to follow the convention.