Inventory: init draft ideas

This commit is contained in:
Johannes Kirschbauer
2024-06-15 13:41:51 +02:00
parent 7474f01193
commit 13aa60529f
9 changed files with 243 additions and 171 deletions

View File

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

View File

@@ -7,65 +7,109 @@
{ clan-core, ... }: { clan-core, ... }:
let let
pkgs = clan-core.inputs.nixpkgs.legacyPackages.${system}; pkgs = clan-core.inputs.nixpkgs.legacyPackages.${system};
# Usage see: https://docs.clan.lol
# nice_flake_interface -> buildClan() -> inventory -> buildClanFromInventory() -> nixosConfigurations
system = "x86_64-linux"; system = "x86_64-linux";
in
clan = # Usage see: https://docs.clan.lol
clan-core.lib.buildClanFromInventory [ # nice_flake_interface -> buildInventory() -> Inventory -> buildClanFromInventory() -> nixosConfigurations
# Inventory 0 (loads the json file managed by the Python API) # buildClanFromInventory = inventory: evalModules {
(builtins.fromJSON (builtins.readFile ./inventory.json)) # extraAttrs = { inherit inventory; };
# -> # # (attrNames inventory.machines)
# };
# 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_1".autoIncludeMachines = true; # services."backups_2".autoIncludeMachines = true;
# services."backups_1".module = "borgbackup"; # services."backups_2".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; # # buildClan :: [ Partial<Inventory> ] -> Inventory
# # Set this for clan commands use ssh i.e. `clan machines update` # # foldl' (acc: v: lib.recursiveUpdate acc v) {} []
# # If you change the hostname, you need to update this line to root@<new-hostname> # inventory = [
# # This only works however if you have avahi running on your admin machine else use IP # # import json
# clan.networking.targetHost = pkgs.lib.mkDefault "root@jon"; # {...}
# # ssh root@flash-installer.local lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT # # power user flake
# disko.devices.disk.main = { # {...}
# device = "/dev/disk/by-id/__CHANGE_ME__"; # ]
# }; # # With Module system
# # IMPORTANT! Add your SSH key here # # Pros: Easy to understand,
# # e.g. > cat ~/.ssh/id_ed25519.pub # # Cons: Verbose, hard to maintain
# users.users.root.openssh.authorizedKeys.keys = throw '' # # buildClan :: { modules = [ { config = Partial<Inventory>; options :: InventoryOptions; } } ]; } -> Inventory
# Don't forget to add your SSH key here! # eval = lib.evalModules {
# users.users.root.openssh.authorizedKeys.keys = [ "<YOUR SSH_KEY>" ] # modules = [
# ''; # {
# # Zerotier needs one controller to accept new nodes. Once accepted # # Inventory Schema
# # the controller can be offline and routing still works. # # Python validation
# clan.networking.zerotier.controller.enable = true; # options = {...}
# }; # }
}; # {
}; # config = map lib.mkDefault
} # (builtins.fromJSON (builtins.readFile ./inventory.json))
++ [ # }
# Low level inventory overrides (comes at the end) # {
{ # # User provided
services."backups_2".autoIncludeMachines = true; # config = {...}
services."backups_2".module = "borgbackup"; # }
} # # Later overrides.
]; # {
# lib.mkForce ...
# }
# ];
# }
# nixosConfigurations = lib.evalModules inventory;
# eval.config.inventory
# #
# eval.config.machines.jon#nixosConfig
# eval.config.machines.sara#nixosConfig
#
# {inventory, config, ...}:{
# hostname = config.machines.sara # Invalid
# hostname = inventory.machines.sara.hostname # Valid
# }
/* /*
# Type # Type
@@ -82,32 +126,6 @@
# i.e. shared config for all machines # i.e. shared config for all machines
} -> Inventory } -> 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 # all machines managed by Clan
inherit (clan) nixosConfigurations clanInternals; inherit (clan) nixosConfigurations clanInternals;

View File

@@ -14,5 +14,33 @@
''; '';
}; };
devShells.inventory-schema = pkgs.mkShell { inputsFrom = [ config.packages.inventory-schema ]; }; devShells.inventory-schema = pkgs.mkShell { inputsFrom = [ config.packages.inventory-schema ]; };
checks.inventory-schema-checks = pkgs.stdenv.mkDerivation {
name = "inventory-schema-checks";
src = ./src;
buildInputs = [ pkgs.cue ];
buildPhase = ''
echo "Running inventory tests..."
echo "Export cue as json-schema..."
cue export --out openapi root.cue
echo "Validate test/*.json against inventory-schema..."
test_dir="test"
for file in "$test_dir"/*; do
# Check if the item is a file
if [ -f "$file" ]; then
# Print the filename
echo "Running test on: $file"
# Run the cue vet command
cue vet "$file" root.cue -d "#Root"
fi
done
touch $out
'';
};
}; };
} }

View File

@@ -1,34 +0,0 @@
{
"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

@@ -1,8 +1,20 @@
package machines package machines
#ServiceRole: "server" | "client" | "both"
#machine: machines: [string]: { #machine: machines: [string]: {
"name": string, name: string,
"description": string, description?: string,
"icon": string, icon?: string,
"system": string // each machines service
services?: [string]: {
// Roles if specificed must contain one or more roles
// If no roles are specified, the service module defines the default roles.
roles?: [ ...#ServiceRole ],
// The service config to use
// This config is scoped to the service.module, only serializable data (strings,numbers, etc) can be assigned here
config: {
...
}
}
} }

View File

@@ -3,7 +3,6 @@ package inventory
import ( import (
"clan.lol/inventory/services" "clan.lol/inventory/services"
"clan.lol/inventory/machines" "clan.lol/inventory/machines"
"clan.lol/inventory/users"
) )
@jsonschema(schema="http://json-schema.org/schema#") @jsonschema(schema="http://json-schema.org/schema#")
@@ -12,9 +11,9 @@ import (
// A name of the clan (primarily shown by the UI) // A name of the clan (primarily shown by the UI)
name: string name: string
// A description of the clan // A description of the clan
description: string description?: string
// The icon path // The icon path
icon: string icon?: string
} }
// A map of services // A map of services
@@ -22,7 +21,4 @@ import (
// A map of machines // A map of machines
machines.#machine machines.#machine
// A map of users
users.#user
} }

View File

@@ -1,21 +1,30 @@
package services package services
#service: services: [string]: { #service: services: [string]: {
autoIncludeMachines: bool, // Required meta fields
meta: { meta: {
name: string, name: string,
icon?: string
description?: string,
}, },
// TODO: this should be the list of avilable modules // Required module specifies the behavior of the service.
module: string, module: string,
machineConfig: {
[string]: { // We moved the machine sepcific config to "machines".
// It may be moved back depending on what makes more sense in the future.
// machineConfig: {
// [string]: {
// roles: string[],
// config: {
// defaultUser?: string
// }
// }
// },
// Configuration for the service
config: { config: {
defaultUser?: string // Schema depends on the module.
} // It declares the interface how the service can be configured.
} ...
},
globalConfig: {
// Should be one of the avilable users
defaultUser?: string,
} }
} }

View File

@@ -0,0 +1,58 @@
{
"machines": {
"jon_machine": {
"name": "jon",
"description": "Jon's machine",
"icon": "assets/icon.png",
"services": {
"matrix": {
"roles": ["server"]
}
}
},
"anna_machine": {
"name": "anna",
"description": "anna's machine"
}
},
"meta": {
"name": "clan name"
},
"services": {
"sync-home": {
"meta": {
"name": "My Home Sync"
},
"module": "syncthing",
"config": {
"folders": ["/sync/my_f"]
}
},
"matrix": {
"meta": {
"name": "Our matrix chat",
"description": "Matrix chat service for our clan"
},
"module": "matrix-synapse",
"config": {
"compression": "zstd"
}
},
"backup": {
"meta": {
"name": "My daily backup"
},
"module": "borgbackup",
"config": {}
},
"borgbackup_1": {
"meta": {
"name": "My weekly backup"
},
"module": "borgbackup",
"config": {
"compression": "lz4"
}
}
}
}

View File

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