update inventory implementation
Some checks failed
buildbot/nix-build .#checks.aarch64-darwin.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-iso-installer Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-flash-installer Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-app-no-breakpoints Build done.
buildbot/nix-build .#checks.x86_64-linux.check-for-breakpoints Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-test-backup Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-deb Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-archlinux Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-flash-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-rpm Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-test-backup Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-age Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-e2fsprogs Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-bash Build done.
buildbot/nix-build .#checks.x86_64-linux.package-module-docs Build done.
buildbot/nix-build .#checks.x86_64-linux."clan-dep-python3.11-mypy" Build done.
buildbot/nix-build .#checks.x86_64-linux."clan-dep-python3.11-qemu" Build done.
buildbot/nix-build .#checks.x86_64-linux.container Build done.
buildbot/nix-build .#checks.x86_64-linux.treefmt Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-cli-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.deltachat Build done.
buildbot/nix-build .#checks.x86_64-linux.package-pending-reviews Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zt-tcp-relay Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zerotierone Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-fakeroot Build done.
buildbot/nix-build .#checks.x86_64-linux.renderClanOptions Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-git Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-nix Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-openssh Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-rsync Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-sops Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-test-backup Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-sshpass Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-tor Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-zbar Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-pytest-without-core Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-app-pytest Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-clan-cli Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-clan-app Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-apk Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-inventory-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-webview-ui Build done.
buildbot/nix-build .#checks.x86_64-linux.borgbackup Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-default Build done.
buildbot/nix-build .#checks.x86_64-linux.lib-jsonschema-example-valid Build done.
buildbot/nix-build .#checks.x86_64-linux.inventory-schema-checks Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-app Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-cli Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-ts-api Build done.
buildbot/nix-build .#checks.x86_64-linux.package-default Build done.
buildbot/nix-build .#checks.x86_64-linux.matrix-synapse Build done.
buildbot/nix-build .#checks.x86_64-linux.package-editor Build done.
buildbot/nix-build .#checks.x86_64-linux.package-impure-checks Build done.
buildbot/nix-build .#checks.x86_64-linux.package-inventory-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.package-merge-after-ci Build done.
buildbot/nix-build .#checks.x86_64-linux.module-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.package-moonlight-sunshine-accept Build done.
buildbot/nix-build .#checks.x86_64-linux.lib-jsonschema-nix-unit-tests Build done.
buildbot/nix-build .#checks.x86_64-linux.package-webview-ui Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zerotier-members Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.x86_64-linux.package-function-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.package-tea-create-pr Build done.
buildbot/nix-build .#checks.x86_64-linux.postgresql Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-flash-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.template-minimal Build done.
buildbot/nix-build .#checks.x86_64-linux.secrets Build done.
buildbot/nix-build .#checks.x86_64-linux.package-module-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.wayland-proxy-virtwl Build done.
buildbot/nix-build .#checks.x86_64-linux.package-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.zt-tcp-relay Build done.
buildbot/nix-build .#checks.x86_64-linux.package-deploy-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-install-test-ubuntu-22-04 Build done.
buildbot/nix-build .#checks.x86_64-linux.package-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-pytest-with-core Build done.
buildbot/nix-build .#checks.x86_64-linux.test-backups Build done.
checks / checks-impure (pull_request) Successful in 2m29s
buildbot/nix-build .#checks.x86_64-linux.flash Build done.
buildbot/nix-build .#checks.x86_64-linux.test-installation Build done.
buildbot/nix-eval Build done.

This commit is contained in:
Johannes Kirschbauer 2024-06-21 16:45:38 +02:00
parent 17d76ddfed
commit 681ba8fa3d
Signed by: hsjobeki
SSH Key Fingerprint: SHA256:vX3utDqig7Ph5L0JPv87ZTPb/w7cMzREKVZzzLFg9qU
14 changed files with 284 additions and 60 deletions

View File

