Merge pull request 'Docs: init migration guide for clanServices' (#3679) from service-docs into main

Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3679
This commit is contained in:
hsjobeki
2025-05-16 14:39:22 +00:00
9 changed files with 211 additions and 149 deletions

View File

@@ -64,13 +64,12 @@ nav:
- Autoincludes: manual/adding-machines.md
- Inventory:
- Inventory: manual/inventory.md
- Services: manual/distributed-services.md
- Secure Boot: manual/secure-boot.md
- Flake-parts: manual/flake-parts.md
- Authoring:
- clan.service: authoring/clanServices/index.md
- Disk Templates: authoring/templates/disk/disko-templates.md
- clanModules: authoring/legacyModules/index.md
- clanService: guides/authoring/clanServices/index.md
- Disk Template: guides/authoring/templates/disk/disko-templates.md
- clanModule: guides/authoring/clanModules/index.md
- Contributing:
- Contribute: contributing/contribute.md
- Debugging: contributing/debugging.md

View File

@@ -9,11 +9,11 @@ This site will guide you through authoring your first module. Explaining which c
!!! Tip
External ClanModules can be ad-hoc loaded via [`clan.inventory.modules`](../../reference/nix-api/inventory.md#inventory.modules)
External ClanModules can be ad-hoc loaded via [`clan.inventory.modules`](../../../reference/nix-api/inventory.md#inventory.modules)
## 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.
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`/`API` all of its interface (`options`) must be serializable.
@@ -48,7 +48,7 @@ clanModules/borgbackup
=== "User module"
If the module should be ad-hoc loaded.
It can be made available in any project via the [`clan.inventory.modules`](../../reference/nix-api/inventory.md#inventory.modules) attribute.
It can be made available in any project via the [`clan.inventory.modules`](../../../reference/nix-api/inventory.md#inventory.modules) attribute.
```nix title="flake.nix"
# ...
@@ -89,7 +89,7 @@ description = "Module A"
This is the example module that does xyz.
```
See the [Full Frontmatter reference](../../reference/clanModules/frontmatter/index.md) further details and all supported attributes.
See the [Full Frontmatter reference](../../../reference/clanModules/frontmatter/index.md) further details and all supported attributes.
## Roles

View File

@@ -1,7 +1,7 @@
# Authoring a 'clan.service' module
!!! Tip
This is the successor format to the older [clanModules](../legacyModules/index.md)
This is the successor format to the older [clanModules](../clanModules/index.md)
While some features might still be missing we recommend to adapt this format early and give feedback.

View File

@@ -4,6 +4,8 @@ Clans `clanServices` system is a composable way to define and deploy services
This guide shows how to **instantiate** a `clanService`, explains how service definitions are structured in your inventory, and how to pick or create services from modules exposed by flakes.
The term **Multi-host-modules** was introduced previously in the [nixus repository](https://github.com/infinisil/nixus) and represents a similar concept.
---
## Overview
@@ -17,6 +19,8 @@ inventory.instances.<instance_name>
Each instance includes a reference to a **module specification** — this is how Clan knows which service module to use and where it came from.
You can reference services from any flake input, allowing you to compose services from multiple flake sources.
These operate on a strict *role-based membership model*, meaning machines are added by assigning them specific *roles*.
---
## Basic Example
@@ -32,6 +36,7 @@ inventory.instances = {
input = "clan-core"; # <-- The flake input where the service is defined
};
# Participation of the machines is defined via roles
# Right side needs to be an attribute set. Its purpose will become clear later
roles.client.machines."machine-a" = {};
roles.server.machines."backup-host" = {};
};
@@ -45,6 +50,54 @@ If you used `clan-core` as an input attribute for your flake:
inputs.clan-core.url = "git+https://git.clan.lol/clan/clan-core"
```
## Configuration Example
Each role might expose configurable options
See clan's [clanServices reference](../reference/clanServices/index.md) for available options
```nix
inventory.instances = {
borgbackup-example = {
module = {
name = "borgbackup";
input = "clan-core";
};
roles.client.machines."machine-a" = {
# 'client' -Settings of 'machine-a'
settings = {
backupFolders = [
/home
/var
];
};
# ---------------------------
};
roles.server.machines."backup-host" = {};
};
}
```
## Tags
Multiple members can be defined using tags as follows
```nix
inventory.instances = {
borgbackup-example = {
module = {
name = "borgbackup";
input = "clan-core";
};
#
# The 'all' -tag targets all machines
roles.client.tags."all" = {};
# ---------------------------
roles.server.machines."backup-host" = {};
};
}
```
## Picking a clanService
You can use services exposed by Clans core module library, `clan-core`.
@@ -55,7 +108,7 @@ You can use services exposed by Clans core module library, `clan-core`.
You can also author your own `clanService` modules.
🔗 Learn how to write your own service: [Authoring a clanService](../authoring/clanServices/index.md)
🔗 Learn how to write your own service: [Authoring a clanService](../guides/authoring/clanServices/index.md)
You might expose your service module from your flake — this makes it easy for other people to also use your module in their clan.
@@ -71,6 +124,6 @@ You might expose your service module from your flake — this makes it easy for
## Whats Next?
* [Author your own clanService →](../authoring/clanServices/index.md)
* [Author your own clanService →](../guides/authoring/clanServices/index.md)
* [Migrate from clanModules →](../guides/migrate-inventory-services.md)
<!-- TODO: * [Understand the architecture →](../explanation/clan-architecture.md) -->

View File

@@ -1,7 +1,147 @@
# How to migrate `Inventory.services`
# Migrating from using `clanModules` to `clanServices`
**Audience**: This is a guide for **people using `clanModules`**.
If you are a **module author** and need to migrate your modules please consult our **new** [clanServices authoring guide](../guides/authoring/clanServices/index.md)
## What's Changing?
Clan is transitioning from the legacy `clanModules` system to the `clanServices` system. This guide will help you migrate your service definitions from the old format (`inventory.services`) to the new format (`inventory.instances`).
| Feature | `clanModules` (Old) | `clanServices` (New) |
| ---------------- | -------------------------- | ----------------------- |
| Module Class | `"nixos"` | `"clan.service"` |
| Inventory Key | `services` | `instances` |
| Module Source | Static | Composable via flakes |
| Custom Settings | Loosely structured | Strongly typed per-role |
| Migration Status | Deprecated (to be removed) | ✅ Preferred |
---
## Before: Old `services` Definition
```nix
services = {
admin = {
simple = {
roles.default.tags = [ "all" ];
roles.default.config = {
allowedKeys = {
"key-1" = "ssh-ed25519 AAAA...0J jon@jon-os";
};
};
};
};
};
```
---
## ✅ After: New `instances` Definition with `clanServices`
```nix
instances = {
# The instance_name is arbitrary but must be unique
# We recommend to incorporate the module name in some kind to keep it clear
admin-simple = {
module = {
name = "admin";
input = "clan-core";
};
roles.default.tags."all" = {};
# Move settings either into the desired role
# In that case they effect all 'client-machines'
roles.default.settings = {
allowedKeys = {
"key-1" = "ssh-ed25519 AAAA...0J jon@jon-os";
};
};
# ----------------------------
# OR move settings into the machine
# then they affect only that single 'machine'
roles.default.machines."jon".settings = {
allowedKeys = {
"key-1" = "ssh-ed25519 AAAA...0J jon@jon-os";
};
};
};
};
```
---
## Steps to Migrate
### 1. Move `services` entries to `instances`
Check if a service that you use has been migrated [In our reference](../reference/clanServices/index.md)
In your inventory, move it from:
```nix
services = { ... };
```
to:
```nix
instances = { ... };
```
Each nested service-instance-pair becomes a flat key, like `borgbackup.simple → borgbackup-simple`.
---
### 2. Add `module.name` and `module.input`
Each instance must declare the module name and flake input it comes from:
```nix
module = {
name = "borgbackup";
input = "clan-core"; # The name of your flake input
};
```
If you used `clan-core` as an input:
```nix
inputs.clan-core.url = "github:clan/clan-core";
```
Then refer to it as `input = "clan-core"`.
---
### 3. Move role and machine config under `roles`
In the new system:
* Use `roles.<role>.machines.<hostname>.settings` for machine-specific config.
* Use `roles.<role>.settings` for role-wide config.
* Remove: `.config` as a top-level attribute is removed.
Example:
```nix
roles.default.machines."test-inventory-machine".settings = {
packages = [ "hello" ];
};
```
---
!!! Warning
* Old `clanModules` (`class = "nixos"`) are deprecated and will be removed in the near future.
* `inventory.services` is no longer recommended; use `inventory.instances` instead.
* Module authors should begin exporting service modules under the `clan.modules` attribute of their flake.
## Further reference
- [Authoring a 'clan.service' module](../authoring/clanServices/index.md)
- [Setting up `inventory.instances`](../manual/distributed-services.md)
- [Inventory Reference](../reference/nix-api/inventory.md)
* [Authoring a 'clan.service' module](../guides/authoring/clanServices/index.md)
* [ClanServices](../guides/clanServices.md)
* [Inventory Reference](../reference/nix-api/inventory.md)

View File

@@ -29,7 +29,7 @@ hide:
Create ressources that can be reused by the community.
[:octicons-arrow-right-24: Authoring guides](./authoring/legacyModules/index.md)
[:octicons-arrow-right-24: Authoring guides](./guides/authoring/clanModules/index.md)
</div>
@@ -99,8 +99,8 @@ hide:
---
The clan core nix module.
This is imported when using clan and is the basis of the extra functionality
The clan core nix module.
This is imported when using clan and is the basis of the extra functionality
that can be provided.

View File

@@ -1,130 +0,0 @@
# Setting up `inventory.instances`
In Clan *distributed services* can be declaratively deployed using the `inventory.instances` attribute
First of all it might be needed to explain what we mean by the term *distributed service*
## What is considered a distributed service?
A **distributed service** is a system where multiple machines work together to provide a certain functionality, abstracting complexity and allowing for declarative configuration and management.
A VPN service in a closed mesh network is a good example of a distributed service — each machine needs to know the addresses and cryptographic keys of the other machines in advance to establish secure, direct connections, enabling private and encrypted communication without relying on a central server.
The term **Multi-host-service-abstractions** was introduced previously in the [nixus repository](https://github.com/infinisil/nixus) and represents a similar concept.
## How to use such a Service in Clan?
In clan everyone can provide services via modules. Those modules must be [`clan.service` modules](../authoring/clanServices/index.md).
To use a service you need to create an instance of it via the `clan.inventory.instances` attribute:
The source of the module must be specified as a simple string.
```nix
{
inventory = {
instances = {
"my-vpn" = {
# service source
module.name = "zerotier";
# ...
};
};
};
}
```
After specifying the *service source* for an instance, the next step is to configure the service.
Services operate on a strict *role-based membership model*, meaning machines are added by assigning them specific *roles*.
The following example shows a *zerotier service* which consists of a `controller` and some `peer` machines.
```nix
{
inventory = {
instances = {
"my-vpn" = {
# service source
module.name = "zerotier";
roles.peer.machines = {
# Right side needs to be an attribute set. Its purpose will become clear later
"my-machine-name" = {};
};
roles.controller.machines = {
"some-server-name" = {};
};
};
};
};
}
```
The next step is optional for some services. It might be desired to pass some service specific settings.
Either to affect all machines of a given role, or to affect a very specific machine.
For example:
In ZeroTier, the `roles.peer.settings` could specify the allowed IP ranges.
The `roles.controller.settings` could define a how to manage dynamic IP assignments for devices that are not statically configured.
```nix
{
inventory = {
instances = {
"my-vpn" = {
# service source
module.name = "zerotier";
roles.peer.machines = {
# Right side needs to be an attribute set. Its purpose will become clear later
"my-machine-name" = {};
};
roles.peer.settings = {
# Allow all ranges
ipRanges = [ "all" ];
};
roles.controller.machines = {
"some-server-name" = {
settings = {
# Enable the dynamic IP controller feature on this machine only
dynamicIp.enable = true;
};
};
};
};
};
};
}
```
Following all the steps described will result in consistent machine configurations that can be *installed* or *updated* via the [Clan CLI](../reference/cli/index.md)
### Using `clan.modules` from other people (optional)
The following example shows how to use remote modules and configure them for use in your clan.
!!! Note
Typically you would just use the `import` builtin. But we wanted to provide a json-compatible interface to allow for external API integrations.
```nix title="flake.nix"
{
inputs = {
# ...
libstd.url = "github:libfoo/libfoo";
# ...
};
outputs =
inputs: flake-parts.lib.mkFlake { inherit inputs; } (
{
clan = {
inventory.instances = {
"my-foo" = {
# Imports clan.module."mod-A" from inputs.libstd
module.input = "libstd";
module.name = "mod-A";
};
};
};
}
);
}
```

View File

@@ -126,7 +126,7 @@ in
- The module MUST have at least `features = [ "inventory" ]` in the frontmatter section.
- The module MUST have a subfolder `roles` with at least one `{roleName}.nix` file.
For further information see: [Module Authoring Guide](../../authoring/clanServices/index.md).
For further information see: [Module Authoring Guide](../../guides/authoring/clanServices/index.md).
???+ example
```nix