From 13aa60529f8cfa06388b383b29afc22bb9a66af0 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Sat, 15 Jun 2024 13:41:51 +0200 Subject: [PATCH] Inventory: init draft ideas --- inventory/.vscode/settings.json | 6 - inventory/example_flake.nix | 216 +++++++++++++++------------ inventory/flake-module.nix | 28 ++++ inventory/inventory.json | 34 ----- inventory/src/machines/machines.cue | 20 ++- inventory/src/root.cue | 8 +- inventory/src/services/services.cue | 35 +++-- inventory/src/tests/1_inventory.json | 58 +++++++ inventory/src/users/users.cue | 9 -- 9 files changed, 243 insertions(+), 171 deletions(-) delete mode 100644 inventory/.vscode/settings.json delete mode 100644 inventory/inventory.json create mode 100644 inventory/src/tests/1_inventory.json delete mode 100644 inventory/src/users/users.cue diff --git a/inventory/.vscode/settings.json b/inventory/.vscode/settings.json deleted file mode 100644 index 82a476e3..00000000 --- a/inventory/.vscode/settings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "cue.toolsPath": "/nix/store/x9471mp522cdi4c9gc8dchvyx6v01b3f-cue-0.8.2/bin/cue", - "[cue]": { - "editor.formatOnSave": false - } -} \ No newline at end of file diff --git a/inventory/example_flake.nix b/inventory/example_flake.nix index b6f7fca6..11be13a7 100644 --- a/inventory/example_flake.nix +++ b/inventory/example_flake.nix @@ -7,107 +7,125 @@ { 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@ - # # 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 = [ "" ] - # ''; - # # 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 + # Usage see: https://docs.clan.lol + # nice_flake_interface -> buildInventory() -> Inventory -> buildClanFromInventory() -> nixosConfigurations + # buildClanFromInventory = inventory: evalModules { + # 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@ + # # # 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 = [ "" ] + # # ''; + # # # 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"; + # } + # ]; + # # buildClan :: [ Partial ] -> Inventory + # # foldl' (acc: v: lib.recursiveUpdate acc v) {} [] + # inventory = [ + # # import json + # {...} + # # power user flake + # {...} + # ] + # # With Module system + # # Pros: Easy to understand, + # # Cons: Verbose, hard to maintain + # # buildClan :: { modules = [ { config = Partial; options :: InventoryOptions; } } ]; } -> Inventory + # eval = lib.evalModules { + # modules = [ + # { + # # Inventory Schema + # # Python validation + # options = {...} + # } + # { + # config = map lib.mkDefault + # (builtins.fromJSON (builtins.readFile ./inventory.json)) + # } + # { + # # User provided + # config = {...} + # } + # # 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 + + buildInventory :: { + clanName :: string + machines :: { + ${name} :: { + config :: { + # NixOS configuration + }; + }; + }; + # ... More mapped inventory options + # i.e. shared config for all machines + } -> Inventory + */ { # all machines managed by Clan inherit (clan) nixosConfigurations clanInternals; diff --git a/inventory/flake-module.nix b/inventory/flake-module.nix index 4519f8e2..65c6c66f 100644 --- a/inventory/flake-module.nix +++ b/inventory/flake-module.nix @@ -14,5 +14,33 @@ ''; }; 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 + ''; + }; }; } diff --git a/inventory/inventory.json b/inventory/inventory.json deleted file mode 100644 index 0ee272e7..00000000 --- a/inventory/inventory.json +++ /dev/null @@ -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" - } - } - } -} diff --git a/inventory/src/machines/machines.cue b/inventory/src/machines/machines.cue index 36d77e37..cdbeed5f 100644 --- a/inventory/src/machines/machines.cue +++ b/inventory/src/machines/machines.cue @@ -1,8 +1,20 @@ package machines +#ServiceRole: "server" | "client" | "both" + #machine: machines: [string]: { - "name": string, - "description": string, - "icon": string, - "system": string + name: string, + description?: string, + icon?: 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: { + ... + } + } } \ No newline at end of file diff --git a/inventory/src/root.cue b/inventory/src/root.cue index c3b7496a..3034dab8 100644 --- a/inventory/src/root.cue +++ b/inventory/src/root.cue @@ -3,7 +3,6 @@ package inventory import ( "clan.lol/inventory/services" "clan.lol/inventory/machines" - "clan.lol/inventory/users" ) @jsonschema(schema="http://json-schema.org/schema#") @@ -12,9 +11,9 @@ import ( // A name of the clan (primarily shown by the UI) name: string // A description of the clan - description: string + description?: string // The icon path - icon: string + icon?: string } // A map of services @@ -22,7 +21,4 @@ import ( // A map of machines machines.#machine - - // A map of users - users.#user } diff --git a/inventory/src/services/services.cue b/inventory/src/services/services.cue index c24ef69f..b95e117f 100644 --- a/inventory/src/services/services.cue +++ b/inventory/src/services/services.cue @@ -1,21 +1,30 @@ package services #service: services: [string]: { - autoIncludeMachines: bool, + // Required meta fields meta: { 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, - machineConfig: { - [string]: { - config: { - defaultUser?: string - } - } - }, - globalConfig: { - // Should be one of the avilable users - defaultUser?: 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: { + // Schema depends on the module. + // It declares the interface how the service can be configured. + ... } -} \ No newline at end of file +} diff --git a/inventory/src/tests/1_inventory.json b/inventory/src/tests/1_inventory.json new file mode 100644 index 00000000..58347d2d --- /dev/null +++ b/inventory/src/tests/1_inventory.json @@ -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" + } + } + } +} diff --git a/inventory/src/users/users.cue b/inventory/src/users/users.cue deleted file mode 100644 index bdd54067..00000000 --- a/inventory/src/users/users.cue +++ /dev/null @@ -1,9 +0,0 @@ -package users - -#user: users: [string]: { - "autoInclude": bool, - "schemas": [ string ], - "config": { - ... - } -} \ No newline at end of file