@ -14,7 +14,7 @@ let
machine_name = config.clan.core.machineName; machine_name = config.clan.core.machineName;
in in
{ lib.warn "This module is deprecated use the service via the service interface instead." {
imports = [ ../borgbackup ]; imports = [ ../borgbackup ];
# imports = if myRole == "server" then [ ../borgbackup/roles/server.nix ]; # imports = if myRole == "server" then [ ../borgbackup/roles/server.nix ];
# Inventory / Interface.nix # Inventory / Interface.nix

View File

@ -1,2 +1,15 @@
Efficient, deduplicating backup program with optional compression and secure encryption. Efficient, deduplicating backup program with optional compression and secure encryption.
--- ---
## Roles
- Client
- Server
## Configuration
Configure target machines where the backups should be sent to through `targets`.
Configure machines that should be backed up either through `includeMachines`
which will exclusively add the included machines to be backed up, or through
`excludeMachines`, which will add every machine except the excluded machine to the backup.

View File

@ -0,0 +1,30 @@
{ config, lib, ... }:
let
instances = config.clan.inventory.borgbackup;
# roles = { ${role_name} :: { machines :: [string] } }
allServers = lib.foldlAttrs (
acc: _instanceName: instanceConfig:
acc
++ (
if builtins.elem machineName instanceConfig.roles.client.machines then
instanceConfig.roles.server.machines
else
[ ]
)
) [ ] instances;
inherit (config.clan.core) machineName;
in
{
config.clan.borgbackup.destinations =
let
destinations = builtins.map (serverName: {
name = serverName;
value = {
repo = "borg@${serverName}:/var/lib/borgbackup/${machineName}";
};
}) allServers;
in
(builtins.listToAttrs destinations);
}

View File

@ -0,0 +1,45 @@
{ config, lib, ... }:
let
clanDir = config.clan.core.clanDir;
machineDir = clanDir + "/machines/";
inherit (config.clan.core) machineName;
instances = config.clan.inventory.borgbackup;
# roles = { ${role_name} :: { machines :: [string] } }
allClients = lib.foldlAttrs (
acc: _instanceName: instanceConfig:
acc
++ (
if builtins.elem machineName instanceConfig.roles.server.machines then
instanceConfig.roles.client.machines
else
[ ]
)
) [ ] instances;
in
{
config.services.borgbackup.repos =
let
filteredMachines = allClients;
borgbackupIpMachinePath = machines: machineDir + machines + "/facts/borgbackup.ssh.pub";
machinesMaybeKey = builtins.map (
machine:
let
fullPath = borgbackupIpMachinePath machine;
in
if builtins.pathExists fullPath then machine else null
) filteredMachines;
machinesWithKey = lib.filter (x: x != null) machinesMaybeKey;
hosts = builtins.map (machine: {
name = machine;
value = {
path = "/var/lib/borgbackup/${machine}";
authorizedKeys = [ (builtins.readFile (borgbackupIpMachinePath machine)) ];
};
}) machinesWithKey;
in
if (builtins.listToAttrs hosts) != [ ] then builtins.listToAttrs hosts else { };
}

View File

@ -5,7 +5,7 @@
imports = [ ./disk-layouts ]; imports = [ ./disk-layouts ];
}; };
borgbackup = ./borgbackup; borgbackup = ./borgbackup;
borgbackup-static = ./borgbackup-static;
deltachat = ./deltachat; deltachat = ./deltachat;
ergochat = ./ergochat; ergochat = ./ergochat;
localbackup = ./localbackup; localbackup = ./localbackup;

View File

