Inventory: init draft ideas

This commit is contained in:
Johannes Kirschbauer 2024-06-15 13:41:51 +02:00
parent bd9883baaf
commit 7474f01193
Signed by: hsjobeki
SSH Key Fingerprint: SHA256:vX3utDqig7Ph5L0JPv87ZTPb/w7cMzREKVZzzLFg9qU
12 changed files with 309 additions and 0 deletions

View File

@ -53,6 +53,8 @@
./nixosModules/flake-module.nix
./pkgs/flake-module.nix
./templates/flake-module.nix
./inventory/flake-module.nix
];
}
);

5
inventory/.envrc Normal file
View File

@ -0,0 +1,5 @@
source_up
watch_file flake-module.nix
use flake .#inventory-schema --builders ''

6
inventory/.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,6 @@
{
"cue.toolsPath": "/nix/store/x9471mp522cdi4c9gc8dchvyx6v01b3f-cue-0.8.2/bin/cue",
"[cue]": {
"editor.formatOnSave": false
}
}

57
inventory/README.md Normal file
View File

@ -0,0 +1,57 @@
# Inventory
This part provides a specification for the inventory.
It is used for design phase and as validation helper.
> Cue is less verbose and easier to understand and maintain than json-schema.
> Json-schema, if needed can be easily generated on-the fly.
## Checking validity
Directly check a json against the schema
`cue vet inventory.json root.cue -d '#Root'`
## Json schema
Export the json-schema i.e. for usage in python / javascript / nix
`cue export --out openapi root.cue`
## Usage
Comments are rendered as descriptions in the json schema.
```cue
// A name of the clan (primarily shown by the UI)
name: string
```
Cue open sets. In the following `foo = {...}` means that the key `foo` can contain any arbitrary json object.
```cue
foo: { ... }
```
Cue dynamic keys.
```cue
[string]: {
attr: string
}
```
This is the schema of
```json
{
"a": {
"attr": "foo"
},
"b": {
"attr": "bar"
}
// ... Indefinitely more dynamic keys of type "string"
}
```

119
inventory/example_flake.nix Normal file
View File

@ -0,0 +1,119 @@
{
description = "<Put your description here>";
inputs.clan-core.url = "https://git.clan.lol/clan/clan-core/archive/main.tar.gz";
outputs =
{ clan-core, ... }:
let
pkgs = clan-core.inputs.nixpkgs.legacyPackages.${system};
# Usage see: https://docs.clan.lol
# nice_flake_interface -> buildClan() -> inventory -> buildClanFromInventory() -> nixosConfigurations
system = "x86_64-linux";
clan =
clan-core.lib.buildClanFromInventory [
# Inventory 0 (loads the json file managed by the Python API)
(builtins.fromJSON (builtins.readFile ./inventory.json))
# ->
# {
# services."backups_1".autoIncludeMachines = true;
# services."backups_1".module = "borgbackup";
# ... etc.
# }
]
++ buildInventory {
clanName = "nice_flake_interface";
description = "A nice flake interface";
icon = "assets/icon.png";
machines = {
jon = {
# Just regular nixos/clan configuration ?
# config = {
# imports = [
# ./modules/shared.nix
# ./machines/jon/configuration.nix
# ];
# nixpkgs.hostPlatform = system;
# # Set this for clan commands use ssh i.e. `clan machines update`
# # If you change the hostname, you need to update this line to root@<new-hostname>
# # This only works however if you have avahi running on your admin machine else use IP
# clan.networking.targetHost = pkgs.lib.mkDefault "root@jon";
# # ssh root@flash-installer.local lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT
# disko.devices.disk.main = {
# device = "/dev/disk/by-id/__CHANGE_ME__";
# };
# # IMPORTANT! Add your SSH key here
# # e.g. > cat ~/.ssh/id_ed25519.pub
# users.users.root.openssh.authorizedKeys.keys = throw ''
# Don't forget to add your SSH key here!
# users.users.root.openssh.authorizedKeys.keys = [ "<YOUR SSH_KEY>" ]
# '';
# # Zerotier needs one controller to accept new nodes. Once accepted
# # the controller can be offline and routing still works.
# clan.networking.zerotier.controller.enable = true;
# };
};
};
}
++ [
# Low level inventory overrides (comes at the end)
{
services."backups_2".autoIncludeMachines = true;
services."backups_2".module = "borgbackup";
}
];
/*
# Type
buildInventory :: {
clanName :: string
machines :: {
${name} :: {
config :: {
# NixOS configuration
};
};
};
# ... More mapped inventory options
# i.e. shared config for all machines
} -> Inventory
*/
buildInventory =
options:
let
# TODO: Map over machines
name = "jon";
inventory = {
# Set the clan meta
meta.name = options.clanName;
meta.description = options.description;
meta.icon = options.icon;
# Declare the services
# This "nixos" module simply provides the usual NixOS configuration options.
services."nixos".module = "nixos";
services."nixos".machineConfig.${name}.config = options.machines.${name}.config;
# Declare the machines
machines.${name} = {
name = options.machines.${name}.meta.name;
description = options.machines.${name}.meta.description;
icon = options.machines.${name}.meta.icon;
system = options.machines.${name}.config.nixpkgs.hostPlatform;
};
};
in
inventory;
in
{
# all machines managed by Clan
inherit (clan) nixosConfigurations clanInternals;
# add the Clan cli tool to the dev shell
devShells.${system}.default = pkgs.mkShell {
packages = [ clan-core.packages.${system}.clan-cli ];
};
};
}

