From 91661da3201ff34417e88bae083d9103eb3b4e0d Mon Sep 17 00:00:00 2001 From: hsjobeki Date: Mon, 10 Feb 2025 03:42:44 +0000 Subject: [PATCH] revert 283aad7ea02e7ca9d42c3775f36339e3b80bd407 revert ADR: init clanModules architecture decision --- decisions/01-ClanModules.md | 181 ------------------------------------ 1 file changed, 181 deletions(-) delete mode 100644 decisions/01-ClanModules.md diff --git a/decisions/01-ClanModules.md b/decisions/01-ClanModules.md deleted file mode 100644 index f132fc9ef..000000000 --- a/decisions/01-ClanModules.md +++ /dev/null @@ -1,181 +0,0 @@ -# Interface for module authors - -Status: proposed - -## Context - -ClanModules define cross `machine` `services`. -Services can be `instantiated` multiple times. -To make configuration more natural each service instance has multiple `roles` (.i.e. `client` `server`) - -Overall this makes it a 4-Dimensional problem where n-`machines` can have m-`services`, m-`services` can have k-`instances` and k-`instances` can have l-`roles`. - -### Problems - -Problems with the current way of writing clanModules. - -1. No way to retrieve the config of a single service instance - 2. -> We can't really support multiple instances even though the nix module *could* support multiple instances - 3. the "config" of a service MUST be evaluated against the "interface" outside of any machine. - -> Solution: evaluate each instance config and store it in seperate attributes -3. Can't merge multiple config instances -> Example: https://pad.lassul.us/i9uSspVbRUmiBmsJ8OR1ug# - -> Propsed change: feed the instance config into a helper that defines the merge behavior -5. Writing modules for multiple instances is cumbersome - -> Propsed change: Helper utility such as "perInstance" -6. No clearly separated, role based interface that is usable via json based APIs - 1. Currently we just import the module into a test machine and try to figure out what changes - -> Proposed change: enforce machine agnostic inventory interface definitions - -### Some immediate ideas - -#### simple idea - -Just use another nested attribute set - -- `clan.something.borgbackup.instance1 = config` -- `clan.something.borgbackup.instance1 = config` - -Problems solved: - -- each instance has its own config - -Problems not solved: - -- Machine independent seperated interface -- Still cumbersome to merge the instances -- Unclear how to get to each config because the interface also depends on the role - -#### Improved Idea - -- PerInstance: utility that maps over all instances and defines what needs to be set for each instance and receives the instanceConfig as argument. -- GlobalConfig: Some stuff that needs to be set statically on a machine if the service is enabled. - -## Proposed Change - -Change the ClanModule interface - -`client.nix` -```nix -{ - # Allows backwards compatibility - _class = "clan"; - - # Allows importing other service modules - module.zerotier = { - # function that receives each instance along with its config and resolved roles - perInstance = - { - # serviceConfig is the config of this instance - # as described in interface attribute below. - # Merged without differing priority: - # service..config - # + role..config - # + machine..config - serviceConfig, - # : string - instanceName, - # machine :: { name :: string , roles :: listOf string; } - machine, - # : { {roleName} :: { machines :: listOf string; } } - roles, - ... }: - { - nixosModule = { - config.debug."${instanceName}-client" = serviceConfig; - }; - }; - # Function that is appplied once for this role - perService = { - nixosModule = - { lib, ... }: - { - # Some shared code should be put into a shared file - # Which is then imported into all/some roles - imports = [ - ../shared.nix - ]; - options.debug = lib.mkOption { - type = lib.types.attrsOf lib.types.raw; - }; - }; - }; - - # Describes the settings how a `client` can be configured. - # These are the `options` of serviceConfig of a `client`. (Since: This file is called client.nix) - interface = - { lib, ... }: - { - options.foo = lib.mkOption { - type = lib.types.str; - default = "bar"; - }; - }; - }; -} -``` - -## Not Changed! (existing inventory.services for api configuration of clanModules) - -```nix -{ - inventory.services = { - test."instance1" = { - roles.client.tags = [ "all" ]; - machines.foo.config = { ... }; - roles.client.config = { ... }; - - }; - test."instance2" = { - roles.server.tags = [ "all" ]; - config = { ... }; - }; - }; -} -``` - -We don't propse to change anything here. Because we had no problems with that interface yet. -We even like it because it is very fast to evaluate and can be configured via UI. - -### Example of borgbackup before and after - -```nix -# client.nix (BEFORE) -{config, ...}: -let - instances = config.clan.inventory.services.borgbackup or { }; - # 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; - - machineName = config.clan.core.settings.machine.name; - - cfg = config.clan.borgbackup; -in -{ -# ... Some nixos config -} -``` - -```nix -# client.nix (AFTER) -{ - _class = "clan"; - perInstance = {instanceName, serviceConfig, machine, roles }: { - # allServers => roles.server; - # machineName => machine.name; - # cfg => serviceConfig; - nixosModule = {config, ...}: { - # ...some nixos config - } - # Extendable. I.e. Instances can also define 'vars' or other things later. - }; -} -```