@ -3,19 +3,24 @@
The inventory is our concept for distributed services. Users can configure multiple machines with minimal effort. 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. - The inventory acts as a declarative source of truth for all machine configurations.
- Users can easily add or remove machines and services. - Users can easily add or remove machines to/from services.
- Ensures that all machines and services are configured consistently, across multiple nixosConfigs. - 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. - Defaults and predefined roles in our modules minimizes the need for manual configuration.
Design questions: 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 ?
- [x] Must roles be a list ? - [x] Must roles be a list ?
-> Yes. In zerotier you can be "moon" and "controller" at the same time. -> Yes. In zerotier a machine can be "moon" and "controller" at the same time.
- [x] Is role client different from peer ? Do we have one example where we use client and peer together and they are different? - [x] 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. -> There are many roles. And they depend on the service.
- [x] Should we use the module name in the path of the service? - [x] Should we use the module name in the path of the service?
-> YES
```json ```json
// ${module_name}.${instance_name} // ${module_name}.${instance_name}
services.borgbackup-static.backup1 = { services.borgbackup-static.backup1 = {
@ -32,8 +37,10 @@ Design questions:
Neutral: Module name is hard to change. Exists anyways. Neutral: Module name is hard to change. Exists anyways.
- [x] Should the machine specific service config be part of the service? - [x] Should the machine specific service config be part of the service?
-> The config implements the schema of the module, which is declared in the service. -> NO. because ...
-> If the config is placed in the machine, it becomes unclear that the scope is ONLY the service and NOT the global nixos config. - 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 Architecture

View File

@ -7,22 +7,25 @@ let
machines = machinesFromInventory syncthing_inventory; machines = machinesFromInventory syncthing_inventory;
resolveGroups = resolveTags =
inventory: members: # Inventory, { machines :: [string], tags :: [string] }
lib.unique ( inventory: members: {
builtins.foldl' ( machines =
acc: currMember: members.machines or [ ]
let ++ (builtins.foldl' (
groupName = builtins.substring 6 (builtins.stringLength currMember - 6) currMember; acc: tag:
groupMembers = let
if inventory.groups.machines ? ${groupName} then tagMembers = builtins.attrNames (
inventory.groups.machines.${groupName} lib.filterAttrs (_n: v: builtins.elem tag v.tags or [ ]) inventory.machines
else );
throw "Machine group ${currMember} not found. Key: groups.machines.${groupName} not in inventory."; in
in # throw "Machine tag ${tag} not found. Not machine with: tag ${tagName} not in inventory.";
if lib.hasPrefix "group:" currMember then (acc ++ groupMembers) else acc ++ [ currMember ] if tagMembers == [ ] then
) [ ] members throw "Machine tag ${tag} not found. Not machine with: tag ${tag} not in inventory."
); else
acc ++ tagMembers
) [ ] members.tags or [ ]);
};
/* /*
Returns a NixOS configuration for every machine in the inventory. Returns a NixOS configuration for every machine in the inventory.
@ -45,29 +48,53 @@ let
acc2: instanceName: serviceConfig: acc2: instanceName: serviceConfig:
let let
resolvedRoles = builtins.mapAttrs ( resolvedRoles = builtins.mapAttrs (
_roleName: members: resolveGroups inventory members _roleName: members: resolveTags inventory members
) serviceConfig.roles; ) serviceConfig.roles;
isInService = builtins.any (members: builtins.elem machineName members) ( isInService = builtins.any (members: builtins.elem machineName members.machines) (
builtins.attrValues resolvedRoles builtins.attrValues resolvedRoles
); );
# Inverse map of roles. Allows for easy lookup of roles for a given machine.
# { ${machine_name} :: [roles]
inverseRoles = lib.foldlAttrs (
acc: roleName:
{ machines }:
acc
// builtins.foldl' (
acc2: machineName: acc2 // { ${machineName} = (acc.${machineName} or [ ]) ++ [ roleName ]; }
) { } machines
) { } resolvedRoles;
machineServiceConfig = (serviceConfig.machines.${machineName} or { }).config or { }; machineServiceConfig = (serviceConfig.machines.${machineName} or { }).config or { };
globalConfig = serviceConfig.config; globalConfig = serviceConfig.config;
# TODO: maybe optimize this dont lookup the role in inverse roles. Imports are not lazy
roleModules = builtins.map (
role:
let
path = "${clan-core.clanModules.${moduleName}}/roles/${role}.nix";
in
if builtins.pathExists path then
path
else
throw "Role doesnt have a module: ${role}. Path: ${path} not found."
) inverseRoles.${machineName} or [ ];
in in
if isInService then if isInService then
acc2 acc2
++ [ ++ [
{ {
imports = [ clan-core.clanModules.${moduleName} ]; imports = [ clan-core.clanModules.${moduleName} ] ++ roleModules;
config.clan.${moduleName} = lib.mkMerge [ config.clan.${moduleName} = lib.mkMerge [
globalConfig globalConfig
machineServiceConfig machineServiceConfig
]; ];
} }
{ {
config.clan.inventory.${instanceName} = { config.clan.inventory.${moduleName}.${instanceName} = {
roles = resolvedRoles; roles = resolvedRoles;
# inherit inverseRoles;
}; };
} }
] ]
@ -78,8 +105,64 @@ let
) inventory.machines; ) inventory.machines;
in in
{ {
inherit clan-core;
new_clan = clan-core.lib.buildInventory {
# High level services.
# If you need multiple instances of a service configure them via:
# inventory.services.[serviceName].[instanceName] = ...
services = {
borbackup = {
roles.server.machines = [ "vyr" ];
roles.client.tags = [ "laptop" ];
machines.vyr = {
config = {
};
};
config = {
};
};
};
# Low level inventory i.e. if you need multiple instances of a service
# Or if you want to manipulate the created inventory directly.
inventory.services.borbackup.default = { };
# Machines. each machine can be referenced by its attribute name under services.
machines = {
camina = {
# This is added to machine tags
clan.tags = [ "laptop" ];
# These are the inventory machine fields
clan.meta.description = "";
clan.meta.name = "";
clan.meta.icon = "";
# Config ...
};
vyr = {
# Config ...
};
vi = {
clan.networking.targetHost = "root@78.47.164.46";
# Config ...
};
aya = {
clan.networking.targetHost = "root@78.47.164.46";
# Config ...
};
ezra = {
# Config ...
};
rianon = {
# Config ...
};
};
};
clan = clan-core.lib.buildClan { clan = clan-core.lib.buildClan {
meta.name = "vis clans"; meta.name = "vi's clans";
# Should usually point to the directory of flake.nix # Should usually point to the directory of flake.nix
directory = self; directory = self;

View File

@ -20,6 +20,4 @@ import (
// // A map of machines // // A map of machines
schema.#machine schema.#machine
schema.#groups
} }

View File

@ -1,18 +1,10 @@
package schema package schema
#groups: groups: {
// Machine groups
machines: {
// Group name mapped to list[machineName]
// "group1": ["machine1", "machine2"]
[string]: [...string]
}
}
#machine: machines: [string]: { #machine: machines: [string]: {
name: string, name: string,
description?: string, description?: string,
icon?: string icon?: string
tags: [...string]
} }
#role: string #role: string
@ -26,7 +18,10 @@ package schema
}, },
// We moved the machine sepcific config to "machines". // We moved the machine sepcific config to "machines".
// It may be moved back depending on what makes more sense in the future. // It may be moved back depending on what makes more sense in the future.
roles: [#role]: [...string], roles: [#role]: {
machines: [...string],
tags: [...string],
}
machines: { machines: {
[string]: { [string]: {
config?: { config?: {

View File

@ -1,39 +1,51 @@
{ {
"machines": { "machines": {
"camina_machine": { "camina_machine": {
"name": "camina" "name": "camina",
"tags": ["laptop"]
}, },
"vyr_machine": { "vyr_machine": {
"name": "vyr" "name": "vyr"
}, },
"vi_machine": { "vi_machine": {
"name": "vi" "name": "vi",
} "tags": ["laptop"]
},
"groups": {
"machines": {
"laptops": ["camina_machine", "vi_machine"],
"all": ["camina_machine", "vi_machine", "vyr_machine"]
} }
}, },
"meta": { "meta": {
"name": "kenjis clan" "name": "kenjis clan"
}, },
"services": { "services": {
"borgbackup-static": { "borgbackup": {
"instance_1": { "instance_1": {
"meta": { "meta": {
"name": "My backup" "name": "My backup"
}, },
"roles": { "roles": {
"server": ["vyr_machine"], "server": {
"client": ["group:laptops"] "machines": ["vyr_machine"]
},
"client": {
"machines": ["vyr_machine"],
"tags": ["laptop"]
}
}, },
"machines": { "machines": {},
"vyr_machine": {}, "config": {}
"vi_machine": {}, },
"camina_machine": {} "instance_2": {
"meta": {
"name": "My backup"
}, },
"roles": {
"server": {
"machines": ["vi_machine"]
},
"client": {
"machines": ["camina_machine"]
}
},
"machines": {},
"config": {} "config": {}
} }
} }

View File

@ -14,13 +14,15 @@
"name": "kenjis clan" "name": "kenjis clan"
}, },
"services": { "services": {
"syncthing-static-peers": { "syncthing": {
"instance_1": { "instance_1": {
"meta": { "meta": {
"name": "My sync" "name": "My sync"
}, },
"roles": { "roles": {
"peer": ["vyr_machine", "vi_machine", "camina_machine"] "peer": {
"machines": ["vyr_machine", "vi_machine", "camina_machine"]
}
}, },
"machines": {}, "machines": {},
"config": { "config": {

View File

@ -14,14 +14,15 @@
"name": "kenjis clan" "name": "kenjis clan"
}, },
"services": { "services": {
"zerotier-static": { "zerotier": {
"instance_1": { "instance_1": {
"meta": { "meta": {
"name": "My Network" "name": "My Network"
}, },
"roles": { "roles": {
"server": ["vyr_machine"], "controller": { "machines": ["vyr_machine"] },
"peer": ["vi_machine", "camina_machine"] "moon": { "machines": ["vyr_machine"] },
"peer": { "machines": ["vi_machine", "camina_machine"] }
}, },
"machines": { "machines": {
"vyr_machine": { "vyr_machine": {

View File

@ -14,5 +14,7 @@
./vm.nix ./vm.nix
./wayland-proxy-virtwl.nix ./wayland-proxy-virtwl.nix
./zerotier ./zerotier
# Inventory
./inventory/interface.nix
]; ];
} }

View File

@ -0,0 +1,36 @@
{ lib, ... }:
let
# {
# roles = {
# client = {
# machines = [
# "camina_machine"
# "vi_machine"
# ];
# };
# server = {
# machines = [ "vyr_machine" ];
# };
# };
# }
instanceOptions = lib.types.submodule {
options.roles = lib.mkOption { type = lib.types.attrsOf machinesList; };
};
# {
# machines = [
# "camina_machine"
# "vi_machine"
# "vyr_machine"
# ];
# }
machinesList = lib.types.submodule {
options.machines = lib.mkOption { type = lib.types.listOf lib.types.str; };
};
in
{
# clan.inventory.${moduleName}.${instanceName} = { ... }
options.clan.inventory = lib.mkOption {
type = lib.types.attrsOf (lib.types.attrsOf instanceOptions);
};
}