diff --git a/docs/site/guides/clanServices.md b/docs/site/guides/clanServices.md index 960b56a36..2dae408ae 100644 --- a/docs/site/guides/clanServices.md +++ b/docs/site/guides/clanServices.md @@ -1,16 +1,22 @@ -# Using `clanServices` +# Using the Inventory -Clan's `clanServices` system is a composable way to define and deploy services across machines. +Clan's inventory system is a composable way to define and deploy services across +machines. -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. +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. +The term **Multi-host-modules** was introduced previously in the [nixus +repository](https://github.com/infinisil/nixus) and represents a similar +concept. ---- +______________________________________________________________________ ## Overview -Services are used in `inventory.instances`, and then they attach to *roles* and *machines* — meaning you decide which machines run which part of the service. +Services are used in `inventory.instances`, and assigned to *roles* and +*machines* -- meaning you decide which machines run which part of the service. For example: @@ -18,116 +24,135 @@ For example: inventory.instances = { borgbackup = { roles.client.machines."laptop" = {}; - roles.client.machines."server1" = {}; + roles.client.machines."workstation" = {}; roles.server.machines."backup-box" = {}; }; } ``` -This says: “Run borgbackup as a *client* on my *laptop* and *server1*, and as a *server* on *backup-box*.” +This says: "Run borgbackup as a *client* on my *laptop* and *workstation*, and +as a *server* on *backup-box*". `client` and `server` are roles defined by the +`borgbackup` service. ## Module source specification -Each instance includes a reference to a **module specification** — this is how Clan knows which service module to use and where it came from. -Usually one would just use `imports` but we needd to make the `module source` configurable via Python API. -By default it is not required to specify the `module`, in which case it defaults to the preprovided services of clan-core. +Each instance includes a reference to a **module specification** -- this is how +Clan knows which service module to use and where it came from. ---- - -## Override Example +It is not required to specify the `module.input` parameter, in which case it +defaults to the pre-provided services of clan-core. In a similar fashion, the +`module.name` parameter can also be omitted, it will default to the name of the +instance. Example of instantiating a `borgbackup` service using `clan-core`: ```nix inventory.instances = { - # Instance Name: Different name for this 'borgbackup' instance - borgbackup = { - # Since this is instances."borgbackup" the whole `module = { ... }` below is equivalent and optional. - module = { - name = "borgbackup"; # <-- Name of the module (optional) - input = "clan-core"; # <-- The flake input where the service is defined (optional) - }; + + borgbackup = { # <- Instance name + + # This can be partially/fully specified, + # - If the instance name is not the name of the module + # - If the input is not clan-core + # module = { + # name = "borgbackup"; # Name of the module (optional) + # input = "clan-core"; # The flake input where the service is defined (optional) + # }; + # 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" = {}; }; } ``` -If you used `clan-core` as an input attribute for your flake: +## Module Settings + +Each role might expose configurable options. See clan's [clanServices +reference](../reference/clanServices/index.md) for all available options. + +Settings can be set in per-machine or per-role. The latter is applied to all +machines that are assigned to that role. + ```nix - # ↓ module.input = "clan-core" -inputs.clan-core.url = "https://git.clan.lol/clan/clan-core/archive/main.tar.gz"; -``` - -## Simplified Example - -If only one instance is needed for a service and the service is a clan core service, the `module` definition can be omitted. - -```nix -# Simplified way of specifying a single instance inventory.instances = { - # instance name is `borgbackup` -> clan core module `borgbackup` will be loaded. borgbackup = { - # 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" = {}; - }; -} -``` - -## 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"; - }; + # Settings for 'machine-a' roles.client.machines."machine-a" = { - # 'client' -Settings of 'machine-a' settings = { backupFolders = [ /home /var ]; }; - # --------------------------- }; - roles.server.machines."backup-host" = {}; + + # Settings for all machines of the role "server" + roles.server.settings = { + directory = "/var/lib/borgbackup"; + }; }; } ``` ## Tags -Multiple members can be defined using tags as follows +Tags can be used to assign multiple machines to a role at once. It can be thought of as a grouping mechanism. + +For example using the `all` tag for services that you want to be configured on all +your machines is a common pattern. + +The following example could be used to backup all your machines to a common +backup server ```nix inventory.instances = { - borgbackup-example = { - module = { - name = "borgbackup"; - input = "clan-core"; - }; - # - # The 'all' -tag targets all machines - roles.client.tags."all" = {}; - # --------------------------- + borgbackup = { + # "All" machines are assigned to the borgbackup 'client' role + roles.client.tags = [ "all" ]; + + # But only one specific machine (backup-host) is assigned to the 'server' role roles.server.machines."backup-host" = {}; }; } ``` +## Sharing additional Nix configuration + +Sometimes you need to add custom NixOS configuration alongside your clan +services. The `extraModules` option allows you to include additional NixOS +configuration that is applied for every machine assigned to that role. + +There are multiple valid syntaxes for specifying modules: + +```nix +inventory.instances = { + borgbackup = { + roles.client = { + # Direct module reference + extraModules = [ ../nixosModules/borgbackup.nix ]; + + # Or using self (needs to be json serializable) + # See next example, for a workaround. + extraModules = [ self.nixosModules.borgbackup ]; + + # Or inline module definition, (needs to be json compatible) + extraModules = [ + { + # Your module configuration here + # ... + # + # If the module needs to contain non-serializable expressions: + imports = [ ./path/to/non-serializable.nix ]; + } + ]; + }; + }; +} +``` + ## Picking a clanService You can use services exposed by Clan's core module library, `clan-core`. @@ -142,18 +167,19 @@ You can also author your own `clanService` modules. You might expose your service module from your flake — this makes it easy for other people to also use your module in their clan. ---- +______________________________________________________________________ ## 💡 Tips for Working with clanServices -* You can add multiple inputs to your flake (`clan-core`, `your-org-modules`, etc.) to mix and match services. -* Each service instance is isolated by its key in `inventory.instances`, allowing you to deploy multiple versions or roles of the same service type. -* Roles can target different machines or be scoped dynamically. +- You can add multiple inputs to your flake (`clan-core`, `your-org-modules`, etc.) to mix and match services. +- Each service instance is isolated by its key in `inventory.instances`, allowing to deploy multiple versions or roles of the same service type. +- Roles can target different machines or be scoped dynamically. ---- +______________________________________________________________________ ## What's Next? -* [Author your own clanService →](../guides/services/community.md) -* [Migrate from clanModules →](../guides/migrations/migrate-inventory-services.md) +- [Author your own clanService →](../guides/services/community.md) +- [Migrate from clanModules →](../guides/migrations/migrate-inventory-services.md) + diff --git a/docs/site/guides/services/community.md b/docs/site/guides/services/community.md index df86149ba..3ff012e96 100644 --- a/docs/site/guides/services/community.md +++ b/docs/site/guides/services/community.md @@ -255,11 +255,50 @@ 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. +The benefit of this approach is that downstream users can override the value of +`myClan` by using `mkForce` or other priority modifiers. + +## Example: A machine-type service + +Users often have different types of machines. These could be any classification +you like, for example "servers" and "desktops". Having such distictions, allows +reusing parts of your configuration that should be appplied to a class of +machines. Since this is such a common pattern, here is how to write such a +service. + +For this example the we have to roles: `server` and `desktop`. Additionally, we +can use the `perMachine` section to add configuration to all machines regardless +of their type. + +```nix title="machine-type.nix" +{ + _class = "clan.service"; + manifest.name = "machine-type"; + + roles.server.perInstance.nixosModule = ./server.nix; + roles.desktop.perInstance.nixosModule = ./desktop.nix; + + perMachine.nixosModule = { + # Configuration for all machines (any type) + }; +} + +``` + +In the inventory we the assign machines to a type, e.g. by using tags + +```nix title="flake.nix" +instnaces.machine-type = { + module.input = "self"; + module.name = "@pinpox/machine-type"; + roles.desktop.tags.desktop = { }; + roles.server.tags.server = { }; +}; +``` --- -## Further +## Further Reading - [Reference Documentation for Service Authors](../../reference/clanServices/clan-service-author-interface.md) - [Migration Guide from ClanModules to ClanServices](../../guides/migrations/migrate-inventory-services.md)