Merge pull request 'Inventory: docs improvements' (#2132) from hsjobeki/clan-core:hsjobeki-inventory-docs into main
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
description = "Convenient Administration for the Clan App"
|
description = "Convenient Administration for the Clan App"
|
||||||
categories = ["administration"]
|
categories = ["Utility"]
|
||||||
|
features = [ "inventory" ]
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{ }
|
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
---
|
---
|
||||||
description = "Statically configure borgbackup with sane defaults."
|
description = "Statically configure borgbackup with sane defaults."
|
||||||
---
|
---
|
||||||
|
!!! Danger "Deprecated"
|
||||||
|
Use [borgbackup](borgbackup.md) instead.
|
||||||
|
|
||||||
|
Don't use borgbackup-static through [inventory](../../guides/inventory.md).
|
||||||
|
|
||||||
This module implements the `borgbackup` backend and implements sane defaults
|
This module implements the `borgbackup` backend and implements sane defaults
|
||||||
for backup management through `borgbackup` for members of the clan.
|
for backup management through `borgbackup` for members of the clan.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
---
|
---
|
||||||
description = "Efficient, deduplicating backup program with optional compression and secure encryption."
|
description = "Efficient, deduplicating backup program with optional compression and secure encryption."
|
||||||
categories = ["backup"]
|
categories = ["System"]
|
||||||
|
features = [ "inventory" ]
|
||||||
---
|
---
|
||||||
BorgBackup (short: Borg) gives you:
|
BorgBackup (short: Borg) gives you:
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
---
|
---
|
||||||
description = "Generates a uuid for use in disk device naming"
|
description = "Generates a uuid for use in disk device naming"
|
||||||
|
features = [ "inventory" ]
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{ }
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
description = "Automatically provisions wifi credentials"
|
description = "Automatically provisions wifi credentials"
|
||||||
|
features = [ "inventory" ]
|
||||||
---
|
---
|
||||||
|
|
||||||
!!! Warning
|
!!! Warning
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{ }
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
---
|
---
|
||||||
description = "Sets the /etc/machine-id and exposes it as a nix option"
|
description = "Sets the /etc/machine-id and exposes it as a nix option"
|
||||||
|
features = [ "inventory" ]
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{ }
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
description = "Open Source, Low Latency, High Quality Voice Chat."
|
description = "Open Source, Low Latency, High Quality Voice Chat."
|
||||||
categories = ["chat", "voice"]
|
categories = ["Audio", "Social"]
|
||||||
---
|
---
|
||||||
The mumble clan module gives you:
|
The mumble clan module gives you:
|
||||||
|
|
||||||
@@ -10,5 +10,5 @@ The mumble clan module gives you:
|
|||||||
- Backed by a large and active open-source community.
|
- Backed by a large and active open-source community.
|
||||||
|
|
||||||
This all set up in a way that allows peer-to-peer hosting.
|
This all set up in a way that allows peer-to-peer hosting.
|
||||||
Every machine inside the clan can be a host for mumble,
|
Every machine inside the clan can be a host for mumble,
|
||||||
and thus it doesn't matter who in the network is online - as long as two people are online they are able to chat with each other.
|
and thus it doesn't matter who in the network is online - as long as two people are online they are able to chat with each other.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
description = "Define package sets from nixpkgs and install them on one or more machines"
|
description = "Define package sets from nixpkgs and install them on one or more machines"
|
||||||
categories = ["packages"]
|
categories = ["System"]
|
||||||
|
features = [ "inventory" ]
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{ }
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
---
|
---
|
||||||
description = "Configures partitioning of the main disk"
|
description = "Configures partitioning of the main disk"
|
||||||
categories = ["disk-layout"]
|
categories = ["System"]
|
||||||
|
features = [ "inventory" ]
|
||||||
---
|
---
|
||||||
# Primary Disk Layout
|
# Primary Disk Layout
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{ }
|
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
description = "Automatically generate the state version of the nixos installation."
|
description = "Automatically generate the state version of the nixos installation."
|
||||||
|
features = [ "inventory" ]
|
||||||
---
|
---
|
||||||
|
|
||||||
This module generates the `system.stateVersion` of the nixos installation automatically.
|
This module generates the `system.stateVersion` of the nixos installation automatically.
|
||||||
|
|
||||||
Options: [system.stateVersion](https://search.nixos.org/options?channel=unstable&show=system.stateVersion&from=0&size=50&sort=relevance&type=packages&query=stateVersion)
|
Options: [system.stateVersion](https://search.nixos.org/options?channel=unstable&show=system.stateVersion&from=0&size=50&sort=relevance&type=packages&query=stateVersion)
|
||||||
|
|
||||||
Migration:
|
Migration:
|
||||||
If you are already setting `system.stateVersion`, then import the module and then either let the automatic generation happen, or trigger the generation manually for the machine. The module will take the specified version, if one is already supplied through the config.
|
If you are already setting `system.stateVersion`, then import the module and then either let the automatic generation happen, or trigger the generation manually for the machine. The module will take the specified version, if one is already supplied through the config.
|
||||||
To manually generate the version for a specified machine run:
|
To manually generate the version for a specified machine run:
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{ }
|
|
||||||
@@ -51,10 +51,12 @@ nav:
|
|||||||
- Flake-parts: getting-started/flake-parts.md
|
- Flake-parts: getting-started/flake-parts.md
|
||||||
- Guides:
|
- Guides:
|
||||||
- guides/index.md
|
- guides/index.md
|
||||||
|
- Adding Machines: guides/add-machines.md
|
||||||
- Inventory: guides/inventory.md
|
- Inventory: guides/inventory.md
|
||||||
- Reference:
|
- Reference:
|
||||||
- reference/index.md
|
- reference/index.md
|
||||||
- Clan Modules:
|
- Clan Modules:
|
||||||
|
- reference/clanModules/index.md
|
||||||
- reference/clanModules/admin.md
|
- reference/clanModules/admin.md
|
||||||
- reference/clanModules/borgbackup-static.md
|
- reference/clanModules/borgbackup-static.md
|
||||||
- reference/clanModules/borgbackup.md
|
- reference/clanModules/borgbackup.md
|
||||||
@@ -65,7 +67,6 @@ nav:
|
|||||||
- reference/clanModules/garage.md
|
- reference/clanModules/garage.md
|
||||||
- reference/clanModules/golem-provider.md
|
- reference/clanModules/golem-provider.md
|
||||||
- reference/clanModules/heisenbridge.md
|
- reference/clanModules/heisenbridge.md
|
||||||
- reference/clanModules/index.md
|
|
||||||
- reference/clanModules/iwd.md
|
- reference/clanModules/iwd.md
|
||||||
- reference/clanModules/localbackup.md
|
- reference/clanModules/localbackup.md
|
||||||
- reference/clanModules/localsend.md
|
- reference/clanModules/localsend.md
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import os
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from clan_cli.api.modules import Frontmatter, extract_frontmatter
|
from clan_cli.api.modules import Frontmatter, extract_frontmatter, get_roles
|
||||||
from clan_cli.errors import ClanError
|
from clan_cli.errors import ClanError
|
||||||
|
|
||||||
# Get environment variables
|
# Get environment variables
|
||||||
@@ -125,14 +125,15 @@ def render_option(name: str, option: dict[str, Any], level: int = 3) -> str:
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
def module_header(module_name: str) -> str:
|
def module_header(module_name: str, has_inventory_feature: bool = False) -> str:
|
||||||
return f"# {module_name}\n\n"
|
indicator = " 🔹" if has_inventory_feature else ""
|
||||||
|
return f"# {module_name}{indicator}\n\n"
|
||||||
|
|
||||||
|
|
||||||
def module_usage(module_name: str) -> str:
|
def module_usage(module_name: str) -> str:
|
||||||
return f"""## Usage
|
return f"""## Usage
|
||||||
|
|
||||||
To use this module, import it like this:
|
To use this module, import it like th:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{{config, lib, inputs, ...}}: {{
|
{{config, lib, inputs, ...}}: {{
|
||||||
@@ -198,25 +199,13 @@ def render_roles(roles: list[str] | None, module_name: str) -> str:
|
|||||||
if roles:
|
if roles:
|
||||||
roles_list = "\n".join([f" - `{r}`" for r in roles])
|
roles_list = "\n".join([f" - `{r}`" for r in roles])
|
||||||
return f"""
|
return f"""
|
||||||
???+ tip "Inventory usage"
|
## Inventory Roles
|
||||||
|
|
||||||
Predefined roles:
|
Predefined roles
|
||||||
|
|
||||||
{roles_list}
|
{roles_list}
|
||||||
|
|
||||||
Usage:
|
For more information, see the [inventory guide](../../guides/inventory.md).
|
||||||
|
|
||||||
```{{.nix hl_lines="4"}}
|
|
||||||
buildClan {{
|
|
||||||
inventory.services = {{
|
|
||||||
{module_name}.instance_1 = {{
|
|
||||||
roles.{roles[0]}.machines = [ "sara_machine" ];
|
|
||||||
# ...
|
|
||||||
}};
|
|
||||||
}};
|
|
||||||
}}
|
|
||||||
```
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
@@ -226,6 +215,21 @@ clan_modules_descr = """Clan modules are [NixOS modules](https://wiki.nixos.org/
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def render_categories(categories: list[str], frontmatter: Frontmatter) -> str:
|
||||||
|
cat_info = frontmatter.categories_info
|
||||||
|
res = """<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;">"""
|
||||||
|
for cat in categories:
|
||||||
|
color = cat_info[cat]["color"]
|
||||||
|
# description = cat_info[cat]["description"]
|
||||||
|
res += f"""
|
||||||
|
<div style="background-color: {color}; color: white; padding: 10px; border-radius: 20px; text-align: center;">
|
||||||
|
{cat}
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
res += "</div>"
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
def produce_clan_modules_docs() -> None:
|
def produce_clan_modules_docs() -> None:
|
||||||
if not CLAN_MODULES:
|
if not CLAN_MODULES:
|
||||||
msg = f"Environment variables are not set correctly: $out={CLAN_MODULES}"
|
msg = f"Environment variables are not set correctly: $out={CLAN_MODULES}"
|
||||||
@@ -270,16 +274,21 @@ def produce_clan_modules_docs() -> None:
|
|||||||
with (Path(options_file) / "share/doc/nixos/options.json").open() as f:
|
with (Path(options_file) / "share/doc/nixos/options.json").open() as f:
|
||||||
options: dict[str, dict[str, Any]] = json.load(f)
|
options: dict[str, dict[str, Any]] = json.load(f)
|
||||||
print(f"Rendering options for {module_name}...")
|
print(f"Rendering options for {module_name}...")
|
||||||
output = module_header(module_name)
|
output = module_header(module_name, "inventory" in frontmatter.features)
|
||||||
|
|
||||||
if frontmatter.description:
|
if frontmatter.description:
|
||||||
output += f"**{frontmatter.description}**\n\n"
|
output += f"**{frontmatter.description}**\n\n"
|
||||||
|
|
||||||
|
output += "## Categories\n\n"
|
||||||
|
output += render_categories(frontmatter.categories, frontmatter)
|
||||||
|
output += "\n---\n\n"
|
||||||
|
|
||||||
output += f"{readme_content}\n"
|
output += f"{readme_content}\n"
|
||||||
|
|
||||||
# get_roles(str) -> list[str] | None
|
# get_roles(str) -> list[str] | None
|
||||||
# roles = get_roles(CLAN_CORE_PATH / "clanModules" / module_name)
|
roles = get_roles(CLAN_CORE_PATH / "clanModules" / module_name)
|
||||||
# if roles:
|
if roles:
|
||||||
# output += render_roles(roles, module_name)
|
output += render_roles(roles, module_name)
|
||||||
|
|
||||||
output += module_usage(module_name)
|
output += module_usage(module_name)
|
||||||
|
|
||||||
|
|||||||
50
docs/site/guides/add-machines.md
Normal file
50
docs/site/guides/add-machines.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# How to add machines
|
||||||
|
|
||||||
|
Clan has two general methods of adding machines
|
||||||
|
|
||||||
|
- **Automatic**: Detects every folder in the `machines` folder.
|
||||||
|
- **Declarative**: Explicit declarations in nix.
|
||||||
|
|
||||||
|
## Automatic register
|
||||||
|
|
||||||
|
Every machine of the form `machines/{machineName}` will be registered automatically.
|
||||||
|
|
||||||
|
Automatically imported:
|
||||||
|
|
||||||
|
- [x] ``machines/{machineName}/configuration.nix`
|
||||||
|
- [x] ``machines/{machineName}/hardware-configuration.nix`
|
||||||
|
- [x] ``machines/{machineName}/facter.json` Automatically configured, for further information see [nixos-facter](../blog/posts/nixos-facter.md)
|
||||||
|
|
||||||
|
## Manual declaration
|
||||||
|
|
||||||
|
Machines can also be added manually under `buildClan`, `clan.*` in flake-parts or via [`inventory`](../guides/inventory.md).
|
||||||
|
|
||||||
|
!!! Note
|
||||||
|
It is possible to use `inventory` and `buildClan` together at the same time.
|
||||||
|
|
||||||
|
=== "**Individual Machine Configuration**"
|
||||||
|
|
||||||
|
```{.nix}
|
||||||
|
buildClan {
|
||||||
|
machines = {
|
||||||
|
"jon" = {
|
||||||
|
# Any valid nixos config
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "**Inventory Configuration**"
|
||||||
|
|
||||||
|
```{.nix}
|
||||||
|
buildClan {
|
||||||
|
inventory = {
|
||||||
|
machines = {
|
||||||
|
"jon" = {
|
||||||
|
# Inventory machines can set tags
|
||||||
|
tags = [ "zone1" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -2,4 +2,5 @@
|
|||||||
|
|
||||||
Detailed guides into the following subtopics:
|
Detailed guides into the following subtopics:
|
||||||
|
|
||||||
|
- [Adding Machines](./add-machines.md): How to add machines.
|
||||||
- [Inventory](./inventory.md): Configuring Services across machine boundaries
|
- [Inventory](./inventory.md): Configuring Services across machine boundaries
|
||||||
|
|||||||
@@ -4,73 +4,36 @@
|
|||||||
|
|
||||||
See [Inventory API Documentation](../reference/nix-api/inventory.md)
|
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.
|
This guide will walk you through setting up a backup service, where the inventory becomes useful.
|
||||||
|
|
||||||
## Prerequisites Meta (optional)
|
!!! example "Experimental status"
|
||||||
|
The inventory implementation is not considered stable yet.
|
||||||
|
We are actively soliciting feedback from users.
|
||||||
|
|
||||||
Metadata about the clan, will be displayed upfront in the upcomming clan-app, make sure to choose a unique name.
|
Stabilizing the API is a priority.
|
||||||
|
|
||||||
Make sure to set `name` either via `inventory.meta` OR via `clan.meta`.
|
## Categories
|
||||||
|
|
||||||
```{.nix hl_lines="3-8"}
|
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;">
|
||||||
buildClan {
|
<!-- Chip 1 -->
|
||||||
inventory = {
|
<div style="background-color: #F5B7B1; color: white; padding: 10px; border-radius: 20px; text-align: center;">
|
||||||
meta = {
|
Light Coral
|
||||||
name = "Superclan"
|
</div>
|
||||||
description = "Awesome backups and family stuff"
|
<!-- Chip 2 -->
|
||||||
};
|
<div style="background-color: #85C1E9; color: white; padding: 10px; border-radius: 20px; text-align: center;">
|
||||||
};
|
Baby Blue
|
||||||
}
|
</div>
|
||||||
```
|
</div>
|
||||||
|
|
||||||
## How to add machines
|
## Prerequisites
|
||||||
|
|
||||||
Every machine of the form `machines/{machineName}/configuration.nix` will be registered automatically.
|
- [x] [Add machines](./add-machines.md) to your clan.
|
||||||
|
|
||||||
Machines can also be manually added under `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.
|
|
||||||
# See the Inventory API Docs for the available attributes.
|
|
||||||
};
|
|
||||||
"jon" = {
|
|
||||||
# Same as above
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Services
|
## Services
|
||||||
|
|
||||||
### Available clanModules
|
The inventory defines `services`. Membership of `machines` is defined via roles exclusively.
|
||||||
|
|
||||||
Currently the inventory interface is implemented by the following clanModules
|
See the each [module documentation](../reference/clanModules/index.md) for available roles.
|
||||||
|
|
||||||
- [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.
|
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
It is possible to use any [clanModule](../reference/clanModules/index.md) in the inventory and add machines via
|
It is possible to use any [clanModule](../reference/clanModules/index.md) in the inventory and add machines via
|
||||||
@@ -95,21 +58,12 @@ Each service can still be customized and configured according to the modules opt
|
|||||||
|
|
||||||
See also: [Multiple Service Instances](#multiple-service-instances)
|
See also: [Multiple Service Instances](#multiple-service-instances)
|
||||||
|
|
||||||
```{.nix hl_lines="14-17"}
|
```{.nix hl_lines="6-7"}
|
||||||
buildClan {
|
buildClan {
|
||||||
inventory = {
|
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 = {
|
services = {
|
||||||
borgbackup.instance_1 = {
|
borgbackup.instance_1 = {
|
||||||
|
# Machines can be added here.
|
||||||
roles.client.machines = [ "jon" ];
|
roles.client.machines = [ "jon" ];
|
||||||
roles.server.machines = [ "backup_server" ];
|
roles.server.machines = [ "backup_server" ];
|
||||||
};
|
};
|
||||||
@@ -120,24 +74,23 @@ Each service can still be customized and configured according to the modules opt
|
|||||||
|
|
||||||
### Scaling the Backup
|
### Scaling the Backup
|
||||||
|
|
||||||
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"`
|
The inventory allows machines to set Tags
|
||||||
|
|
||||||
|
It is possible to add services to multiple machines via tags as shown
|
||||||
|
|
||||||
!!! Example "Tags Example"
|
!!! Example "Tags Example"
|
||||||
|
|
||||||
```{.nix hl_lines="9 12 17"}
|
```{.nix hl_lines="5 8 14"}
|
||||||
buildClan {
|
buildClan {
|
||||||
inventory = {
|
inventory = {
|
||||||
machines = {
|
machines = {
|
||||||
"backup_server" = {
|
|
||||||
# Don't include any nixos config here
|
|
||||||
# See inventory.Machines for available options
|
|
||||||
};
|
|
||||||
"jon" = {
|
"jon" = {
|
||||||
tags = [ "backup" ];
|
tags = [ "backup" ];
|
||||||
};
|
};
|
||||||
"sara" = {
|
"sara" = {
|
||||||
tags = [ "backup" ];
|
tags = [ "backup" ];
|
||||||
};
|
};
|
||||||
|
# ...
|
||||||
};
|
};
|
||||||
services = {
|
services = {
|
||||||
borgbackup.instance_1 = {
|
borgbackup.instance_1 = {
|
||||||
@@ -172,7 +125,7 @@ It is possible to add services to multiple machines via tags. The service instan
|
|||||||
roles.client.machines = [ "jon" ];
|
roles.client.machines = [ "jon" ];
|
||||||
roles.server.machines = [ "backup_server" ];
|
roles.server.machines = [ "backup_server" ];
|
||||||
};
|
};
|
||||||
borgbackup.instance_1 = {
|
borgbackup.instance_2 = {
|
||||||
roles.client.machines = [ "backup_server" ];
|
roles.client.machines = [ "backup_server" ];
|
||||||
roles.server.machines = [ "backup_backup_server" ];
|
roles.server.machines = [ "backup_backup_server" ];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ let
|
|||||||
hwConfig = "${directory}/machines/${name}/hardware-configuration.nix";
|
hwConfig = "${directory}/machines/${name}/hardware-configuration.nix";
|
||||||
|
|
||||||
facterModules = lib.optionals (builtins.pathExists facterJson) [
|
facterModules = lib.optionals (builtins.pathExists facterJson) [
|
||||||
"${clan-core.inputs.nixos-facter-modules}/modules/nixos/facter.nix"
|
clan-core.inputs.nixos-facter-modules.nixosModules.facter
|
||||||
{ config.facter.reportPath = facterJson; }
|
{ config.facter.reportPath = facterJson; }
|
||||||
];
|
];
|
||||||
in
|
in
|
||||||
@@ -231,6 +231,9 @@ in
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
inventory.machines = lib.mapAttrs (_n: _: { }) config.machines;
|
||||||
|
}
|
||||||
# Merge the meta attributes from the buildClan function
|
# Merge the meta attributes from the buildClan function
|
||||||
{ inventory.meta = if config.meta != null then config.meta else { }; }
|
{ inventory.meta = if config.meta != null then config.meta else { }; }
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ rec {
|
|||||||
in
|
in
|
||||||
readmeContents;
|
readmeContents;
|
||||||
|
|
||||||
getShortDescription =
|
getFrontmatter =
|
||||||
modulename:
|
modulename:
|
||||||
let
|
let
|
||||||
content = getReadme modulename;
|
content = getReadme modulename;
|
||||||
@@ -21,14 +21,21 @@ rec {
|
|||||||
parsed = builtins.partition ({ index, ... }: if index >= 2 then false else true) (
|
parsed = builtins.partition ({ index, ... }: if index >= 2 then false else true) (
|
||||||
lib.filter ({ index, ... }: index != 0) (lib.imap0 (index: part: { inherit index part; }) parts)
|
lib.filter ({ index, ... }: index != 0) (lib.imap0 (index: part: { inherit index part; }) parts)
|
||||||
);
|
);
|
||||||
|
|
||||||
# Use this if the content is needed
|
|
||||||
# readmeContent = lib.concatMapStrings (v: "---" + v.part) parsed.wrong;
|
|
||||||
|
|
||||||
meta = builtins.fromTOML (builtins.head parsed.right).part;
|
meta = builtins.fromTOML (builtins.head parsed.right).part;
|
||||||
in
|
in
|
||||||
if (builtins.length parts >= 3) then
|
if (builtins.length parts >= 3) then
|
||||||
meta.description
|
meta
|
||||||
else
|
else
|
||||||
throw "Short description delimiter `---` not found in README.md for module ${modulename}";
|
throw ''
|
||||||
|
TOML Frontmatter not found in README.md for module ${modulename}
|
||||||
|
|
||||||
|
Please add the following to the top of your README.md:
|
||||||
|
|
||||||
|
---
|
||||||
|
description = "Your description here"
|
||||||
|
categories = [ "Your categories here" ]
|
||||||
|
features = [ "inventory" ]
|
||||||
|
---
|
||||||
|
...rest of your README.md...
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,4 +74,5 @@
|
|||||||
) [ ] config.services;
|
) [ ] config.services;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,44 +37,18 @@ let
|
|||||||
) [ ] members.tags or [ ]);
|
) [ ] members.tags or [ ]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
checkService =
|
||||||
|
serviceName:
|
||||||
|
let
|
||||||
|
frontmatter = clan-core.lib.modules.getFrontmatter serviceName;
|
||||||
|
in
|
||||||
|
if builtins.elem "inventory" frontmatter.features or [ ] then true else false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Returns a NixOS configuration for every machine in the inventory.
|
Returns a NixOS configuration for every machine in the inventory.
|
||||||
|
|
||||||
machinesFromInventory :: Inventory -> { ${machine_name} :: NixOSConfiguration }
|
machinesFromInventory :: Inventory -> { ${machine_name} :: NixOSConfiguration }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
# { client_1_machine = { tags = [ "backup" ]; }; client_2_machine = { tags = [ "backup" ]; }; not_used_machine = { }; }
|
|
||||||
getAllMachines =
|
|
||||||
inventory:
|
|
||||||
lib.foldlAttrs (
|
|
||||||
res: serviceName: serviceConfigs:
|
|
||||||
(lib.foldlAttrs (
|
|
||||||
res: instanceName: serviceConfig:
|
|
||||||
lib.foldlAttrs (
|
|
||||||
res: roleName: members:
|
|
||||||
let
|
|
||||||
resolved = resolveTags {
|
|
||||||
inherit
|
|
||||||
serviceName
|
|
||||||
instanceName
|
|
||||||
roleName
|
|
||||||
inventory
|
|
||||||
members
|
|
||||||
;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
res
|
|
||||||
// builtins.listToAttrs (
|
|
||||||
builtins.map (m: {
|
|
||||||
name = m;
|
|
||||||
value = { };
|
|
||||||
}) resolved.machines
|
|
||||||
)
|
|
||||||
) res serviceConfig.roles
|
|
||||||
) res serviceConfigs)
|
|
||||||
) { } (inventory.services or { })
|
|
||||||
// inventory.machines or { };
|
|
||||||
|
|
||||||
buildInventory =
|
buildInventory =
|
||||||
{ inventory, directory }:
|
{ inventory, directory }:
|
||||||
# For every machine in the inventory, build a NixOS configuration
|
# For every machine in the inventory, build a NixOS configuration
|
||||||
@@ -178,7 +152,7 @@ let
|
|||||||
]
|
]
|
||||||
else
|
else
|
||||||
acc2
|
acc2
|
||||||
) [ ] serviceConfigs)
|
) [ ] (serviceConfigs))
|
||||||
) [ ] inventory.services
|
) [ ] inventory.services
|
||||||
# Append each machine config
|
# Append each machine config
|
||||||
++ [
|
++ [
|
||||||
@@ -188,9 +162,35 @@ let
|
|||||||
(lib.optionalAttrs (machineConfig.deploy.targetHost or null != null) {
|
(lib.optionalAttrs (machineConfig.deploy.targetHost or null != null) {
|
||||||
config.clan.core.networking.targetHost = machineConfig.deploy.targetHost;
|
config.clan.core.networking.targetHost = machineConfig.deploy.targetHost;
|
||||||
})
|
})
|
||||||
|
{
|
||||||
|
assertions = lib.foldlAttrs (
|
||||||
|
acc: serviceName: _:
|
||||||
|
acc
|
||||||
|
++ [
|
||||||
|
{
|
||||||
|
assertion = checkService serviceName;
|
||||||
|
message = ''
|
||||||
|
Service ${serviceName} cannot be used in inventory. It does not declare the 'inventory' feature.
|
||||||
|
|
||||||
|
|
||||||
|
To allow it add the following to the beginning of the README.md of the module:
|
||||||
|
|
||||||
|
---
|
||||||
|
...
|
||||||
|
|
||||||
|
features = [ "inventory" ]
|
||||||
|
---
|
||||||
|
|
||||||
|
Also make sure to test the module with the 'inventory' feature enabled.
|
||||||
|
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
]
|
||||||
|
) [ ] inventory.services;
|
||||||
|
}
|
||||||
]
|
]
|
||||||
) (getAllMachines inventory);
|
) (inventory.machines or { });
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
inherit buildInventory getAllMachines;
|
inherit buildInventory;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,8 @@
|
|||||||
{ inventory, clan-core, ... }:
|
{ inventory, clan-core, ... }:
|
||||||
let
|
let
|
||||||
inherit (inventory) buildInventory getAllMachines;
|
inherit (inventory) buildInventory;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
test_get_all_used_machines = {
|
|
||||||
# Test that all machines are returned
|
|
||||||
expr = getAllMachines {
|
|
||||||
machines = {
|
|
||||||
machine_3 = {
|
|
||||||
tags = [ "tag_3" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
services = {
|
|
||||||
borgbackup.instance_1 = {
|
|
||||||
roles.server.machines = [ "backup_server" ];
|
|
||||||
roles.client.machines = [
|
|
||||||
"client_1_machine"
|
|
||||||
"client_2_machine"
|
|
||||||
];
|
|
||||||
roles.client.tags = [ "tag_3" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
expected = {
|
|
||||||
backup_server = { };
|
|
||||||
client_1_machine = { };
|
|
||||||
client_2_machine = { };
|
|
||||||
machine_3 = {
|
|
||||||
tags = [ "tag_3" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
test_inventory_empty = {
|
test_inventory_empty = {
|
||||||
# Empty inventory should return an empty module
|
# Empty inventory should return an empty module
|
||||||
expr = buildInventory {
|
expr = buildInventory {
|
||||||
@@ -117,9 +88,9 @@ in
|
|||||||
not_used_machine = builtins.length configs.not_used_machine;
|
not_used_machine = builtins.length configs.not_used_machine;
|
||||||
};
|
};
|
||||||
expected = {
|
expected = {
|
||||||
client_1_machine = 5;
|
client_1_machine = 6;
|
||||||
client_2_machine = 5;
|
client_2_machine = 6;
|
||||||
not_used_machine = 2;
|
not_used_machine = 3;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
import tomllib
|
import tomllib
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass, field
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, get_args, get_type_hints
|
from typing import Any, TypedDict, get_args, get_type_hints
|
||||||
|
|
||||||
from clan_cli.cmd import run_no_stdout
|
from clan_cli.cmd import run_no_stdout
|
||||||
from clan_cli.errors import ClanCmdError, ClanError
|
from clan_cli.errors import ClanCmdError, ClanError
|
||||||
@@ -15,10 +15,47 @@ from . import API
|
|||||||
from .serde import from_dict
|
from .serde import from_dict
|
||||||
|
|
||||||
|
|
||||||
|
class CategoryInfo(TypedDict):
|
||||||
|
color: str
|
||||||
|
description: str
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Frontmatter:
|
class Frontmatter:
|
||||||
description: str
|
description: str
|
||||||
categories: list[str] | None = None
|
categories: list[str] = field(default_factory=lambda: ["Uncategorized"])
|
||||||
|
features: list[str] = field(default_factory=list)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def categories_info(self) -> dict[str, CategoryInfo]:
|
||||||
|
category_map: dict[str, CategoryInfo] = {
|
||||||
|
"AudioVideo": {
|
||||||
|
"color": "#AEC6CF",
|
||||||
|
"description": "Applications for presenting, creating, or processing multimedia (audio/video)",
|
||||||
|
},
|
||||||
|
"Audio": {"color": "#CFCFC4", "description": "Audio"},
|
||||||
|
"Video": {"color": "#FFD1DC", "description": "Video"},
|
||||||
|
"Development": {"color": "#F49AC2", "description": "Development"},
|
||||||
|
"Education": {"color": "#B39EB5", "description": "Education"},
|
||||||
|
"Game": {"color": "#FFB347", "description": "Game"},
|
||||||
|
"Graphics": {"color": "#FF6961", "description": "Graphics"},
|
||||||
|
"Social": {"color": "#76D7C4", "description": "Social"},
|
||||||
|
"Network": {"color": "#77DD77", "description": "Network"},
|
||||||
|
"Office": {"color": "#85C1E9", "description": "Office"},
|
||||||
|
"Science": {"color": "#779ECB", "description": "Science"},
|
||||||
|
"System": {"color": "#F5C3C0", "description": "System"},
|
||||||
|
"Settings": {"color": "#03C03C", "description": "Settings"},
|
||||||
|
"Utility": {"color": "#B19CD9", "description": "Utility"},
|
||||||
|
"Uncategorized": {"color": "#C23B22", "description": "Uncategorized"},
|
||||||
|
}
|
||||||
|
|
||||||
|
return category_map
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
for category in self.categories:
|
||||||
|
if category not in self.categories_info:
|
||||||
|
msg = f"Invalid category: {category}"
|
||||||
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
|
||||||
def extract_frontmatter(readme_content: str, err_scope: str) -> tuple[Frontmatter, str]:
|
def extract_frontmatter(readme_content: str, err_scope: str) -> tuple[Frontmatter, str]:
|
||||||
|
|||||||
@@ -23,11 +23,14 @@
|
|||||||
modulename: _: jsonLib.parseOptions (optionsFromModule modulename) { }
|
modulename: _: jsonLib.parseOptions (optionsFromModule modulename) { }
|
||||||
) clanModules;
|
) clanModules;
|
||||||
|
|
||||||
clanModuleFunctionSchemas = lib.mapAttrsFlatten (modulename: _: {
|
clanModuleFunctionSchemas = lib.mapAttrsFlatten (
|
||||||
name = modulename;
|
modulename: _:
|
||||||
description = self.lib.modules.getShortDescription modulename;
|
(self.lib.modules.getFrontmatter modulename)
|
||||||
parameters = jsonLib.parseOptions (optionsFromModule modulename) { };
|
// {
|
||||||
}) clanModules;
|
name = modulename;
|
||||||
|
parameters = jsonLib.parseOptions (optionsFromModule modulename) { };
|
||||||
|
}
|
||||||
|
) clanModules;
|
||||||
in
|
in
|
||||||
rec {
|
rec {
|
||||||
checks = {
|
checks = {
|
||||||
|
|||||||
Reference in New Issue
Block a user