diff --git a/docs/.gitignore b/docs/.gitignore index 128ca295b..1658c2ad8 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,5 +1,6 @@ /site/reference/clan-core /site/reference/clanModules +/site/reference/nix-api/inventory.md /site/reference/cli /site/static/Roboto-Regular.ttf /site/static/FiraCode-VF.ttf \ No newline at end of file diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 8ae87c39f..8bd5d22ac 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -48,6 +48,9 @@ nav: - Mesh VPN: getting-started/mesh-vpn.md - Backup & Restore: getting-started/backups.md - Flake-parts: getting-started/flake-parts.md + - Guides: + - guides/index.md + - Inventory: guides/inventory.md - Reference: - reference/index.md - Clan Modules: diff --git a/docs/nix/default.nix b/docs/nix/default.nix index 01dae322f..914024538 100644 --- a/docs/nix/default.nix +++ b/docs/nix/default.nix @@ -2,6 +2,7 @@ pkgs, module-docs, clan-cli-docs, + inventory-api-docs, asciinema-player-js, asciinema-player-css, roboto, @@ -32,6 +33,7 @@ pkgs.stdenv.mkDerivation { mkdir -p ./site/reference/cli cp -af ${module-docs}/* ./site/reference/ cp -af ${clan-cli-docs}/* ./site/reference/cli/ + cp -af ${inventory-api-docs} ./site/reference/nix-api/inventory.md mkdir -p ./site/static/asciinema-player ln -snf ${asciinema-player-js} ./site/static/asciinema-player/asciinema-player.min.js diff --git a/docs/nix/flake-module.nix b/docs/nix/flake-module.nix index bd44e94b7..89052d53f 100644 --- a/docs/nix/flake-module.nix +++ b/docs/nix/flake-module.nix @@ -73,7 +73,7 @@ in { devShells.docs = pkgs.callPackage ./shell.nix { - inherit (self'.packages) docs clan-cli-docs; + inherit (self'.packages) docs clan-cli-docs inventory-api-docs; inherit asciinema-player-js asciinema-player-css @@ -83,7 +83,7 @@ }; packages = { docs = pkgs.python3.pkgs.callPackage ./default.nix { - inherit (self'.packages) clan-cli-docs; + inherit (self'.packages) clan-cli-docs inventory-api-docs; inherit (inputs) nixpkgs; inherit module-docs; inherit asciinema-player-js; diff --git a/docs/nix/shell.nix b/docs/nix/shell.nix index 29432d906..fd9246265 100644 --- a/docs/nix/shell.nix +++ b/docs/nix/shell.nix @@ -3,6 +3,7 @@ pkgs, module-docs, clan-cli-docs, + inventory-api-docs, asciinema-player-js, asciinema-player-css, roboto, @@ -19,6 +20,8 @@ pkgs.mkShell { mkdir -p ./site/reference/cli cp -af ${module-docs}/* ./site/reference/ cp -af ${clan-cli-docs}/* ./site/reference/cli/ + cp -af ${inventory-api-docs} ./site/reference/nix-api/inventory.md + chmod +w ./site/reference/* echo "Generated API documentation in './site/reference/' " diff --git a/docs/site/guides/index.md b/docs/site/guides/index.md new file mode 100644 index 000000000..b4a625c49 --- /dev/null +++ b/docs/site/guides/index.md @@ -0,0 +1,5 @@ +# Guides + +Detailed guides into the following subtopics: + +- [Inventory](./inventory.md): Configuring Services across machine boundaries diff --git a/docs/site/guides/inventory.md b/docs/site/guides/inventory.md new file mode 100644 index 000000000..7e9bd93dc --- /dev/null +++ b/docs/site/guides/inventory.md @@ -0,0 +1,196 @@ +# Inventory + +`Inventory` is an abstract service layer for consistently configuring distributed services across machine boundaries. + +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. + +## Prerequisites Meta (optional) + +Metadata about the clan, will be displayed upfront in the upcomming clan-app, make sure to choose a unique name. + +Make sure to set `name` either via `inventory.meta` OR via `clan.meta`. + +```{.nix hl_lines="3-8"} +buildClan { + inventory = { + meta = { + name = "Superclan" + description = "Awesome backups and family stuff" + }; + }; +} +``` + +## How to add machines + +Machines can be added via `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 + # The following fields are avilable + # description: null | string + # icon: null | string + # name: string + # system: null | string + # tags: [...string] + }; + "jon" = { + # Same as above + }; + }; + }; +} +``` + +## Services + +### Available clanModules + +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. + +### Adding services to machines + +A module can be added to one or multiple machines via `Roles`. clan's `Role` interface provide sane defaults for a module this allows the module author to reduce the configuration overhead to a minimum. + +Each service can still be customized and configured according to the modules options. + +- Per instance configuration via `services...config` +- Per role configuration via `services...roles..config` +- Per machine configuration via `services...machines..config` + +### Setting up the Backup Service + +!!! Example "Borgbackup Example" + + To configure a service it needs to be added to the machine. + It is required to assign the service (`borgbackup`) an arbitrary instance name. (`instance_1`) + + See also: [Multiple Service Instances](#multiple-service-instances) + + ```{.nix hl_lines="14-17"} + 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 = { + roles.client.machines = [ "jon" ]; + roles.server.machines = [ "backup_server" ]; + }; + }; + }; + } + ``` + +### Scalabling the Backup + +The inventory allows machines to set **Tags** + +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"` + +!!! Example "Tags Example" + + ```{.nix hl_lines="9 12 17"} + 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 = { + roles.client.tags = [ "backup" ]; + roles.server.machines = [ "backup_server" ]; + }; + }; + }; + } + ``` + +### Multiple Service Instances + +!!! danger "Important" + Not all modules implement support for multiple instances yet. + Multiple instance usage could create complexity, refer to each modules documentation, for intended usage. + +!!! Example + + In this example `backup_server` has role `client` and `server` in different instances. + + ```{.nix hl_lines="11 14"} + buildClan { + inventory = { + machines = { + "jon" = {}; + "backup_server" = {}; + "backup_backup_server" = {} + }; + services = { + borgbackup.instance_1 = { + roles.client.machines = [ "jon" ]; + roles.server.machines = [ "backup_server" ]; + }; + borgbackup.instance_1 = { + roles.client.machines = [ "backup_server" ]; + roles.server.machines = [ "backup_backup_server" ]; + }; + }; + }; + } + ``` + +### API specification + +**The complete schema specification is available [here](../reference/nix-api/inventory.md)** + +Or it can build anytime via: + +```sh +nix build git+https://git.clan.lol/clan/clan-core#inventory-schema +> result +> ├── schema.cue +> └── schema.json +``` diff --git a/docs/site/reference/nix-api/inventory.md b/docs/site/reference/nix-api/inventory.md index 297a03927..75fa5e970 100644 --- a/docs/site/reference/nix-api/inventory.md +++ b/docs/site/reference/nix-api/inventory.md @@ -1,57 +1,185 @@ -# Inventory +# Inventory API -`Inventory` is an abstract service layer for consistently configuring distributed services across machine boundaries. +*Inventory* is an abstract service layer for consistently configuring distributed services across machine boundaries. -The following is the specification of the inventory in `cuelang` +The following is a specification of the inventory in [cuelang](https://cuelang.org/) format. ```cue -{ - meta: { - // A name of the clan (primarily shown by the UI) - name: string - // A description of the clan - description?: string - // The icon path - icon?: string - } +package compose - // A map of services - services: [string]: [string]: { - // Required meta fields - meta: { - name: string, - icon?: string - description?: string, - }, - // Machines are added via the avilable roles - // Membership depends only on this field - roles: [string]: { - machines: [...string], - tags: [...string], - } - machines?: { - [string]: { - config?: { - ... - } - } - }, +#Root: { + @jsonschema(schema="http://json-schema.org/draft-07/schema#") + machines?: [string]: { + deploy?: { + // Configuration for the deployment of the machine + targetHost: null | string + } + description: null | string + icon: null | string + name: string + system: null | string + tags: [...string] + } + meta?: { + description: null | string + icon: null | string + name: string + } + services?: { + borgbackup?: [string]: { + // borgbackup-config + config?: { + // destinations where the machine should be backuped to + destinations?: { + [string]: { + // the name of the backup job + name: string - // Global Configuration for the service - // Applied to all machines. - config?: { - // Schema depends on the module. - // It declares the interface how the service can be configured. - ... - } - } - // A map of machines, extends the machines of `buildClan` - machines: [string]: { - name: string, - description?: string, - icon?: string - tags: [...string] - system: string - } + // the borgbackup repository to backup to + repo: string + } + } + } | *{ + ... + } + machines?: [string]: { + // borgbackup-config + config?: { + // destinations where the machine should be backuped to + destinations?: { + [string]: { + // the name of the backup job + name: string + + // the borgbackup repository to backup to + repo: string + } + } + } | *{ + ... + } + imports: [...string] + } + meta?: { + description: null | string + icon: null | string + name: string + } + roles?: { + client?: { + // borgbackup-config + config?: { + // destinations where the machine should be backuped to + destinations?: { + [string]: { + // the name of the backup job + name: string + + // the borgbackup repository to backup to + repo: string + } + } + } | *{ + ... + } + imports: [...string] + machines: [...string] + tags: [...string] + } + server?: { + // borgbackup-config + config?: { + // destinations where the machine should be backuped to + destinations?: { + [string]: { + // the name of the backup job + name: string + + // the borgbackup repository to backup to + repo: string + } + } + } | *{ + ... + } + imports: [...string] + machines: [...string] + tags: [...string] + } + } + } + packages?: [string]: { + // packages-config + config?: { + // The packages to install on the machine + packages: [...string] + } | *{ + ... + } + machines?: [string]: { + // packages-config + config?: { + // The packages to install on the machine + packages: [...string] + } | *{ + ... + } + imports: [...string] + } + meta?: { + description: null | string + icon: null | string + name: string + } + roles?: default?: { + // packages-config + config?: { + // The packages to install on the machine + packages: [...string] + } | *{ + ... + } + imports: [...string] + machines: [...string] + tags: [...string] + } + } + "single-disk"?: [string]: { + // single-disk-config + config?: { + // The primary disk device to install the system on + device: null | string + } | *{ + ... + } + machines?: [string]: { + // single-disk-config + config?: { + // The primary disk device to install the system on + device: null | string + } | *{ + ... + } + imports: [...string] + } + meta?: { + description: null | string + icon: null | string + name: string + } + roles?: default?: { + // single-disk-config + config?: { + // The primary disk device to install the system on + device: null | string + } | *{ + ... + } + imports: [...string] + machines: [...string] + tags: [...string] + } + } + } } ``` diff --git a/lib/inventory/flake-module.nix b/lib/inventory/flake-module.nix index 07ad18f5c..14394022a 100644 --- a/lib/inventory/flake-module.nix +++ b/lib/inventory/flake-module.nix @@ -46,6 +46,29 @@ in }; # Inventory schema with concrete module implementations + packages.inventory-api-docs = pkgs.stdenv.mkDerivation { + name = "inventory-schema"; + buildInputs = [ ]; + src = ./.; + buildPhase = '' + cat < "$out" + # Inventory API + + *Inventory* is an abstract service layer for consistently configuring distributed services across machine boundaries. + + The following is a specification of the inventory in [cuelang](https://cuelang.org/) format. + + \`\`\`cue + EOF + + cat ${self'.packages.inventory-schema-pretty}/schema.cue >> $out + + cat <> $out + \`\`\` + EOF + ''; + }; + packages.inventory-schema = pkgs.stdenv.mkDerivation { name = "inventory-schema"; buildInputs = [ pkgs.cue ];