clan-core/inventory
2024-06-25 12:23:29 +00:00
..
src update inventory implementation 2024-06-25 12:23:29 +00:00
.envrc Inventory: init draft ideas 2024-06-19 09:40:23 +02:00
default.nix Extend build-clan interface 2024-06-25 12:23:29 +00:00
flake-module.nix schema improvements 2024-06-25 12:23:29 +00:00
README.md inventory: rename clan.services 2024-06-25 12:23:29 +00:00

Inventory

The inventory is our concept for distributed services. Users can configure multiple machines with minimal effort.

  • The inventory acts as a declarative source of truth for all machine configurations.
  • Users can easily add or remove machines to/from services.
  • Ensures that all machines and services are configured consistently, across multiple nixosConfigs.
  • Defaults and predefined roles in our modules minimizes the need for manual configuration.

Design questions:

  • Is the service config interface the same as the module config interface ?

  • As a user i dont want to see borgbackup as the high level category ?

  • Must roles be a list ? -> Yes. In zerotier a machine can be "moon" and "controller" at the same time.

  • Is role client different from peer ? Do we have one example where we use client and peer together and they are different? -> There are many roles. And they depend on the service.

  • Should we use the module name in the path of the service? -> YES

    // ${module_name}.${instance_name}
    services.borgbackup-static.backup1 = {
    
    }
    

    Pro: Easier to handle. Better groups the module specific instances. Contra: More nesting in json

    Neutral: Module name is hard to change. Exists anyways.

  • Should the machine specific service config be part of the service? -> NO. because ...

    • The config implements the schema of the module, which is declared in the service.
    • If the config is placed in the machine, it becomes unclear that the scope is ONLY the service and NOT the global nixos config.
    • If the config is placed in the machine it is de-located into another top-level field. In the module this complicates access.

Architecture

nixosConfig < machine_module        < inventory
---------------------------------------------
nixos   < borgbackup            <- inventory <-> UI

        creates the config      Maps from high level services to the borgbackup clan module
        for ONE machine         Inventory is completely serializable.
                                UI can interact with the inventory to define machines, and services
                                Defining Users is out of scope for the first prototype.
  • Why do we need 2 modules? -> It is technically possible to have only 1 module. Pros: Simple to use/Easy to understand. Less modules Cons: Harder to write a module. Because it must do 2 things. One module should do only 1 thing.
clan.machines.${machine_name} = {
    # "borgbackup.ssh.pub" = machineDir + machines + "/facts/borgbackup.ssh.pub";
    facts = ...
};
clan.services.${instance} = {
#   roles.server = [ "jon_machine" ]
#   roles.${role_name} = [ ${machine_name} ];
};

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.

// 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.

foo: { ... }

Cue dynamic keys.

[string]: {
    attr: string
}

This is the schema of

{
    "a": {
        "attr": "foo"
    },
    "b": {
        "attr": "bar"
    }
    // ... Indefinitely more dynamic keys of type "string"
}