View File

@ -0,0 +1,18 @@
{ ... }:
{
perSystem =
{ pkgs, config, ... }:
{
packages.inventory-schema = pkgs.stdenv.mkDerivation {
name = "inventory-schema";
src = ./src;
buildInputs = [ pkgs.cue ];
installPhase = ''
mkdir -p $out
'';
};
devShells.inventory-schema = pkgs.mkShell { inputsFrom = [ config.packages.inventory-schema ]; };
};
}

34
inventory/inventory.json Normal file
View File

@ -0,0 +1,34 @@
{
"meta": {
"name": "My clan",
"description": "My clan description",
"icon": "assets/clan-icon.png"
},
"services": {
"service_ref": {
"meta": {
"name": "backup"
},
"autoIncludeMachines": true,
"module": "core"
}
},
"machines": {
"jon_machine": {
"name": "jon_machine",
"description": "Jon's machine",
"icon": "assets/icon.png",
"system": "x86_64-linux"
}
},
"users": {
"mic": {
"autoInclude": false,
"schemas": ["ssh-user"],
"config": {
"sshKey": "...",
"username": "mic92"
}
}
}
}

View File

@ -0,0 +1,2 @@
module: "clan.lol/inventory"
language: version: "v0.8.2"

View File

@ -0,0 +1,8 @@
package machines
#machine: machines: [string]: {
"name": string,
"description": string,
"icon": string,
"system": string
}

28
inventory/src/root.cue Normal file
View File

@ -0,0 +1,28 @@
package inventory
import (
"clan.lol/inventory/services"
"clan.lol/inventory/machines"
"clan.lol/inventory/users"
)
@jsonschema(schema="http://json-schema.org/schema#")
#Root: {
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
}
// A map of services
services.#service
// A map of machines
machines.#machine
// A map of users
users.#user
}

View File

@ -0,0 +1,21 @@
package services
#service: services: [string]: {
autoIncludeMachines: bool,
meta: {
name: string,
},
// TODO: this should be the list of avilable modules
module: string,
machineConfig: {
[string]: {
config: {
defaultUser?: string
}
}
},
globalConfig: {
// Should be one of the avilable users
defaultUser?: string,
}
}

View File

@ -0,0 +1,9 @@
package users
#user: users: [string]: {
"autoInclude": bool,
"schemas": [ string ],
"config": {
...
}
}