Compare commits

...

148 Commits

Author SHA1 Message Date
Jörg Thalheim
11bd629597 generate-test-vars: also precache finalScript 2025-06-28 08:58:45 +02:00
Jörg Thalheim
f28b5a4760 generate-test-vars: fix entrypoint 2025-06-28 08:50:41 +02:00
Jörg Thalheim
43df2c9a14 fix unlocked flake.lock in tests 2025-06-28 08:50:41 +02:00
Jörg Thalheim
65ee951b72 select: drop unused --impure flag 2025-06-27 19:30:45 +02:00
Jörg Thalheim
b251275063 select: use nix_options copy 2025-06-27 19:30:45 +02:00
Jörg Thalheim
6afe4305b4 select: drop unused nixpkgs fallback 2025-06-27 19:30:45 +02:00
Jörg Thalheim
553d13b05a don't keep appending --impure to nix_options when running tests 2025-06-27 18:54:13 +02:00
Jörg Thalheim
6ab5171b5b add restricted network nixos modules
See README.md for explanation
2025-06-27 18:44:17 +02:00
Jörg Thalheim
e152740017 container-test-driver: implement wait_for_open_port 2025-06-27 18:35:55 +02:00
Jörg Thalheim
bc3ba8eeff markdown: ignore trailing whitespace 2025-06-27 16:26:39 +02:00
Mic92
5d5bb32970 Merge pull request 'select: disable remote building and substitution' (#4123) from speed-up-flake-select into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4123
2025-06-27 12:00:18 +00:00
Jörg Thalheim
3035752d00 select: disable remote building and substitution
this should make things faster since the derivation itself is trivial.
2025-06-27 13:37:16 +02:00
kenji
0799c72095 Merge pull request 'modules/zerotier: Fix typo in documentation' (#4121) from kenji/ke-fix-zerotier-typo into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4121
2025-06-27 11:24:28 +00:00
kenji
b5ef05f9ad Merge pull request 'modules/users: Fix the password deployment' (#4113) from kenji/ke-fix-user-password-service into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4113
2025-06-27 11:20:59 +00:00
kenji
a624cb34ee Merge pull request 'pkgs/clan: Add machine validator with suggestion logic' (#4112) from ke-machines-update into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4112
2025-06-27 11:09:05 +00:00
a-kenji
c0d4db6a8d modules/zerotier: Fix typo in documentation 2025-06-27 12:58:59 +02:00
kenji
a88f3e21a6 Merge pull request 'pkgs/clan: Improve error message on clan secrets users add' (#4095) from kenji/ke-clan-age-key-error into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4095
Reviewed-by: brianmcgee <brian@bmcgee.ie>
2025-06-27 10:52:16 +00:00
a-kenji
e248b1f551 modules/users: Fix the password deployment
The password needs to be available prior to logging in,
this is why we need to set `neededFor = users`.
2025-06-27 12:48:15 +02:00
kenji
89e8673e82 Merge pull request 'lib/test/sops: Fix secret deployment for test machines' (#4120) from kenji/ke-fix-sops-test-integration into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4120
2025-06-27 10:45:41 +00:00
a-kenji
3e70e30b6b pkgs/clan: Add machine validator with suggestion logic
Add machine validator with suggestion logic to:
- `clan machines update`
- `clan machines delete`
- `clan machines update-hardware-config`
2025-06-27 12:32:36 +02:00
a-kenji
0a56f60005 lib/test/sops: Fix secret deployment for test machines
Fix secret deployment for test machines in our NixOS vm and container
tests.

We filter now if we really need to deploy a certain set of files as a
deployment script, which alleviates us running into these edgecases:
```
error: The option `nodes.server.system.activationScripts.setupSecrets.text'
was accessed but has no value defined. Try setting the option.
```
2025-06-27 12:19:46 +02:00
hsjobeki
9de5b97802 Merge pull request 'modules/clan: consistent logic for auto injecting nixpkgs, nix-darwin' (#4117) from hsjobeki/fix-clan.nix into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4117
2025-06-27 08:35:01 +00:00
Johannes Kirschbauer
8789ebeb59 modules/clan: consistent logic for auto injecting nixpkgs, nix-darwin
We want to make them options this is a temporary fix
2025-06-27 10:23:53 +02:00
hsjobeki
6f1a5286db Merge pull request 'Fix(clan-module): pass clan-core not a module' (#4116) from hsjobeki/fix-clan.nix into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4116
2025-06-27 08:21:44 +00:00
Johannes Kirschbauer
7372063579 Fix(clan-module): pass clan-core not a module 2025-06-27 10:13:58 +02:00
hsjobeki
c3c9a8d082 Merge pull request 'modules: add explizit class to clan module' (#4115) from hsjobeki/buildClan into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4115
2025-06-27 08:13:54 +00:00
Johannes Kirschbauer
d011b1ab02 docs: rename all references from 'buildClan' to 'lib.clan' 2025-06-27 09:54:23 +02:00
Johannes Kirschbauer
b34e5b30e5 modules: add explizit class to clan module 2025-06-27 09:53:40 +02:00
hsjobeki
b1376f2669 Merge pull request 'buildClan: deprecate in favor of 'clan'' (#4111) from hsjobeki/buildClan into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4111
2025-06-27 07:29:32 +00:00
Johannes Kirschbauer
79ec0f07eb modules: fix consistent nixpkgs and nix-darwin injection 2025-06-27 09:21:19 +02:00
Johannes Kirschbauer
7833a56723 modules.nixosVmTest: rename to nixosTest to match the target module _class 2025-06-26 17:37:42 +02:00
Johannes Kirschbauer
50f6b4a095 modules.clan.default: move specialArgs into common place 2025-06-26 17:37:42 +02:00
Johannes Kirschbauer
e195a77476 buildClan: deprecate in favor of 'clan'
clan.lib.clan { <your definition> } returns an eval result
In contrast to buildClan which returns the .config
This allows for better introspection
2025-06-26 17:08:47 +02:00
Johannes Kirschbauer
0271af0dcb modules: move clan module to flake.modules.clan.default 2025-06-26 17:08:47 +02:00
Johannes Kirschbauer
cfce6d9845 flake-parts: enable modules feature 2025-06-26 17:08:47 +02:00
hsjobeki
6929700c77 Merge pull request 'chore: clean up logic around clanInternals' (#4110) from hsjobeki/buildClan into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4110
2025-06-26 14:21:59 +00:00
Johannes Kirschbauer
7d755d04b5 chore: clean up logic around clanInternals 2025-06-26 16:12:35 +02:00
pinpox
4f8421def0 Merge pull request 'Fix machine-id on macos' (#4109) from fix-mac-machine-id into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4109
2025-06-26 13:57:19 +00:00
hsjobeki
0cabce6e5f Merge pull request 'chore: buildClan warn access without .config prefix' (#4108) from hsjobeki/buildClan into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4108
2025-06-26 13:39:39 +00:00
pinpox
264b010a89 Fix machine-id on macos 2025-06-26 15:35:34 +02:00
hsjobeki
28147fb5d5 Merge pull request 'refactor: unify evalClanService with evalService' (#4106) from hsjobeki/eval service into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4106
2025-06-26 13:22:03 +00:00
Johannes Kirschbauer
a95d39923e chore: buildClan warn access without .config prefix
Makes behavior consistent with nixosSystem, nixpkgs.
Alows access to options and other eval modules results
Needed for error tracking and better devx
2025-06-26 15:21:49 +02:00
Johannes Kirschbauer
acaf44e2c5 chore: remove spurious class 2025-06-26 15:20:18 +02:00
Johannes Kirschbauer
e77769bd20 refactor: clanLib buildClan 2025-06-26 15:20:05 +02:00
Johannes Kirschbauer
11a94893fb refactor: unify evalClanService with evalService 2025-06-26 14:50:35 +02:00
hsjobeki
c079d6b65f Merge pull request 'refactor: simplify buildClan remove any filtering' (#4105) from hsjobeki/buildClan into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4105
2025-06-26 12:04:37 +00:00
Johannes Kirschbauer
1568950410 refactor: simplify buildClan remove any filtering 2025-06-26 13:56:14 +02:00
hsjobeki
5ae6636126 Merge pull request 'refactor: clan expose the clan module as is' (#4101) from hsjobeki/clan into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4101
2025-06-26 11:44:24 +00:00
Johannes Kirschbauer
6c460db016 schema: update clan option source 2025-06-26 13:24:34 +02:00
renovate[bot]
47b338f539 Update data-mesher digest to 32b1ff6 2025-06-26 10:50:17 +00:00
renovate[bot]
f314fbb1b9 Update treefmt-nix digest to ac8e6f3 2025-06-26 10:30:17 +00:00
Johannes Kirschbauer
9196de993d feat(darwinModules): add module location analog to flake-parts 2025-06-26 11:55:55 +02:00
Johannes Kirschbauer
fcd2124936 refactor: clan expose the clan module as is 2025-06-26 11:47:53 +02:00
hsjobeki
06711a09c5 Merge pull request 'inventory.json: remove all services from local inventory' (#4100) from clan-unify into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4100
2025-06-26 09:45:04 +00:00
Johannes Kirschbauer
2f5793a2bc inventory.json: remove all services from local inventory 2025-06-26 11:28:33 +02:00
hsjobeki
76e8cf10cb Merge pull request 'Refactor(build-inventory): remove build-inventory in favor of simple and expressive evalModules' (#4097) from clan-unify into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4097
2025-06-26 09:27:55 +00:00
Johannes Kirschbauer
a01ece8742 Refactor(build-inventory): remove build-inventory in favor of simple and expressive evalModules 2025-06-26 11:11:50 +02:00
pinpox
a37bdd9fac Merge pull request 'Add deprecation warnings to all clanModules' (#4098) from all-deprecations into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4098
2025-06-26 08:43:55 +00:00
pinpox
0b459f64e6 Add deprecation warnings to all clanModules 2025-06-26 10:35:47 +02:00
renovate[bot]
e09deaf42c Update disko digest to 83c4da2 2025-06-26 02:50:17 +00:00
hsjobeki
4ea7a10a79 Merge pull request 'importer: Fix the documentation for the importer service' (#4062) from kenji/importer: Fix the documentation for the importer service into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4062
Reviewed-by: hsjobeki <hsjobeki@gmail.com>
2025-06-25 16:30:04 +00:00
hsjobeki
1955a8171e Merge pull request 'build-inventory: refactor into seperate folders and explizit submodule' (#4094) from clan-unify into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4094
2025-06-25 16:23:58 +00:00
Johannes Kirschbauer
0bb5ed923e build-inventory: fix tests temporarily 2025-06-25 18:15:47 +02:00
Johannes Kirschbauer
c91b5fb3db build-inventory: move inventory and inventoryClass into explizitly different folders 2025-06-25 17:55:45 +02:00
a-kenji
6188583885 pkgs/clan: Improve error message on clan secrets users add
Improve error message on `clan secrets users add [user] --age-key
`AGE-PLUGIN-YUBIKEY`

Since there is no way to get the recipient through the AGE-PLUGIN-YUBIKEY,
we should fail fast and give an actionable error to the user.
2025-06-25 17:30:59 +02:00
Johannes Kirschbauer
68ed393c87 build-inventory: replace by equivalent submodule 2025-06-25 17:23:46 +02:00
hsjobeki
af27f43491 Merge pull request 'inventory/interface: reduce apply arguments chain by adding options' (#4092) from clan-unify into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4092
2025-06-25 14:41:55 +00:00
Johannes Kirschbauer
16392622c5 Chore: add _file for internals error tracing 2025-06-25 15:47:18 +02:00
Johannes Kirschbauer
1819243123 inventory/interface: reduce apply arguments chain by adding it to _module.args 2025-06-25 15:15:22 +02:00
kenji
4204381edc Merge pull request 'pkgs/agit: Pre-fill the editor with commit messages' (#4083) from kenji/pkgs/agit: Pre-fill the editor with commit messages into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4083
2025-06-25 10:52:22 +00:00
kenji
4e35ab2e47 Merge pull request 'pkgs/agit: Autofill AGit topic based on the current branch name' (#4091) from kenji/ke-topic-name-from-branch into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4091
2025-06-25 10:47:44 +00:00
a-kenji
332f844ec6 pkgs/agit: Autofill AGit topic based on the current branch name
This makes it more likely that AGit topics are compatible with git
commands.
2025-06-25 12:32:32 +02:00
hsjobeki
a4bcaa8854 Merge pull request 'build-clan: always use a single entry point' (#4089) from clan-unify into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4089
2025-06-25 10:28:50 +00:00
Johannes Kirschbauer
d0ae75e5cc build-clan: export default.nix that injects clanLib
This should be the single entry point, that includes clanLib
instead of importApply propagation
2025-06-25 12:07:59 +02:00
kenji
ed7162635b Merge pull request 'pkgs/clan-cli: Fix typo in sshd test' (#4088) from kenji/pkgs/clan-cli: Fix typo in sshd test into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4088
2025-06-25 10:00:06 +00:00
Johannes Kirschbauer
aa96a11369 build-clan: move clan attribute relates modules into subfolder 2025-06-25 10:55:37 +02:00
hsjobeki
3e030a5199 Merge pull request 'build-clan: move clan attribute relates modules into subfolder' (#4063) from clan-unify into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4063
2025-06-25 08:46:18 +00:00
a-kenji
b14a15407c pkgs/clan-cli: Fix typo in sshd test 2025-06-25 10:13:06 +02:00
DavHau
d1163bc2c5 Merge pull request 'docs: add clan options search page' (#4077) from davhau/docs: add clan options search page into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4077
2025-06-25 06:56:55 +00:00
DavHau
75ce3fcb84 nuschtos: fix flake dependencies crashing tests 2025-06-25 13:48:50 +07:00
DavHau
9299c83822 bring back services rendering for docs
Setting services to visible = false breaks stuff
2025-06-25 13:48:50 +07:00
DavHau
2b73671f18 docs/devshell: unbreak - add options-page
Create the options-page subpage when the docs dev shell is loaded.

Also simplify the dev shell definition by just utilizing what's in configurePhase of the docs derivation
2025-06-25 13:48:50 +07:00
DavHau
4421ce006e docs: add clan options search page
This provides a simpler and more intuitive search over a flat list of possible options.

Styling still to be improved
2025-06-25 12:55:25 +07:00
DavHau
ae1a139818 nix_modules: generate clan.py in top-level shell
Generally I don't think dev shells are the right place to trigger generation of files.
This should be part of the formatter and pre-commit hook

@hsjobeki
2025-06-25 12:33:36 +07:00
a-kenji
c6dce03c58 pkgs/agit: Pre-fill the editor with commit messages
Pre-fill the editor with commit messages for the AGit PR.
2025-06-25 01:56:46 +02:00
Luis Hebendanz
b1dcef4862 Merge pull request 'clan-app: Add a 'group' to log_manager. Move log_manager to own subdirectory' (#4081) from Qubasa/clan-core:improve_ui_logs into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4081
2025-06-24 19:53:09 +00:00
Qubasa
6558a915ad clan-app: Add a 'group' to log_manager. Move log_manager to own subdirectory 2025-06-24 21:42:18 +02:00
kenji
92918719e9 Merge pull request 'pkgs/agit: Document agit PR fetching' (#4080) from kenji/pkgs/agit: Document agit PR fetching into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4080
2025-06-24 17:21:34 +00:00
Luis Hebendanz
81b87a6437 Merge pull request 'clan-lib: Move nix_options from Machine class to Flake class' (#4048) from Qubasa/clan-core:move_nix_options into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4048
Reviewed-by: lassulus <clanlol@lassul.us>
2025-06-24 17:19:16 +00:00
kenji
96cf48a8a8 Merge pull request 'pkgs/agit: Add proper closing message for aborting an AGit PR' (#4076) from kenji/pkgs/agit: Add proper closing message for aborting an AGit PR into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4076
2025-06-24 17:18:00 +00:00
a-kenji
6831dc9f72 pkgs/agit: Document agit PR fetching 2025-06-24 19:13:04 +02:00
Qubasa
60d2837ddd clan-cli: Remove unecessary nix_options args from functions 2025-06-24 19:07:41 +02:00
Qubasa
1bec31b371 generate-test-vars: Fix wrong Flake function invocations 2025-06-24 19:03:20 +02:00
Qubasa
5c6c848dea formatter.iix: Add generate-test-vars to be typechecked 2025-06-24 19:03:20 +02:00
Qubasa
d14a5d34fd clan-lib: Move nix_options from Machine class to Flake class 2025-06-24 19:03:20 +02:00
Luis Hebendanz
d3d2cb8723 Merge pull request 'Move update.py to clan_lib/machines part 4' (#4073) from Qubasa/clan-core:move_to_clan_lib6 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4073
2025-06-24 14:52:10 +00:00
Luis Hebendanz
e6a7efafcf Merge pull request 'Move delete.py to clan_lib/machines part 3' (#4069) from Qubasa/clan-core:move_to_clan_lib5 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4069
2025-06-24 14:51:19 +00:00
Luis Hebendanz
ef5a4ab122 Merge pull request 'Move list.py to clan_lib/machines part 2' (#4068) from Qubasa/clan-core:move_to_clan_lib4 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4068
2025-06-24 14:51:06 +00:00
a-kenji
c8e6a6c6b8 pkgs/agit: Add proper closing message for aborting an AGit PR
Add a proper closing message for aborting an AGit PR.
Also add documentation directly to the comments of the COMMIT_EDITMSG.
2025-06-24 16:47:10 +02:00
renovate[bot]
bbebf67eb0 Update dependency vite to v7 2025-06-24 13:10:33 +00:00
pinpox
724aa17faa Merge pull request 'Make machine ID a option' (#4013) from machine-id-option into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4013
2025-06-24 12:13:22 +00:00
Johannes Kirschbauer
9fcbb6d688 build-clan: move clan attribute relates modules into subfolder 2025-06-24 13:13:59 +02:00
pinpox
b53975684e Merge branch 'main' into machine-id-option 2025-06-24 11:12:24 +00:00
kenji
a1b1f3e9de Merge pull request 'pkgs/agit: Add all commits since main to edit comment' (#4071) from kenji/pkgs/agit: Add all commits since main to edit comment into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4071
2025-06-24 11:01:15 +00:00
a-kenji
d4a4f61f74 pkgs/agit: Add all commits since main to edit comment
This is a first step for adding all the commits to the `agit c` and
prefilling it.
2025-06-24 12:18:15 +02:00
Qubasa
e79b926566 clan-cli: Move update.py to clan_lib/machines 2025-06-24 12:17:21 +02:00
Qubasa
d85277a077 clan-vm-manager: Fix list_machines import 2025-06-24 12:16:38 +02:00
Qubasa
29a5fbed53 clan-cli: Move delete.py to clan_lib/machines 2025-06-24 12:16:38 +02:00
Qubasa
e53a490edc clan-cli: Move list.py to clan_lib/machines 2025-06-24 12:16:38 +02:00
Qubasa
48ea1c757f clan-cli: Move morph.py to clan_lib/machines 2025-06-24 12:16:38 +02:00
renovate[bot]
f81c2254e1 Update dependency tailwindcss to v4 2025-06-24 10:10:27 +00:00
DavHau
03fe06285b inventory interface: add description for module.name 2025-06-24 10:09:05 +00:00
pinpox
b476eb2f92 Merge branch 'main' into machine-id-option 2025-06-24 10:08:04 +00:00
Qubasa
ae73428ba5 clan-vm-manager: Fix list_machines import 2025-06-24 12:03:56 +02:00
Qubasa
ca17fb0ee8 clan-cli: Move list.py to clan_lib/machines 2025-06-24 11:57:02 +02:00
kenji
f288b8c1ef Merge pull request 'pkgs/clan: Add --tags support to clan machines update' (#4061) from kenji/pkgs/clan: Add --tags support to clan machines update into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4061
2025-06-24 09:43:35 +00:00
pinpox
62199e5ec9 Merge branch 'main' into machine-id-option 2025-06-24 09:41:42 +00:00
Qubasa
add15a1a3e clan-cli: Move delete.py to clan_lib/machines 2025-06-24 11:37:21 +02:00
Qubasa
5a14bd3993 clan-cli: Move list.py to clan_lib/machines 2025-06-24 11:32:42 +02:00
Qubasa
eb26ccaed0 clan-cli: Move morph.py to clan_lib/machines 2025-06-24 11:24:38 +02:00
Luis Hebendanz
1b6a3ba335 Merge pull request 'clan-cli: Move hardware.py to clan_lib/machines part2' (#4066) from Qubasa/clan-core:move_to_clan_lib2 into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4066
2025-06-24 09:19:41 +00:00
Luis Hebendanz
18d45da9d6 Merge pull request 'clan-cli: Add missining propagation of host-key-check in machines.update' (#4053) from Qubasa/clan-core:fix_host_key_check_in_update into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4053
2025-06-24 09:10:30 +00:00
Qubasa
b26aad3619 clan-cli: Move hardware.py to clan_lib/machines 2025-06-24 11:07:37 +02:00
pinpox
cb69eea68f Make machine ID a option 2025-06-24 10:42:03 +02:00
Qubasa
7eb90acfc4 clan-cli: Add missining propagation of host-key-check in machines.update 2025-06-24 10:35:53 +02:00
brianmcgee
26a2b45c74 Merge pull request 'add Tag and TagGroup components' (#4038) from ui/tags into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4038
2025-06-24 08:30:06 +00:00
a-kenji
5b04cfc06a pkgs/clan: Add --tags support to clan machines update 2025-06-23 23:51:43 +02:00
a-kenji
e0b7b3329a importer: Fix the documentation for the importer service 2025-06-23 23:27:37 +02:00
hsjobeki
afc001cc54 Merge pull request 'pkgs/clan-cli: Remove confusing note from the CLI help' (#4045) from kenji/pkgs/clan-cli: Remove confusing note from the CLI help into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4045
2025-06-23 14:22:28 +00:00
hsjobeki
a6f94987f9 Merge pull request 'Feat(inventory): simplify instance module spec, by applying a default' (#4054) from hsjobeki/module-default into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4054
2025-06-23 14:21:55 +00:00
hsjobeki
f0d8974d03 Merge pull request 'Refactor(build-clan): rename to lib/modules' (#4055) from clan-unify into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4055
2025-06-23 14:16:54 +00:00
Johannes Kirschbauer
5dc80e43cd Chore(classes): update classes 2025-06-23 16:11:12 +02:00
Johannes Kirschbauer
247eb46b5e Refactor(build-clan): rename to lib/modules
This is a preparation for moving everything into clan, to make it all one module evaluation
2025-06-23 16:06:49 +02:00
Luis Hebendanz
fa843569c7 Merge pull request 'Simplify parse_deployment_address function' (#4052) from Qubasa/clan-core:simplify_parse_deployment_address into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4052
2025-06-23 13:51:37 +00:00
Johannes Kirschbauer
c37651f2fe Feat(inventory): simplify instance module spec, by applying a default 2025-06-23 15:46:52 +02:00
Qubasa
046d13bd50 clan-lib: Rename parse_deployment_address to parse_ssh_uri 2025-06-23 15:32:35 +02:00
Qubasa
c3a631de7e clan-lib: Remove override args from parse_deployment_address, instead use the Remote.override method where necessary 2025-06-23 15:28:22 +02:00
Luis Hebendanz
b3c04ccd53 Merge pull request 'Simplify handling of HostKeyCheck' (#4051) from Qubasa/clan-core:make_host_key_check_literal into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4051
2025-06-23 13:22:23 +00:00
Qubasa
217f55adec clan-cli: Simplify HostKeyCheck to a Literal instead of an Enum 2025-06-23 15:08:44 +02:00
Qubasa
c4b3b26fa6 clan-cli: Move clan_cli/ssh/host_key.py to clan_lib/ssh 2025-06-23 15:07:18 +02:00
Luis Hebendanz
f1b886f04c Merge pull request 'clan-lib: Rename check_machine_online to can_ssh_login. Move to Remote object' (#4050) from Qubasa/clan-core:fix_check_online_machine into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/4050
2025-06-23 12:32:39 +00:00
Qubasa
c65bd82e98 clan-lib: Rename check_machine_online to can_ssh_login. Move to Remote object 2025-06-23 14:21:51 +02:00
renovate[bot]
c4ce1e7962 chore(deps): update disko digest to 8fd2d6c 2025-06-23 12:10:18 +00:00
a-kenji
6ff64f7e0a pkgs/clan-cli: Remove confusing note from the CLI help
Remove a now obsolete and thus confusing note from the help output
of `clan show`.
2025-06-23 08:57:43 +02:00
renovate[bot]
df5de44ba3 chore(deps): update data-mesher digest to f072536 2025-06-23 00:20:19 +00:00
Brian McGee
36e2f25b57 feat(ui): add TagGroup component
Introduces a new `TagGroup` component for rendering grouped tags with optional inverted styling.
2025-06-20 12:22:59 +01:00
Brian McGee
2ed5d29c89 feat(ui): add Tag component
Adds a reusable `Tag` component with support for default and inverted styles. Also includes cleanup of unused dependencies in `package.json`.
2025-06-20 12:22:58 +01:00
Brian McGee
4586b0d17d feat(ui): rename TagStatus to MachineStatus
Standardizes naming and updates related props, classes, and types for clarity and consistency.
2025-06-20 09:13:55 +01:00
212 changed files with 4070 additions and 2522 deletions

View File

@@ -22,7 +22,7 @@
dependencies = [
self
pkgs.stdenv.drvPath
self.clanInternals.machines.${pkgs.hostPlatform.system}.test-backup.config.system.clan.deployment.file
self.clan.clanInternals.machines.${pkgs.hostPlatform.system}.test-backup.config.system.clan.deployment.file
] ++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
in
@@ -162,7 +162,7 @@
]
++
# import the inventory generated nixosModules
self.clanInternals.inventoryClass.machines.test-backup.machineImports;
self.clan.clanInternals.inventoryClass.machines.test-backup.machineImports;
clan.core.settings.directory = ./.;
};

View File

@@ -8,7 +8,7 @@ nixosLib.runTest (
{ ... }:
{
imports = [
clan-core.modules.nixosVmTest.clanTest
clan-core.modules.nixosTest.clanTest
];
hostPkgs = pkgs;

View File

@@ -1,6 +1,6 @@
{ fetchgit }:
fetchgit {
url = "https://git.clan.lol/clan/clan-core.git";
rev = "13a9b1719835ef4510e4adb6941ddfe9a91d41cb";
sha256 = "sha256-M+pLnpuX+vIsxTFtbBZaNA1OwGQPeSbsMbTiDl1t4vY=";
rev = "28131afbbcd379a8ff04c79c66c670ef655ed889";
sha256 = "1294cwjlnc341fl6zbggn4rgq8z33gqkcyggjfvk9cf7zdgygrf6";
}

View File

@@ -16,7 +16,7 @@ nixosLib.runTest (
{ ... }:
{
imports = [
clan-core.modules.nixosVmTest.clanTest
clan-core.modules.nixosTest.clanTest
];
hostPkgs = pkgs;

View File

@@ -9,7 +9,7 @@ nixosLib.runTest (
{ hostPkgs, config, ... }:
{
imports = [
clan-core.modules.nixosVmTest.clanTest
clan-core.modules.nixosTest.clanTest
];
hostPkgs = pkgs;

View File

@@ -8,7 +8,7 @@ nixosLib.runTest (
{ ... }:
{
imports = [
clan-core.modules.nixosVmTest.clanTest
clan-core.modules.nixosTest.clanTest
];
hostPkgs = pkgs;

View File

@@ -9,6 +9,7 @@ in
{
imports = filter pathExists [
./backups/flake-module.nix
../nixosModules/clanCore/machine-id/tests/flake-module.nix
./devshell/flake-module.nix
./flash/flake-module.nix
./impure/flake-module.nix
@@ -48,6 +49,8 @@ in
zt-tcp-relay = self.clanLib.test.containerTest ./zt-tcp-relay nixosTestArgs;
matrix-synapse = self.clanLib.test.containerTest ./matrix-synapse nixosTestArgs;
postgresql = self.clanLib.test.containerTest ./postgresql nixosTestArgs;
user-firewall-iptables = self.clanLib.test.containerTest ./user-firewall/iptables.nix nixosTestArgs;
user-firewall-nftables = self.clanLib.test.containerTest ./user-firewall/nftables.nix nixosTestArgs;
dummy-inventory-test = import ./dummy-inventory-test nixosTestArgs;
dummy-inventory-test-from-flake = import ./dummy-inventory-test-from-flake nixosTestArgs;
@@ -80,7 +83,7 @@ in
_n: m:
let
schema =
(self.clanLib.inventory.evalClanService {
(self.clanLib.evalService {
modules = [ m ];
prefix = [
"checks"

View File

@@ -8,9 +8,9 @@ let
{ modulesPath, pkgs, ... }:
let
dependencies = [
self.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.toplevel
self.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.diskoScript
self.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.clan.deployment.file
self.clan.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.toplevel
self.clan.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.diskoScript
self.clan.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.clan.deployment.file
pkgs.stdenv.drvPath
pkgs.bash.drvPath
pkgs.nixos-anywhere

View File

@@ -8,7 +8,7 @@ nixosLib.runTest (
{ ... }:
{
imports = [
clan-core.modules.nixosVmTest.clanTest
clan-core.modules.nixosTest.clanTest
];
hostPkgs = pkgs;

View File

@@ -9,7 +9,7 @@ nixosLib.runTest (
{ ... }:
{
imports = [
clan-core.modules.nixosVmTest.clanTest
clan-core.modules.nixosTest.clanTest
];
hostPkgs = pkgs;

View File

@@ -0,0 +1,100 @@
# Shared configuration for user firewall tests
{ self, pkgs, ... }:
{
imports = [
self.nixosModules.user-firewall
];
networking.firewall.enable = true;
# Configure the user firewall module
# Test with default allowedInterfaces (which includes wg*)
networking.user-firewall = {
# Use defaults for allowedInterfaces to test that wg* is included by default
exemptUsers = [
"root"
"alice"
];
};
# Create test users
users.users = {
alice = {
isNormalUser = true;
uid = 1001;
initialPassword = "test";
};
bob = {
isNormalUser = true;
uid = 1002;
initialPassword = "test";
};
};
# Add tools for testing
environment.systemPackages = with pkgs; [
curl
netcat
iproute2
];
# Add a local web server for testing
services.nginx = {
enable = true;
virtualHosts = {
"localhost" = {
listen = [
{
addr = "127.0.0.1";
port = 8080;
}
];
locations."/" = {
return = "200 'test server response'";
extraConfig = "add_header Content-Type text/plain;";
};
};
"wg0-test" = {
listen = [
{
addr = "10.100.0.2";
port = 8081;
}
{
addr = "[fd00::2]";
port = 8081;
}
];
locations."/" = {
return = "200 'wg0 interface test response'";
extraConfig = "add_header Content-Type text/plain;";
};
};
};
};
# Create a dummy interface to test allowed interface patterns
systemd.services.setup-wg0-interface = {
description = "Setup wg0 dummy interface";
after = [ "network-pre.target" ];
before = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
${pkgs.iproute2}/bin/ip link add wg0 type dummy || true
${pkgs.iproute2}/bin/ip addr add 10.100.0.2/24 dev wg0 || true
${pkgs.iproute2}/bin/ip addr add fd00::2/64 dev wg0 || true
${pkgs.iproute2}/bin/ip link set wg0 up || true
'';
};
# Make nginx wait for the wg0 interface
systemd.services.nginx = {
after = [ "setup-wg0-interface.service" ];
requires = [ "setup-wg0-interface.service" ];
};
}

View File

@@ -0,0 +1,82 @@
{
name = "user-firewall-iptables";
nodes = {
router =
{ ... }:
{
imports = [ ./router.nix ];
};
machine =
{ ... }:
{
imports = [ ./common.nix ];
# Force iptables backend
networking.nftables.enable = false;
};
};
testScript = ''
start_all()
router.wait_for_unit("multi-user.target")
router.wait_for_unit("nginx.service")
machine.wait_for_unit("multi-user.target")
machine.wait_for_unit("nginx.service")
# Get router IPs (both IPv4 and IPv6)
router_ip = router.succeed("ip -4 addr show eth1 | grep -oP '(?<=inet\\s)\\d+(\\.\\d+){3}'").strip()
router_ip6 = router.succeed("ip -6 addr show eth1 | grep -oP '(?<=inet6\\s)[0-9a-f:]+' | grep -v '^fe80' | head -1").strip()
print(f"Router IPv4: {router_ip}")
print(f"Router IPv6: {router_ip6}")
# Test firewall restart
machine.succeed("systemctl restart firewall")
machine.wait_for_unit("firewall.service")
# Verify rules are loaded
machine.succeed("iptables -L user-firewall-output >&2")
# Test alice (exempt user) - should succeed both locally and to router
machine.wait_until_succeeds("runuser -u alice -- curl -s http://127.0.0.1:8080")
machine.succeed(f"runuser -u alice -- curl -s http://{router_ip}")
machine.succeed(f"runuser -u alice -- curl -s http://[{router_ip6}]")
# Test bob (restricted user) - localhost should work, external should fail
machine.succeed("runuser -u bob -- curl -s http://127.0.0.1:8080")
# This should be blocked by firewall - IPv4
result = machine.succeed(f"runuser -u bob -- curl -s --connect-timeout 2 http://{router_ip} 2>&1 || echo 'EXIT_CODE='$?")
assert "EXIT_CODE=7" in result, f"Bob should be blocked from external IPv4 access (expected EXIT_CODE=7) but got: {result}"
# This should be blocked by firewall - IPv6
result6 = machine.succeed(f"runuser -u bob -- curl -s --connect-timeout 2 http://[{router_ip6}] 2>&1 || echo 'EXIT_CODE='$?")
assert "EXIT_CODE=7" in result6, f"Bob should be blocked from external IPv6 access (expected EXIT_CODE=7) but got: {result6}"
# Verify the rules are actually present for both IPv4 and IPv6
rules4 = machine.succeed("iptables -L user-firewall-output -n -v")
assert "REJECT" in rules4, "REJECT rule not found in iptables"
rules6 = machine.succeed("ip6tables -L user-firewall-output -n -v")
assert "REJECT" in rules6, "REJECT rule not found in ip6tables"
# Wait for the dummy interface to be created
machine.wait_for_unit("setup-wg0-interface.service")
machine.wait_for_unit("nginx.service")
machine.wait_for_open_port(8081, "10.100.0.2")
# Check that wg0 interface exists
machine.succeed("ip link show wg0")
machine.succeed("ip addr show wg0")
# The key test: users should be able to connect via wg0 interface
# For alice (exempt user) - should work
machine.succeed("runuser -u alice -- curl -s --interface wg0 http://10.100.0.2:8081/")
machine.succeed("runuser -u alice -- curl -s --interface wg0 http://[fd00::2]:8081/") # IPv6 test
# For bob (restricted user) - should also work because wg* is in default allowedInterfaces
machine.succeed("runuser -u bob -- curl -s --interface wg0 http://10.100.0.2:8081/")
machine.succeed("runuser -u bob -- curl -s --interface wg0 http://[fd00::2]:8081/") # IPv6 test
# Verify that wg* interfaces are allowed in the firewall rules
machine.succeed("iptables -L user-firewall-output -n -v | grep -E 'wg0|wg\\+' >&2")
'';
}

View File

@@ -0,0 +1,77 @@
{
name = "user-firewall-nftables";
nodes = {
router = {
imports = [ ./router.nix ];
};
machine = {
imports = [ ./common.nix ];
# Force nftables backend
networking.nftables.enable = true;
};
};
testScript = ''
start_all()
router.wait_for_unit("multi-user.target")
router.wait_for_unit("nginx.service")
machine.wait_for_unit("multi-user.target")
machine.wait_for_unit("nginx.service")
# Get router IPs (both IPv4 and IPv6)
router_ip = router.succeed("ip -4 addr show eth1 | grep -oP '(?<=inet\\s)\\d+(\\.\\d+){3}'").strip()
router_ip6 = router.succeed("ip -6 addr show eth1 | grep -oP '(?<=inet6\\s)[0-9a-f:]+' | grep -v '^fe80' | head -1").strip()
print(f"Router IPv4: {router_ip}")
print(f"Router IPv6: {router_ip6}")
# Test nftables restart
machine.succeed("systemctl restart nftables")
machine.wait_for_unit("nftables.service")
# Verify rules are loaded
machine.succeed("nft list table inet user-firewall >&2")
# Test alice (exempt user) - should succeed both locally and to router
machine.wait_until_succeeds("runuser -u alice -- curl -s http://127.0.0.1:8080")
machine.succeed(f"runuser -u alice -- curl -s http://{router_ip}")
machine.succeed(f"runuser -u alice -- curl -s http://[{router_ip6}]")
# Test bob (restricted user) - localhost should work, external should fail
machine.succeed("runuser -u bob -- curl -s http://127.0.0.1:8080")
# This should be blocked by firewall - IPv4
result = machine.succeed(f"runuser -u bob -- curl -s --connect-timeout 2 http://{router_ip} 2>&1 || echo 'EXIT_CODE='$?")
assert "EXIT_CODE=7" in result, f"Bob should be blocked from external IPv4 access (expected EXIT_CODE=7) but got: {result}"
# This should be blocked by firewall - IPv6
result6 = machine.succeed(f"runuser -u bob -- curl -s --connect-timeout 2 http://[{router_ip6}] 2>&1 || echo 'EXIT_CODE='$?")
assert "EXIT_CODE=7" in result6, f"Bob should be blocked from external IPv6 access (expected EXIT_CODE=7) but got: {result6}"
# Verify the rules are actually present
rules = machine.succeed("nft list table inet user-firewall")
assert 'meta skuid 1002' in rules and 'reject' in rules, f"Reject rule for bob (uid 1002) not found in nftables. Actual rules:\n{rules}"
assert "oifname" in rules, f"Interface rules not found in nftables. Actual rules:\n{rules}"
# Wait for the dummy interface to be created
machine.wait_for_unit("setup-wg0-interface.service")
machine.wait_for_unit("nginx.service")
machine.wait_for_open_port(8081, "10.100.0.2")
# Check that wg0 interface exists
machine.succeed("ip link show wg0")
machine.succeed("ip addr show wg0")
# The key test: users should be able to connect via wg0 interface
# For alice (exempt user) - should work
machine.succeed("runuser -u alice -- curl -s --interface wg0 http://10.100.0.2:8081/")
machine.succeed("runuser -u alice -- curl -s --interface wg0 http://[fd00::2]:8081/") # IPv6 test
# For bob (restricted user) - should also work because wg* is in default allowedInterfaces
machine.succeed("runuser -u bob -- curl -s --interface wg0 http://10.100.0.2:8081/")
machine.succeed("runuser -u bob -- curl -s --interface wg0 http://[fd00::2]:8081/") # IPv6 test
# Verify that wg* interfaces are allowed in the nftables rules
rules_with_wg = machine.succeed("nft list table inet user-firewall | grep -E 'oifname.*wg' >&2")
'';
}

View File

@@ -0,0 +1,32 @@
# Shared router configuration for user firewall tests
{ ... }:
{
networking.firewall.enable = false;
networking.useNetworkd = true;
# Simple web server to test connectivity
services.nginx = {
enable = true;
virtualHosts."router" = {
listen = [
{
addr = "0.0.0.0";
port = 80;
}
{
addr = "[::]";
port = 80;
}
{
addr = "10.100.0.1";
port = 80;
}
];
locations."/" = {
return = "200 'router response'";
extraConfig = "add_header Content-Type text/plain;";
};
};
};
}

View File

@@ -18,6 +18,13 @@
../../root-password
];
config = {
warnings = [
"The clan.admin module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
users.users.root.openssh.authorizedKeys.keys = builtins.attrValues config.clan.admin.allowedKeys;
};
}

View File

@@ -15,8 +15,11 @@ in
};
config = {
warnings = [
"The clan.auto-upgrade module is deprecated and will be removed on 2025-07-15. Please migrate to using the system.autoUpgrade NixOS option directly."
"The clan.auto-upgrade module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
system.autoUpgrade = {

View File

@@ -90,6 +90,12 @@ in
config = {
warnings = [
"The clan.borgbackup module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
# Destinations
clan.borgbackup.destinations =
let

View File

@@ -27,6 +27,13 @@ in
};
config = {
warnings = [
"The clan.admin module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
services.data-mesher.initNetwork =
let
# for a given machine, read it's public key and remove any new lines

View File

@@ -5,7 +5,9 @@
}:
{
warnings = [
"The clan.deltachat module is deprecated and will be removed on 2025-07-15. Please migrate to user-maintained configuration."
"The clan.deltachat module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
networking.firewall.interfaces."zt+".allowedTCPPorts = [ 25 ]; # smtp with other hosts

View File

@@ -7,6 +7,12 @@
{
config = {
warnings = [
"The clan.disk-id module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
clan.core.vars.generators.disk-id = {
files.diskId.secret = false;
runtimeInputs = [

View File

@@ -1,7 +1,9 @@
_: {
warnings = [
"The clan.ergochat module is deprecated and will be removed on 2025-07-15. Please migrate to user-maintained configuration."
"The clan.ergochat module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
services.ergochat = {

View File

@@ -23,7 +23,6 @@ in
iwd = ./iwd;
localbackup = ./localbackup;
localsend = ./localsend;
machine-id = ./machine-id;
matrix-synapse = ./matrix-synapse;
moonlight = ./moonlight;
mumble = ./mumble;

View File

@@ -1,5 +1,12 @@
{ config, pkgs, ... }:
{
warnings = [
"The clan.ergochat module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
systemd.services.garage.serviceConfig = {
LoadCredential = [
"rpc_secret_path:${config.clan.core.vars.generators.garage-shared.files.rpc_secret.path}"

View File

@@ -12,7 +12,9 @@
];
config = {
warnings = [
"The clan.heisenbridge module is deprecated and will be removed on 2025-07-15. Please migrate to user-maintained configuration."
"The clan.heisenbridge module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
services.heisenbridge = {
enable = true;

View File

@@ -39,7 +39,9 @@ in
];
config = {
warnings = [
"The clan.localsend module is deprecated and will be removed on 2025-07-15. Please migrate to user-maintained configuration."
"The clan.localsend module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
clan.core.state.localsend.folders = [

View File

@@ -1,4 +0,0 @@
---
description = "Sets the /etc/machine-id and exposes it as a nix option"
features = [ "inventory" ]
---

View File

@@ -1,6 +0,0 @@
# Dont import this file
# It is only here for backwards compatibility.
# Dont author new modules with this file.
{
imports = [ ./roles/default.nix ];
}

View File

@@ -1,45 +0,0 @@
{
config,
pkgs,
lib,
...
}:
let
var = config.clan.core.vars.generators.machine-id.files.machineId or { };
in
{
config = lib.mkMerge [
(lib.mkIf ((var.value or null) != null) {
assertions = [
{
assertion = lib.stringLength var.value == 32;
message = "machineId must be exactly 32 characters long.";
}
];
boot.kernelParams = [
''systemd.machine_id=${var.value}''
];
environment.etc."machine-id" = {
text = var.value;
};
})
{
clan.core.vars.generators.machine-id = {
files.machineId.secret = false;
runtimeInputs = [
pkgs.coreutils
pkgs.bash
];
script = ''
uuid=$(bash ${./uuid4.sh})
# Remove the hyphens from the UUID
uuid_no_hyphens=$(echo -n "$uuid" | tr -d '-')
echo -n "$uuid_no_hyphens" > "$out/machineId"
'';
};
}
];
}

View File

@@ -37,8 +37,11 @@ in
};
config = {
warnings = [
"The clan.mumble module is deprecated and will be removed on 2025-07-15. Please migrate to user-maintained configuration."
"The clan.mumble module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
services.murmur = {

View File

@@ -19,6 +19,12 @@
};
};
config.warnings = [
"The clan.mycelium module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
config.services.mycelium = {
enable = true;
addHostedPublicNodes = lib.mkDefault config.clan.mycelium.addHostedPublicNodes;

View File

@@ -12,6 +12,12 @@
};
};
config = {
warnings = [
"The clan.packages module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
environment.systemPackages = map (
pName: lib.getAttrFromPath (lib.splitString "." pName) pkgs
) config.clan.packages.packages;

View File

@@ -6,6 +6,13 @@
...
}:
{
warnings = [
"The clan.root-password module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
users.mutableUsers = false;
users.users.root.hashedPasswordFile =
config.clan.core.vars.generators.root-password.files.password-hash.path;

View File

@@ -17,6 +17,13 @@ in
clan.sshd.hostKeys.rsa.enable = lib.mkEnableOption "Generate RSA host key";
};
config = {
warnings = [
"The clan.sshd module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
services.openssh = {
enable = true;
settings.PasswordAuthentication = false;

View File

@@ -3,6 +3,13 @@ let
var = config.clan.core.vars.generators.state-version.files.version or { };
in
{
warnings = [
"The clan.state-version module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
system.stateVersion = lib.mkDefault (lib.removeSuffix "\n" var.value);
clan.core.vars.generators.state-version = {

View File

@@ -11,6 +11,7 @@ in
imports = [
../shared.nix
];
clan.syncthing.introducer = lib.strings.removeSuffix "\n" (
if builtins.pathExists introducerId then
builtins.readFile introducerId

View File

@@ -26,6 +26,13 @@ in
};
config = {
warnings = [
"The clan.user-password module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
users.mutableUsers = false;
users.users.${cfg.user} = {
hashedPasswordFile = config.clan.core.vars.generators.user-password.files.user-password-hash.path;

View File

@@ -17,6 +17,13 @@ in
../shared.nix
];
config = {
warnings = [
"The clan.zerotier module is deprecated and will be removed on 2025-07-15.
Please migrate to user-maintained configuration or the new equivalent clan services
(https://docs.clan.lol/reference/clanServices)."
];
systemd.services.zerotier-inventory-autoaccept =
let
machines = uniqueStrings (roles.moon.machines ++ roles.controller.machines ++ roles.peer.machines);

View File

@@ -6,7 +6,7 @@
let
testFlake = clanLib.buildClan {
# Point to the folder of the module
# TODO: make this optional in buildClan
# TODO: make this optional
directory = ./..;
# Create some test machines

View File

@@ -8,13 +8,13 @@ inventory.instances = {
zone1 = {
module.name = "@clan/importer";
roles.default.tags = [ "zone1" ];
roles.default.tags.zone1 = {};
roles.default.extraModules = [ "modules/zone1.nix" ];
};
base = {
module.name = "@clan/importer";
roles.default.tags = [ "all" ];
roles.default.tags.all = {};
roles.default.extraModules = [ "modules/base.nix" ];
};

View File

@@ -41,7 +41,7 @@
clan.core.vars.generators."user-password-${settings.user}" = {
# files.user-password-hash.neededFor = "users";
files.user-password-hash.neededFor = "users";
files.user-password-hash.restartUnits = lib.optional (config.services.userborn.enable) "userborn.service";
files.user-password.deploy = false;

View File

@@ -6,7 +6,7 @@
let
testFlake = clanLib.buildClan {
# Point to the folder of the module
# TODO: make this optional in buildClan
# TODO: make this optional
directory = ./..;
# Create some test machines
@@ -46,7 +46,7 @@ in
inherit testFlake;
expr =
testFlake.clanInternals.inventoryClass.distributedServices.importedModulesEvaluated.self-wifi.config;
testFlake.clan.clanInternals.inventoryClass.distributedServices.importedModulesEvaluated.self-wifi.config;
expected = 1;
# expr = {

View File

@@ -16,7 +16,7 @@ inventory.instances = {
The input should be named according to your flake input.
All machines will be peers and connected to the zerotier network.
Jon is the controller machine, which will will accept other machines into the network.
Sara is a moon and sets the `stableEndpoint` setting with a publically reachable IP, the moon is optional.
Sara is a moon and sets the `stableEndpoint` setting with a publicly reachable IP, the moon is optional.
## Overview

View File

@@ -44,6 +44,9 @@
# vendoring / needed for impure tests
ln -sfT ${self'.packages.clan-cli.nixpkgs} "$PRJ_ROOT/pkgs/clan-cli/clan_lib/nixpkgs"
ln -sfT ${inputs.nix-select} "$PRJ_ROOT/pkgs/clan-cli/clan_lib/select"
# Generate classes.py from schemas
${self'.packages.classgen}/bin/classgen ${self'.legacyPackages.schemas.clan-schema-abstract}/schema.json $PRJ_ROOT/pkgs/clan-cli/clan_lib/nix_models/clan.py
'';
};
};

1
docs/.gitignore vendored
View File

@@ -1,3 +1,4 @@
/site/reference
/site/static
/site/options-page
!/site/static/extra.css

View File

@@ -116,7 +116,6 @@ nav:
- reference/clanModules/iwd.md
- reference/clanModules/localbackup.md
- reference/clanModules/localsend.md
- reference/clanModules/machine-id.md
- reference/clanModules/matrix-synapse.md
- reference/clanModules/moonlight.md
- reference/clanModules/mumble.md
@@ -169,7 +168,7 @@ nav:
- reference/clan.core/state.md
- reference/clan.core/vars.md
- Nix API:
- buildClan: reference/nix-api/buildclan.md
- clan: reference/nix-api/clan.md
- Inventory: reference/nix-api/inventory.md
- Glossary: reference/glossary.md
- Decisions:
@@ -180,6 +179,7 @@ nav:
- 04-fetching-nix-from-python: decisions/04-fetching-nix-from-python.md
- 05-deployment-parameters: decisions/05-deployment-parameters.md
- Template: decisions/_template.md
- Options: options.md
docs_dir: site
site_dir: out

View File

@@ -7,6 +7,7 @@
asciinema-player-css,
roboto,
fira-code,
docs-options,
...
}:
let
@@ -35,6 +36,11 @@ pkgs.stdenv.mkDerivation {
mkdir -p ./site/reference/cli
cp -af ${module-docs}/* ./site/reference/
cp -af ${clan-cli-docs}/* ./site/reference/cli/
chmod -R +w ./site/reference
echo "Generated API documentation in './site/reference/' "
cp -r ${docs-options} ./site/options-page
chmod -R +w ./site/options-page
mkdir -p ./site/static/asciinema-player
ln -snf ${asciinema-player-js} ./site/static/asciinema-player/asciinema-player.min.js

View File

@@ -1,5 +1,8 @@
{ inputs, self, ... }:
{
imports = [
./options/flake-module.nix
];
perSystem =
{
config,
@@ -94,7 +97,6 @@
# Frontmatter format for clanModules
export CLAN_MODULES_FRONTMATTER_DOCS=${clanModulesFrontmatter}/share/doc/nixos/options.json
# buildClan options
export BUILD_CLAN_PATH=${buildClanOptions}/share/doc/nixos/options.json
mkdir $out
@@ -112,19 +114,20 @@
clanModulesViaService
;
};
devShells.docs = pkgs.callPackage ./shell.nix {
inherit (self'.packages) docs clan-cli-docs inventory-api-docs;
inherit
asciinema-player-js
asciinema-player-css
module-docs
self'
;
};
devShells.docs = self'.packages.docs.overrideAttrs (_old: {
nativeBuildInputs =
self'.devShells.default.nativeBuildInputs ++ self'.packages.docs.nativeBuildInputs;
shellHook = ''
${self'.devShells.default.shellHook}
git_root=$(git rev-parse --show-toplevel)
cd "$git_root"
runPhase configurePhase
'';
});
packages = {
docs = pkgs.python3.pkgs.callPackage ./default.nix {
clan-core = self;
inherit (self'.packages) clan-cli-docs inventory-api-docs;
inherit (self'.packages) clan-cli-docs docs-options inventory-api-docs;
inherit (inputs) nixpkgs;
inherit module-docs;
inherit asciinema-player-js;

View File

@@ -41,7 +41,7 @@
clanModulesViaService = lib.mapAttrs (
_moduleName: moduleValue:
let
evaluatedService = clan-core.clanLib.inventory.evalClanService {
evaluatedService = clan-core.clanLib.evalService {
modules = [ moduleValue ];
prefix = [ ];
};

View File

@@ -0,0 +1,167 @@
{ self, config, ... }:
{
perSystem =
{
inputs',
lib,
...
}:
let
inherit (lib)
mapAttrsToList
flip
mapAttrs
mkOption
types
splitString
stringLength
substring
;
inherit (self) clanLib;
serviceModules = self.clan.modules;
baseHref = "/options-page/";
getRoles =
module:
(clanLib.evalService {
modules = [ module ];
prefix = [ ];
}).config.roles;
getManifest =
module:
(clanLib.evalService {
modules = [ module ];
prefix = [ ];
}).config.manifest;
loadFile = file: if builtins.pathExists file then builtins.readFile file else "";
settingsModules =
module: flip mapAttrs (getRoles module) (_roleName: roleConfig: roleConfig.interface);
# Map each letter to its capitalized version
capitalizeChar =
char:
{
a = "A";
b = "B";
c = "C";
d = "D";
e = "E";
f = "F";
g = "G";
h = "H";
i = "I";
j = "J";
k = "K";
l = "L";
m = "M";
n = "N";
o = "O";
p = "P";
q = "Q";
r = "R";
s = "S";
t = "T";
u = "U";
v = "V";
w = "W";
x = "X";
y = "Y";
z = "Z";
}
.${char};
title =
name:
let
# split by -
parts = splitString "-" name;
# capitalize first letter of each part
capitalize = part: (capitalizeChar (substring 0 1 part)) + substring 1 (stringLength part) part;
capitalizedParts = map capitalize parts;
in
builtins.concatStringsSep " " capitalizedParts;
fakeInstanceOptions =
name: module:
let
manifest = getManifest module;
description = ''
# ${title name} (Clan Service)
**${manifest.description}**
${loadFile (module._file + "/../README.md")}
${
if manifest.categories != [ ] then
"Categories: " + builtins.concatStringsSep ", " manifest.categories
else
"No categories defined"
}
'';
in
{
options = {
_ = mkOption {
type = types.raw;
};
instances.${name} = lib.mkOption {
inherit description;
type = types.submodule {
options.roles = flip mapAttrs (settingsModules module) (
roleName: roleSettingsModule:
mkOption {
type = types.submodule {
_file = "docs flake-module";
imports = [
{ _module.args = { inherit clanLib; }; }
(import ../../../lib/modules/inventoryClass/roles-interface.nix {
nestedSettingsOption = mkOption {
type = types.raw;
description = ''
See [instances.${name}.roles.${roleName}.settings](${baseHref}?option_scope=0&option=instances.${name}.roles.${roleName}.settings)
'';
};
settingsOption = mkOption {
type = types.submoduleWith {
modules = [ roleSettingsModule ];
};
};
})
];
};
}
);
};
};
};
};
mkScope = name: modules: {
inherit name;
modules = [
{
_module.args = { inherit clanLib; };
_file = "docs mkScope";
}
{ noInstanceOptions = true; }
../../../lib/modules/inventoryClass/interface.nix
] ++ mapAttrsToList fakeInstanceOptions modules;
urlPrefix = "https://github.com/nix-community/dream2nix/blob/main/";
};
in
{
packages.docs-options = inputs'.nuschtos.packages.mkMultiSearch {
inherit baseHref;
title = "Clan Options";
# scopes = mapAttrsToList mkScope serviceModules;
scopes = [ (mkScope "Clan Inventory" serviceModules) ];
};
};
}

View File

@@ -383,36 +383,16 @@ For more information, see the [inventory guide](../../guides/inventory.md).
`clan.admin.allowedkeys`
This means there are two equivalent ways to set the `allowedkeys` option.
Either via a nixos module or via the inventory interface.
**But it is recommended to keep together `imports` and `config` to preserve
locality of the module configuration.**
=== "Inventory"
```nix
clan-core.lib.buildClan {
inventory.services = {
admin.me = {
roles.default.machines = [ "jon" ];
config.allowedkeys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQD..." ];
};
```nix
clan-core.lib.clan {
inventory.services = {
admin.me = {
roles.default.machines = [ "jon" ];
config.allowedkeys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQD..." ];
};
};
```
=== "NixOS"
```nix
clan-core.lib.buildClan {
machines = {
jon = {
clan.admin.allowedkeys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQD..." ];
imports = [ clanModules.admin ];
};
};
};
```
};
```
"""
)
return ""
@@ -708,18 +688,18 @@ def produce_build_clan_docs() -> None:
msg = f"Environment variables are not set correctly: $out={OUT}"
raise ClanError(msg)
output = """# BuildClan
output = """# Clan
This provides an overview of the available arguments of the `clan` interface.
Each attribute is documented below
- **buildClan**: A function that takes an attribute set.`.
- **clan-core.lib.clan**: A function that takes an attribute set.
??? example "buildClan Example"
??? example "clan Example"
```nix
buildClan {
clan {
self = self;
machines = {
jon = { };
@@ -728,7 +708,13 @@ Each attribute is documented below
};
```
- **flake-parts**: Each attribute can be defined via `clan.<attribute name>`. See our [flake-parts](../../guides/flake-parts.md) guide.
- **clan with flake-parts**: Import the FlakeModule
After importing the FlakeModule you can define your `clan` as a flake attribute
All attribute can be defined via `clan.*`
Further information see: [flake-parts](../../guides/flake-parts.md) guide.
??? example "flake-parts Example"
@@ -767,7 +753,7 @@ Each attribute is documented below
for option in root.suboptions:
output += options_docs_from_tree(option, init_level=2)
outfile = Path(OUT) / "nix-api/buildclan.md"
outfile = Path(OUT) / "nix-api/clan.md"
outfile.parent.mkdir(parents=True, exist_ok=True)
with Path.open(outfile, "w") as of:
of.write(output)
@@ -821,8 +807,8 @@ Typically needed by module authors to define roles, behavior and metadata for di
See: [clanService Authoring Guide](../../guides/authoring/clanServices/index.md)
"""
# Inventory options are already included under the buildClan attribute
# We just omitted them in the buildClan docs, because we want a separate output for the inventory model
# Inventory options are already included under the clan attribute
# We just omitted them in the clan docs, because we want a separate output for the inventory model
with Path(CLAN_SERVICE_INTERFACE).open() as f:
options: dict[str, dict[str, Any]] = json.load(f)
@@ -860,11 +846,11 @@ def produce_inventory_docs() -> None:
output = """# Inventory
This provides an overview of the available attributes of the `inventory` model.
It can be set via the `inventory` attribute of the [`buildClan`](./buildclan.md#inventory) function, or via the [`clan.inventory`](./buildclan.md#inventory) attribute of flake-parts.
It can be set via the `inventory` attribute of the [`clan`](./clan.md#inventory) function, or via the [`clan.inventory`](./clan.md#inventory) attribute of flake-parts.
"""
# Inventory options are already included under the buildClan attribute
# We just omitted them in the buildClan docs, because we want a separate output for the inventory model
# Inventory options are already included under the clan attribute
# We just omitted them in the clan docs, because we want a separate output for the inventory model
with Path(BUILD_CLAN_PATH).open() as f:
options: dict[str, dict[str, Any]] = json.load(f)

View File

@@ -1,40 +0,0 @@
{
docs,
pkgs,
module-docs,
clan-cli-docs,
asciinema-player-js,
asciinema-player-css,
roboto,
fira-code,
self',
...
}:
pkgs.mkShell {
name = "clan-docs";
inputsFrom = [
docs
self'.devShells.default
];
shellHook = ''
git_root=$(git rev-parse --show-toplevel)
cd ''${git_root}/docs
mkdir -p ./site/reference/cli
cp -af ${module-docs}/* ./site/reference/
cp -af ${clan-cli-docs}/* ./site/reference/cli/
chmod -R +w ./site/reference/*
echo "Generated API documentation in './site/reference/' "
mkdir -p ./site/static/asciinema-player
ln -snf ${asciinema-player-js} ./site/static/asciinema-player/asciinema-player.min.js
ln -snf ${asciinema-player-css} ./site/static/asciinema-player/asciinema-player.css
# Link to fonts
ln -snf ${roboto}/share/fonts/truetype/Roboto-Regular.ttf ./site/static/
ln -snf ${fira-code}/share/fonts/truetype/FiraCode-VF.ttf ./site/static/
'';
}

View File

@@ -0,0 +1,14 @@
{% extends "base.html" %} {% block extrahead %}
<style>
.md-main__inner {
max-width: 100% !important;
}
.md-content {
max-width: 100% !important;
}
.md-main__inner {
margin-top: 0 !important;
}
</style>
{% endblock %} {% block site_nav %}{% endblock %} {% block content %} {{
page.content }} {% endblock %}

View File

@@ -52,7 +52,7 @@ clanModules/borgbackup
```nix title="flake.nix"
# ...
buildClan {
clan-core.lib.clan {
# 1. Add the module to the available clanModules with inventory support
inventory.modules = {
custom-module = ./modules/my_module;
@@ -175,7 +175,7 @@ The following shows how to add options to your module.
Configuration can be set as follows.
```nix title="flake.nix"
buildClan {
clan-core.lib.clan {
inventory.services = {
custom-module.instance_1 = {
roles.default.machines = [ "machineA" ];

View File

@@ -27,7 +27,7 @@ inputs = {
## 2. Import the Clan flake-parts Module
After updating your flake inputs, the next step is to import the Clan flake-parts module. This will make the [Clan options](../reference/nix-api/buildclan.md) available within `mkFlake`.
After updating your flake inputs, the next step is to import the Clan flake-parts module. This will make the [Clan options](../reference/nix-api/clan.md) available within `mkFlake`.
```nix
{
@@ -62,7 +62,7 @@ Next you'll need to configure Clan wide settings and define machines, here's an
];
# Define your Clan
# See: https://docs.clan.lol/reference/nix-api/buildclan/
# See: https://docs.clan.lol/reference/nix-api/clan/
clan = {
# Clan wide settings
meta.name = ""; # This is required and must be unique

View File

@@ -8,7 +8,7 @@ Clan currently offers the following methods to configure machines:
!!! Success "Recommended for advanced Nix users"
- flake.nix (i.e. via `buildClan`)
- flake.nix (i.e. via `clan-core.lib.clan`)
- `machine` argument
- `inventory` argument
@@ -30,7 +30,7 @@ In the `flake.nix` file:
=== "**normal flake template**"
```nix title="flake.nix" hl_lines="3"
buildClan {
clan-core.lib.clan {
# Set a unique name
meta.name = "Lobsters";
# Necessary for importing external Clan services
@@ -60,7 +60,7 @@ Adding or configuring a new machine requires two simple steps:
???+ Note "Cloud Machines"
NixOS can cause strange issues when booting in certain cloud environments.
- If on Linode: Make sure that the system uses Direct Disk boot kernel (found in the configuration pannel)
### Step 1. Identify Target Disk-ID

View File

@@ -175,7 +175,7 @@ During an update, the CLI will SSH into the build host and run `nixos-rebuild` f
```{.nix hl_lines="5" .no-copy}
buildClan {
clan {
# ...
machines = {
"jon" = {
@@ -191,7 +191,7 @@ To exclude machines from being updated when running `clan machines update` witho
one can set the `clan.deployment.requireExplicitUpdate` option to true:
```{.nix hl_lines="5" .no-copy}
buildClan {
clan {
# ...
machines = {
"jon" = {

View File

@@ -82,7 +82,7 @@ are loaded when using Clan:
outputs =
{ self, clan-core, ... }:
let
clan = clan-core.clanLib.buildClan {
clan = clan-core.clanLib.clan {
inherit self;
meta.name = "myclan";

View File

@@ -47,7 +47,7 @@ Each service can still be customized and configured according to the modules opt
See also: [Multiple Service Instances](#multiple-service-instances)
```{.nix hl_lines="6-7"}
buildClan {
clan-core.lib.clan {
inventory = {
services = {
borgbackup.instance_1 = {
@@ -69,7 +69,7 @@ It is possible to add services to multiple machines via tags as shown
!!! Example "Tags Example"
```{.nix hl_lines="5 8 14"}
buildClan {
clan-core.lib.clan {
inventory = {
machines = {
"jon" = {
@@ -101,7 +101,7 @@ It is possible to add services to multiple machines via tags as shown
In this example `backup_server` has role `client` and `server` in different instances.
```{.nix hl_lines="11 14"}
buildClan {
clan-core.lib.clan {
inventory = {
machines = {
"jon" = {};

View File

@@ -13,10 +13,10 @@ Currently, Clan supports the following features for macOS:
In this example, we'll name the machine `yourmachine`. Replace this with your preferred machine name.
=== "**If using core.lib.buildClan**"
=== "**If using clan-core.lib.clan**"
```nix
buildClan {
clan-core.lib.clan {
inventory = {
machines.yourmachine.machineClass = "darwin";
};

View File

@@ -52,7 +52,7 @@ This guide shows you how to configure `zerotier` either through `NixOS Options`
};
};
```
## 3. Apply the Configuration
Update the `controller` machine:

View File

@@ -68,7 +68,7 @@ output parameters.
The existing `nixosConfigurations` output of your flake will be created by
clan. In addition, a new `clanInternals` output will be added. Since both of
these are provided by the output of `lib.buildClan`, a common syntax is to use a
these are provided by the output of `clan-core.lib.clan`, a common syntax is to use a
`let...in` statement to create your clan and access it's parameters in the flake
outputs.
@@ -85,7 +85,7 @@ For the provide flake example, your flake should now look like this:
outputs = { self, nixpkgs, clan-core, ... }:
let
clan = clan-core.lib.buildClan {
clan = clan-core.lib.clan {
self = self; # this needs to point at the repository root
specialArgs = {};
meta.name = throw "Change me to something unique";

View File

@@ -17,19 +17,14 @@ Every folder `machines/{machineName}` will be registered automatically as a Clan
- [x] `machines/{machineName}/facter.json` Automatically configured, for further information see [nixos-facter](https://clan.lol/blog/nixos-facter/)
- [x] `machines/{machineName}/disko.nix` Automatically loaded, for further information see the [disko docs](https://github.com/nix-community/disko/blob/master/docs/quickstart.md).
## Manual declaration
Machines can also be added manually under `buildClan`, `clan.*` in flake-parts or via [`inventory`](../guides/inventory.md).
!!! Note
It is possible to use `inventory` and `buildClan` together at the same time.
Machines can be added via [`clan.inventory.machines`](../guides/inventory.md) or in `clan.machines`, which allows for defining NixOS options.
=== "**Individual Machine Configuration**"
```{.nix}
buildClan {
clan-core.lib.clan {
machines = {
"jon" = {
# Any valid nixos config
@@ -41,12 +36,13 @@ Machines can also be added manually under `buildClan`, `clan.*` in flake-parts o
=== "**Inventory Configuration**"
```{.nix}
buildClan {
clan-core.lib.clan {
inventory = {
machines = {
"jon" = {
# Inventory machines can set tags
# Inventory can set tags and other metadata
tags = [ "zone1" ];
deploy.targetHost = "root@jon";
};
};
};

View File

@@ -5,7 +5,7 @@ At the moment, NixOS/Clan does not support [Secure Boot](https://wiki.gentoo.org
### Step 2: Access the UEFI/BIOS Menu
- Restart your computer.
- As your computer restarts, press the appropriate key to enter the UEFI/BIOS settings.
- As your computer restarts, press the appropriate key to enter the UEFI/BIOS settings.
??? tip "The key depends on your laptop or motherboard manufacturer. Click to see a reference list:"
| Manufacturer | UEFI/BIOS Key(s) |

6
docs/site/options.md Normal file
View File

@@ -0,0 +1,6 @@
---
template: options.html
---
<iframe src="/options-page/" height="1000" width="100%"></iframe>

View File

@@ -21,7 +21,7 @@ Flake URL-like syntax used to link to clans.
Required to connect the `url-open` application to the `clan-app`.
## facts *(deprecated)*
System for creating secrets and public files in a declarative way.
System for creating secrets and public files in a declarative way.
**Note:** Deprecated, use `vars` instead.
## inventory

View File

@@ -7,7 +7,7 @@ This section of the site provides an overview of available options and commands
- Learn how to use the [Clan CLI](./cli/index.md)
- Explore available services and application [modules](./clanModules/index.md)
- Discover [configuration options](./clan.core/index.md) that manage essential features
- Find descriptions of the [Nix interfaces](./nix-api/buildclan.md) for defining a Clan
- Find descriptions of the [Nix interfaces](./nix-api/clan.md) for defining a Clan
---

92
flake.lock generated
View File

@@ -16,11 +16,11 @@
]
},
"locked": {
"lastModified": 1750183842,
"narHash": "sha256-znYkJ+9GUNQCmFtEhGvMRZPRP3fdGmbiuTyyrJRKUGA=",
"rev": "cb75111e4c99c7a960cfdd0d743f75663e36cbfa",
"lastModified": 1750933274,
"narHash": "sha256-Aq7mRVv+mws5U+6RmQSVxiO6dKQi/r6MlO4caKwZdK0=",
"rev": "32b1ff6978758dda91a1e48d54f4f523ce9d1a98",
"type": "tarball",
"url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/cb75111e4c99c7a960cfdd0d743f75663e36cbfa.tar.gz"
"url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/32b1ff6978758dda91a1e48d54f4f523ce9d1a98.tar.gz"
},
"original": {
"type": "tarball",
@@ -34,11 +34,11 @@
]
},
"locked": {
"lastModified": 1750040002,
"narHash": "sha256-KrC9iOVYIn6ukpVlHbqSA4hYCZ6oDyJKrcLqv4c5v84=",
"lastModified": 1750903843,
"narHash": "sha256-Ng9+f0H5/dW+mq/XOKvB9uwvGbsuiiO6HrPdAcVglCs=",
"owner": "nix-community",
"repo": "disko",
"rev": "7f1857b31522062a6a00f88cbccf86b43acceed1",
"rev": "83c4da299c1d7d300f8c6fd3a72ac46cb0d59aae",
"type": "github"
},
"original": {
@@ -67,6 +67,52 @@
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"ixx": {
"inputs": {
"flake-utils": [
"nuschtos",
"flake-utils"
],
"nixpkgs": [
"nuschtos",
"nixpkgs"
]
},
"locked": {
"lastModified": 1748294338,
"narHash": "sha256-FVO01jdmUNArzBS7NmaktLdGA5qA3lUMJ4B7a05Iynw=",
"owner": "NuschtOS",
"repo": "ixx",
"rev": "cc5f390f7caf265461d4aab37e98d2292ebbdb85",
"type": "github"
},
"original": {
"owner": "NuschtOS",
"ref": "v0.0.8",
"repo": "ixx",
"type": "github"
}
},
"nix-darwin": {
"inputs": {
"nixpkgs": [
@@ -128,15 +174,41 @@
"url": "https://nixos.org/channels/nixpkgs-unstable/nixexprs.tar.xz"
}
},
"nuschtos": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"ixx": "ixx",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1749730855,
"narHash": "sha256-L3x2nSlFkXkM6tQPLJP3oCBMIsRifhIDPMQQdHO5xWo=",
"owner": "NuschtOS",
"repo": "search",
"rev": "8dfe5879dd009ff4742b668d9c699bc4b9761742",
"type": "github"
},
"original": {
"owner": "NuschtOS",
"repo": "search",
"type": "github"
}
},
"root": {
"inputs": {
"data-mesher": "data-mesher",
"disko": "disko",
"flake-parts": "flake-parts",
"flake-utils": "flake-utils",
"nix-darwin": "nix-darwin",
"nix-select": "nix-select",
"nixos-facter-modules": "nixos-facter-modules",
"nixpkgs": "nixpkgs",
"nuschtos": "nuschtos",
"sops-nix": "sops-nix",
"systems": "systems",
"treefmt-nix": "treefmt-nix"
@@ -184,11 +256,11 @@
]
},
"locked": {
"lastModified": 1749194973,
"narHash": "sha256-eEy8cuS0mZ2j/r/FE0/LYBSBcIs/MKOIVakwHVuqTfk=",
"lastModified": 1750931469,
"narHash": "sha256-0IEdQB1nS+uViQw4k3VGUXntjkDp7aAlqcxdewb/hAc=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "a05be418a1af1198ca0f63facb13c985db4cb3c5",
"rev": "ac8e6f32e11e9c7f153823abc3ab007f2a65d3e1",
"type": "github"
},
"original": {

View File

@@ -34,6 +34,13 @@
treefmt-nix.follows = "treefmt-nix";
};
};
# dependencies needed for nuschtos
flake-utils.url = "github:numtide/flake-utils";
flake-utils.inputs.systems.follows = "systems";
nuschtos.url = "github:NuschtOS/search";
nuschtos.inputs.nixpkgs.follows = "nixpkgs";
nuschtos.inputs.flake-utils.follows = "flake-utils";
};
outputs =
@@ -56,27 +63,28 @@
clan = {
meta.name = "clan-core";
};
systems = import systems;
imports =
# only importing existing paths allows to minimize the flake for test
# by removing files
filter pathExists [
./checks/flake-module.nix
./clanModules/flake-module.nix
./clanServices/flake-module.nix
./devShell.nix
./docs/nix/flake-module.nix
./flakeModules/flake-module.nix
./flakeModules/demo_iso.nix
./lib/filter-clan-core/flake-module.nix
./lib/flake-module.nix
./lib/flake-parts/clan-nixos-test.nix
./nixosModules/clanCore/vars/flake-module.nix
./nixosModules/flake-module.nix
./pkgs/flake-module.nix
./templates/flake-module.nix
]
[ flake-parts.flakeModules.modules ]
++
# only importing existing paths allows to minimize the flake for test
# by removing files
filter pathExists [
./checks/flake-module.nix
./clanModules/flake-module.nix
./clanServices/flake-module.nix
./devShell.nix
./docs/nix/flake-module.nix
./flakeModules/flake-module.nix
./flakeModules/demo_iso.nix
./lib/filter-clan-core/flake-module.nix
./lib/flake-module.nix
./lib/flake-parts/clan-nixos-test.nix
./nixosModules/clanCore/vars/flake-module.nix
./nixosModules/flake-module.nix
./pkgs/flake-module.nix
./templates/flake-module.nix
]
++ [
(if pathExists ./flakeModules/clan.nix then import ./flakeModules/clan.nix inputs.self else { })
]

View File

@@ -1,55 +1,78 @@
clan-core:
# Downstream flake arguments
{
config,
lib,
self,
inputs,
config,
lib,
...
}:
let
inherit (lib) types;
in
{
# Backwards compatibility
imports = [
(lib.mkRenamedOptionModule [ "clan" ] [ "flake" "clan" ])
];
options.flake = {
# CLI compat
clanInternals = lib.mkOption {
description = "Stable nix interface interacted by the clan cli.";
default = config.flake.clan.clanInternals;
};
# The clan module
clan = lib.mkOption {
description = "Clan module. Define your clan inside here";
default = { };
type = types.submoduleWith {
class = "clan";
specialArgs =
# TODO: make these explizit options and deduplicate with lib.clan function
let
nixpkgs = inputs.nixpkgs or clan-core.inputs.nixpkgs;
nix-darwin = inputs.nix-darwin or clan-core.inputs.nix-darwin;
in
{
inherit self;
inherit nixpkgs nix-darwin;
};
modules = [
clan-core.modules.clan.default
];
};
};
buildClanModule = clan-core.clanLib.buildClanModule;
publicAttrs = import ../lib/build-clan/public.nix;
# Create output options only for listed attributes
# TODO: Refactor this into an explicit module, so we can have description and other attributes to be listed in flake-parts
outputModule = {
clan = lib.genAttrs publicAttrs.clan (
name: config.clan.${name} or (throw "Output: clan.${name} not found.")
);
topLevel = {
options = lib.genAttrs publicAttrs.topLevel (_: lib.mkOption { });
config = lib.genAttrs publicAttrs.topLevel (
name: config.clan.${name} or (throw "Output: clan.${name} not found.")
# Mapped flake toplevel outputs
darwinConfigurations = lib.mkOption {
type = types.lazyAttrsOf types.raw;
description = "darwinConfigurations produced by clan for a specific machine";
apply = lib.mapAttrs (
k: v: {
_file = "#nixosModules.${k}";
imports = [ v ];
}
);
};
darwinModules = lib.mkOption {
type = types.lazyAttrsOf types.deferredModule;
description = "darwinModules produced by clan for a specific machine";
apply = lib.mapAttrs (
k: v: {
_file = "#nixosModules.${k}";
imports = [ v ];
}
);
};
};
in
{
options.clan = lib.mkOption {
default = { };
type = types.submoduleWith {
specialArgs = {
inherit clan-core self;
inherit (inputs) nixpkgs nix-darwin;
# TODO: inject the inventory interface
# inventoryInterface = {};
};
modules = [
buildClanModule.flakePartsModule
];
};
};
options.flake = {
clan = lib.mkOption { type = types.raw; };
} // outputModule.topLevel.options;
config = {
flake = {
clan = outputModule.clan;
} // outputModule.topLevel.config;
# Use normal prio, to allow merging with user values
config.flake = {
inherit (config.flake.clan)
nixosConfigurations
nixosModules
darwinConfigurations
darwinModules
;
};
_file = __curPos.file;

View File

@@ -106,6 +106,13 @@
extraPythonPackages = (self'.packages.clan-app.devshellPyDeps pkgs.python3Packages);
extraPythonPaths = [ "../../clan-cli" ];
};
"generate-test-vars" = {
directory = "pkgs/generate-test-vars";
extraPythonPackages = [
(pkgs.python3.withPackages (ps: self'.packages.clan-cli.devshellPyDeps ps))
];
extraPythonPaths = [ "../clan-cli" ];
};
}
// (
if pkgs.stdenv.isLinux then

View File

@@ -9,110 +9,5 @@
"test-darwin-machine": {
"machineClass": "darwin"
}
},
"services": {
"zerotier": {
"one": {
"roles": {
"controller": {
"machines": ["test-inventory-machine"]
}
}
}
},
"borgbackup": {
"simple": {
"roles": {
"client": {
"machines": ["test-inventory-machine"]
},
"server": {
"tags": ["2"]
}
}
},
"double": {
"roles": {
"server": {
"machines": ["test-inventory-machine"]
},
"client": {
"tags": ["1"]
}
}
}
},
"packages": {
"editors": {
"meta": {
"name": "Some editor packages"
},
"roles": {
"default": {
"extraModules": [],
"machines": ["test-inventory-machine"],
"tags": []
}
},
"config": {},
"extraModules": [],
"machines": {
"test-inventory-machine": {
"config": {
"packages": ["hello"]
},
"extraModules": []
}
}
},
"browsing": {
"meta": {
"name": "Web browsing packages"
},
"roles": {
"default": {
"config": {},
"extraModules": [],
"machines": ["test-inventory-machine"],
"tags": []
}
},
"config": {},
"extraModules": [],
"machines": {
"test-inventory-machine": {
"config": {
"packages": ["chromium"]
},
"extraModules": []
}
}
}
},
"single-disk": {
"default": {
"meta": {
"name": "single-disk"
},
"roles": {
"default": {
"config": {},
"extraModules": [],
"machines": ["test-inventory-machine"],
"tags": []
}
},
"config": {},
"extraModules": [],
"machines": {
"test-inventory-machine": {
"config": {
"device": "/dev/null"
},
"extraModules": []
}
}
}
}
}
}

View File

@@ -1,83 +0,0 @@
## WARNING: Do not add core logic here.
## This is only a wrapper such that buildClan can be called as a function.
## Add any logic to ./module.nix
{
lib,
clanLib,
...
}:
{
flakePartsModule = {
imports = [
(lib.modules.importApply ./interface.nix { inherit clanLib; })
./module.nix
];
};
/**
A function that takes some arguments such as 'clan-core' and returns the 'buildClan' function.
# Arguments of the first function
- clan-core: Self, provided by our flake-parts module
- publicAttrs: { clan :: List Str, topLevel :: List Str } Publicly exported attribute names
# Arguments of the second function (aka 'buildClan')
- self: Reference to the users flake
- inventory: An "Inventory" attribute set, see the docs, for how to construct one
- specialArgs: Extra arguments to pass to nixosSystem i.e. useful to make self available
- ...: Any other argument of the 'clan' submodule. See the docs for all available options
# Returns
Public attributes of buildClan. As specified in publicAttrs.
*/
buildClanWith =
{
clan-core,
# TODO: Below should be module options such that the user can override them?
nixpkgs,
publicAttrs ? import ./public.nix,
nix-darwin ? null,
}:
{
## Inputs
self ? lib.warn "Argument: 'self' must be set when using 'buildClan'." null, # Reference to the current flake
# allows to include machine-specific modules i.e. machines.${name} = { ... }
# A map from arch to pkgs, if specified this nixpkgs will be only imported once for each system.
# This improves performance, but all nipxkgs.* options will be ignored.
# deadnix: skip
inventory ? { },
## Special inputs (not passed to the module system as config)
specialArgs ? { }, # Extra arguments to pass to nixosSystem i.e. useful to make self available
##
...
}@attrs:
let
eval = import ./function-adapter.nix {
inherit
lib
nixpkgs
nix-darwin
clan-core
self
;
inherit specialArgs;
};
rest = builtins.removeAttrs attrs [ "specialArgs" ];
result = eval {
imports = [
rest
# implementation
./module.nix
];
};
in
{
clan = lib.genAttrs publicAttrs.clan (
name:
result.clanInternals.${name}
or (throw "Output: clanInternals.${name} not found. Check: ${result.file}")
);
}
// lib.filterAttrs (name: _v: builtins.elem name publicAttrs.topLevel) result;
}

View File

@@ -1,27 +0,0 @@
{
lib,
nixpkgs,
nix-darwin ? null,
clan-core,
self,
specialArgs ? { },
}:
# Returns a function that takes self, which should point to the directory of the flake
module:
(lib.evalModules {
specialArgs = {
inherit
self
clan-core
nixpkgs
nix-darwin
;
};
modules = [
(lib.modules.importApply ./interface.nix { inherit (clan-core) clanLib; })
module
{
inherit specialArgs;
}
];
}).config

View File

@@ -1,21 +0,0 @@
/**
Publicly exported attribute names
These are mapped from 'options.clan.{name}' into 'flake.{name}'
For example "clanInternals" will be exposed as "flake.clan.clanInternals"
This list is used to guarantee equivalent attribute sets for both flake-parts and buildClan users.
*/
{
# flake.clan.{name} <- clan.{name}
clan = [
"templates"
"modules"
];
# flake.{name} <- clan.{name}
topLevel = [
"clanInternals"
"nixosConfigurations"
"nixosModules"
"darwinConfigurations"
"darwinModules"
];
}

View File

@@ -20,7 +20,7 @@ in
{
# A function that returns an extension to runTest
# TODO: remove this from clanLib, add to legacyPackages, simplify signature
flake.modules.nixosVmTest.clanTest =
flake.modules.nixosTest.clanTest =
{ config, hostPkgs, ... }:
let
testName = config.name;
@@ -87,7 +87,7 @@ in
self.packages.${hostPkgs.system}.generate-test-vars
}/bin/generate-test-vars";
relativeDir = removePrefix ("${self}/") (toString config.clan.directory);
relativeDir = removePrefix "${self}/" (toString config.clan.directory);
update-vars = hostPkgs.writeShellScriptBin "update-vars" ''
${update-vars-script} $PRJ_ROOT/${relativeDir} ${testName}
@@ -158,18 +158,31 @@ in
'';
# the test's flake.nix with locked clan-core input
flakeForSandbox = hostPkgs.runCommand "offline-flake-for-test-${config.name}" { } ''
cp -r ${config.clan.directory} $out
chmod +w -R $out
substituteInPlace $out/flake.nix \
--replace-fail \
"https://git.clan.lol/clan/clan-core/archive/main.tar.gz" \
"${clan-core.packages.${hostPkgs.system}.clan-core-flake}"
'';
flakeForSandbox =
hostPkgs.runCommand "offline-flake-for-test-${config.name}"
{
nativeBuildInputs = [ hostPkgs.nix ];
}
''
cp -r ${config.clan.directory} $out
chmod +w -R $out
substituteInPlace $out/flake.nix \
--replace-fail \
"https://git.clan.lol/clan/clan-core/archive/main.tar.gz" \
"${clan-core.packages.${hostPkgs.system}.clan-core-flake}"
# Create a proper lock file for the test flake
export HOME=$(mktemp -d)
nix flake lock $out \
--extra-experimental-features 'nix-command flakes' \
--override-input clan-core ${clan-core.packages.${hostPkgs.system}.clan-core-flake} \
--override-input nixpkgs ${clan-core.inputs.nixpkgs}
'';
in
{
imports = [
../test/container-test-driver/driver-module.nix
];
options = {
clanSettings = mkOption {
@@ -197,7 +210,7 @@ in
self = throw "set clan.directory in the test";
};
modules = [
clanLib.buildClanModule.flakePartsModule
clan-core.modules.clan.default
{
_prefix = [
"checks"

View File

@@ -1,62 +1,54 @@
{
lib,
self,
nixpkgs,
nix-darwin ? null,
...
}:
# Produces the
# 'clanLib' attribute set
# Wrapped with fix, so we can depend on other clanLib functions without passing the whole flake
lib.fix (clanLib: {
/**
Like callPackage, but doesn't try to automatically detect arguments
'lib' and 'clanLib' are always passed, plus the additional arguments
*/
callLib = file: args: import file ({ inherit lib clanLib; } // args);
lib.fix (
clanLib:
let
buildClanLib = (
clanLib.callLib ./modules {
clan-core = self;
}
);
in
{
# ------------------------------------
buildClan = clanLib.buildClanModule.buildClanWith {
clan-core = self;
inherit nixpkgs nix-darwin;
};
evalServiceSchema =
self:
{
moduleSpec,
flakeInputs ? self.inputs,
localModuleSet ? self.clan.modules,
}:
let
resolvedModule = clanLib.inventory.resolveModule {
inherit moduleSpec flakeInputs localModuleSet;
};
in
(clanLib.inventory.evalClanService {
modules = [ resolvedModule ];
prefix = [ ];
}).config.result.api.schema;
# ------------------------------------
# ClanLib functions
evalClan = clanLib.callLib ./inventory/eval-clan-modules { };
buildClanModule = clanLib.callLib ./build-clan { };
inventory = clanLib.callLib ./inventory { };
modules = clanLib.callLib ./inventory/frontmatter { };
test = clanLib.callLib ./test { };
# Custom types
types = clanLib.callLib ./types { };
inherit (buildClanLib)
buildClan
clan
;
/**
Like callPackage, but doesn't try to automatically detect arguments
'lib' and 'clanLib' are always passed, plus the additional arguments
*/
callLib = file: args: import file ({ inherit lib clanLib; } // args);
# Plain imports.
introspection = import ./introspection { inherit lib; };
jsonschema = import ./jsonschema { inherit lib; };
facts = import ./facts.nix { inherit lib; };
evalService = clanLib.callLib ./modules/inventory/distributed-service/evalService.nix { };
# ------------------------------------
# ClanLib functions
evalClan = clanLib.callLib ./modules/inventory/eval-clan-modules { };
inventory = clanLib.callLib ./modules/inventory { };
modules = clanLib.callLib ./modules/inventory/frontmatter { };
test = clanLib.callLib ./test { };
# Custom types
types = clanLib.callLib ./types { };
# flakes
flakes = clanLib.callLib ./flakes.nix {
clan-core = self;
};
# Plain imports.
introspection = import ./introspection { inherit lib; };
jsonschema = import ./jsonschema { inherit lib; };
facts = import ./facts.nix { inherit lib; };
# deprecated
# remove when https://git.clan.lol/clan/clan-core/pulls/3212 is implemented
inherit (self.inputs.nix-select.lib) select;
})
# flakes
flakes = clanLib.callLib ./flakes.nix {
clan-core = self;
};
# deprecated
# remove when https://git.clan.lol/clan/clan-core/pulls/3212 is implemented
inherit (self.inputs.nix-select.lib) select;
}
)

View File

@@ -7,16 +7,15 @@
rec {
# TODO: automatically generate this from the directory conventions
imports = [
./build-clan/flake-module.nix
./modules/flake-module.nix
./clanTest/flake-module.nix
./introspection/flake-module.nix
./inventory/flake-module.nix
./modules/inventory/flake-module.nix
./jsonschema/flake-module.nix
./types/flake-module.nix
];
flake.clanLib = import ./default.nix {
inherit lib inputs self;
inherit (inputs) nixpkgs nix-darwin;
};
# TODO: remove this legacy alias
flake.lib = flake.clanLib;

View File

@@ -40,7 +40,7 @@ in
{ ... }:
{
imports = [
self.modules.nixosVmTest.clanTest
self.modules.nixosTest.clanTest
testModule
];
@@ -68,7 +68,7 @@ in
{ ... }:
{
imports = [
self.modules.nixosVmTest.clanTest
self.modules.nixosTest.clanTest
testModule
];

View File

@@ -1,90 +0,0 @@
# 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.
Open questions:
- [ ] How do we set default role, description and other metadata?
- It must be accessible from Python.
- It must set the value in the module system.
- [ ] Inventory might use assertions. Should each machine inherit the inventory assertions ?
- [ ] Is the service config interface the same as the module config interface ?
- [ ] As a user do I want to see borgbackup as the high level category?
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.
```
## 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.
```cue
// 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.
```cue
foo: { ... }
```
Cue dynamic keys.
```cue
[string]: {
attr: string
}
```
This is the schema of
```json
{
"a": {
"attr": "foo"
},
"b": {
"attr": "bar"
}
// ... Indefinitely more dynamic keys of type "string"
}
```

View File

@@ -1,49 +0,0 @@
# Generate partial NixOS configurations for every machine in the inventory
# This function is responsible for generating the module configuration for every machine in the inventory.
{ lib, clanLib }:
let
/*
Returns a set with NixOS configuration for every machine in the inventory.
machinesFromInventory :: Inventory -> { ${machine_name} :: NixOSConfiguration }
*/
buildInventory =
{
inventory,
directory,
flakeInputs,
prefix ? [ ],
localModuleSet ? { },
}:
(lib.evalModules {
# TODO: remove clanLib from specialArgs
specialArgs = {
inherit clanLib;
};
modules = [
./builder
(lib.modules.importApply ./service-list-from-inputs.nix {
inherit flakeInputs clanLib localModuleSet;
})
{ inherit directory inventory; }
(
# config.distributedServices.allMachines.${name} or [ ];
{ config, ... }:
{
distributedServices = clanLib.inventory.mapInstances {
inherit (config) inventory;
inherit localModuleSet;
inherit flakeInputs;
prefix = prefix ++ [ "distributedServices" ];
};
machines = config.distributedServices.allMachines;
}
)
(lib.modules.importApply ./inventory-introspection.nix { inherit clanLib; })
];
}).config;
in
{
inherit buildInventory;
}

View File

@@ -9,7 +9,7 @@
{ machines, ... }:
{
# Only compute the default value
# The option MUST be defined in ./build-inventory/interface.nix
# The option MUST be defined in inventoryClass/interface.nix
all = lib.mkDefault (builtins.attrNames machines);
nixos = lib.mkDefault (
builtins.attrNames (lib.filterAttrs (_n: m: m.machineClass == "nixos") machines)

View File

@@ -0,0 +1,12 @@
{ clan-core }:
{
_class = "clan";
_module.args = {
inherit clan-core;
inherit (clan-core) clanLib;
};
imports = [
./module.nix
./interface.nix
];
}

View File

@@ -0,0 +1,4 @@
{ self, lib, ... }:
{
flake.modules.clan.default = lib.modules.importApply ./default.nix { clan-core = self; };
}

View File

@@ -1,6 +1,6 @@
{ clanLib }:
{
lib,
clanLib,
self,
# TODO: Use dependency injection to allow for testing
# inventoryInterface,
@@ -90,7 +90,7 @@ in
};
templates = lib.mkOption {
type = types.submodule { imports = [ ./templates/interface.nix ]; };
type = types.submodule { imports = [ ./templates.nix ]; };
default = { };
description = ''
Define Clan templates.
@@ -100,7 +100,11 @@ in
inventory = lib.mkOption {
type = types.submodule {
imports = [
(lib.modules.importApply ../inventory/build-inventory/interface.nix { inherit clanLib; })
{
_module.args = { inherit clanLib; };
_file = "clan interface";
}
../inventoryClass/interface.nix
];
};
description = ''
@@ -116,13 +120,13 @@ in
Global information about the clan.
'';
type = types.deferredModuleWith {
staticModules = [ ../inventory/build-inventory/meta-interface.nix ];
staticModules = [ ../inventoryClass/meta-interface.nix ];
};
default = { };
};
secrets = lib.mkOption {
type = types.submodule { imports = [ ./secrets/interface.nix ]; };
type = types.submodule { imports = [ ./secrets.nix ]; };
description = ''
Secrets related options such as AGE plugins required to encrypt/decrypt secrets using the CLI.
'';
@@ -203,7 +207,11 @@ in
clanModules = lib.mkOption { type = lib.types.raw; };
# The machine 'imports' generated by the inventory per machine
inventoryClass = lib.mkOption { type = lib.types.raw; };
inventoryClass = lib.mkOption {
type = types.submoduleWith {
modules = [ ];
};
};
# TODO: remove all dependents in python, delete this option
inventory = lib.mkOption {

View File

@@ -19,8 +19,6 @@ let
specialArgs
;
inherit (clan-core.clanLib.inventory) buildInventory;
supportedSystems = [
"x86_64-linux"
"aarch64-linux"
@@ -43,18 +41,7 @@ let
if pkgs != null then pkgs else nixpkgs.legacyPackages.${system}
);
# map from machine name to service configuration
# { ${machineName} :: Config }
inventoryClass = (
buildInventory {
inherit inventory directory;
flakeInputs = config.self.inputs;
prefix = config._prefix ++ [ "inventoryClass" ];
# TODO: remove inventory.modules, this is here for backwards compatibility
localModuleSet =
lib.filterAttrs (n: _: !inventory._legacyModules ? ${n}) inventory.modules // config.modules;
}
);
inherit (clan-core) clanLib;
moduleSystemConstructor = {
# TODO: remove default system once we have a hardware-config mechanism
@@ -62,7 +49,7 @@ let
darwin = nix-darwin.lib.darwinSystem;
};
allMachines = inventoryClass.machines; # <- inventory.machines <- clan.machines
allMachines = config.clanInternals.inventoryClass.machines; # <- inventory.machines <- clan.machines
machineClasses = lib.mapAttrs (
name: _: inventory.machines.${name}.machineClass or "nixos"
@@ -120,7 +107,7 @@ let
moduleSystemConstructor.${machineClasses.${name}} {
modules = [
(config.outputs.moduleForMachine.${name} or { })
(lib.modules.importApply ./machineModules/overridePkgs.nix {
(lib.modules.importApply ../machineModules/overridePkgs.nix {
pkgs = pkgsFor.${system};
})
];
@@ -178,7 +165,6 @@ in
config = {
inventory.modules = clan-core.clanModules;
inventory._legacyModules = clan-core.clanModules;
# Merge the meta attributes from the buildClan function
inventory.meta = config.meta;
outputs.moduleForMachine = lib.mkMerge [
@@ -201,7 +187,7 @@ in
in
{
imports = [
(lib.modules.importApply ./machineModules/forName.nix {
(lib.modules.importApply ../machineModules/forName.nix {
inherit (config.inventory) meta;
inherit
name
@@ -219,7 +205,7 @@ in
networking.hostName = lib.mkDefault name;
}
)
) inventoryClass.machines)
) config.clanInternals.inventoryClass.machines)
# The user can define some machine config here
# i.e. 'clan.machines.jon = ...'
@@ -241,7 +227,39 @@ in
inherit darwinConfigurations;
clanInternals = {
inherit inventoryClass;
inventoryClass =
let
localModuleSet =
lib.filterAttrs (n: _: !inventory._legacyModules ? ${n}) inventory.modules // config.modules;
flakeInputs = config.self.inputs;
in
{
_module.args = {
inherit clanLib;
};
imports = [
../inventoryClass/builder/default.nix
(lib.modules.importApply ../inventoryClass/service-list-from-inputs.nix {
inherit localModuleSet flakeInputs clanLib;
})
{
inherit inventory directory;
}
(
{ config, ... }:
{
distributedServices = clanLib.inventory.mapInstances {
inherit (config) inventory;
inherit localModuleSet flakeInputs;
prefix = [ "distributedServices" ];
};
machines = config.distributedServices.allMachines;
}
)
../inventoryClass/inventory-introspection.nix
];
};
# TODO: remove this after a month or so
# This is here for backwards compatibility for older CLI versions
inventory = config.inventory;

38
lib/modules/default.nix Normal file
View File

@@ -0,0 +1,38 @@
## WARNING: Do not add core logic here.
## This is only a wrapper such that 'clan' can be called as a function.
{
lib,
clan-core,
...
}:
rec {
buildClan =
# TODO: Once all templates and docs are migrated add: lib.warn "'buildClan' is deprecated. Use 'clan-core.lib.clan' instead"
module: (clan module).config;
clan =
{
self ? lib.warn "Argument: 'self' must be set" null, # Reference to the current flake
...
}@m:
let
nixpkgs = self.inputs.nixpkgs or clan-core.inputs.nixpkgs;
nix-darwin = self.inputs.nix-darwin or clan-core.inputs.nix-darwin;
in
lib.evalModules {
class = "clan";
specialArgs = {
inherit
self
;
inherit
nixpkgs
nix-darwin
;
};
modules = [
m
clan-core.modules.clan.default
];
};
}

View File

@@ -1,13 +1,12 @@
{
pkgs,
lib,
clanLib,
clan-core,
}:
let
eval = lib.evalModules {
class = "nixos";
modules = [
(lib.modules.importApply ./interface.nix { inherit clanLib; })
clan-core.modules.clan.default
];
};
evalDocs = pkgs.nixosOptionsDoc {

View File

@@ -9,6 +9,9 @@ let
);
in
{
imports = [
./clan/flake-module.nix
];
perSystem =
{
pkgs,
@@ -19,7 +22,7 @@ in
let
jsonDocs = import ./eval-docs.nix {
inherit pkgs lib;
inherit (self) clanLib;
clan-core = self;
};
in
{

View File

@@ -3,9 +3,14 @@ let
services = clanLib.callLib ./distributed-service/inventory-adapter.nix { };
in
{
inherit (services) evalClanService mapInstances resolveModule;
inherit (import ./build-inventory { inherit lib clanLib; }) buildInventory;
interface = lib.modules.importApply ./build-inventory/interface.nix { inherit clanLib; };
inherit (services) mapInstances;
interface = {
_file = "clanLib.inventory.interface";
imports = [
../inventoryClass/interface.nix
];
_module.args = { inherit clanLib; };
};
# Returns the list of machine names
# { ... } -> [ string ]
resolveTags =

View File

@@ -0,0 +1,30 @@
/*
Example usage:
```nix
evalService = import /this/file.nix { inherit lib clanLib; };
result = evalService { modules = []; prefix = []; };
=> result.config
=> result.options
```
*/
{ lib, clanLib }:
# <lambda evalService>
{ modules, prefix }:
lib.evalModules {
class = "clan.service";
specialArgs._ctx = prefix;
modules =
[
# Base module
./service-module.nix
# Feature modules
(lib.modules.importApply ./api-feature.nix {
inherit clanLib prefix;
})
]
++
# Modules of caller
modules;
}

View File

@@ -15,67 +15,9 @@
...
}:
let
evalClanService =
{ modules, prefix }:
(lib.evalModules {
class = "clan.service";
specialArgs._ctx = prefix;
modules = [
./service-module.nix
# feature modules
(lib.modules.importApply ./api-feature.nix {
inherit clanLib prefix;
})
] ++ modules;
});
resolveModule =
{
moduleSpec,
flakeInputs,
localModuleSet,
}:
let
# TODO:
resolvedModuleSet =
# If the module.name is self then take the modules defined in the flake
# Otherwise its an external input which provides the modules via 'clan.modules' attribute
if moduleSpec.input == null then
localModuleSet
else
let
input =
flakeInputs.${moduleSpec.input} or (throw ''
Flake doesn't provide input with name '${moduleSpec.input}'
Choose one of the following inputs:
- ${
builtins.concatStringsSep "\n- " (
lib.attrNames (lib.filterAttrs (_name: input: input ? clan) flakeInputs)
)
}
To import a local module from 'clan.modules' remove the 'input' attribute from the module definition
Remove the following line from the module definition:
...
- module.input = "${moduleSpec.input}"
'');
clanAttrs =
input.clan
or (throw "It seems the flake input ${moduleSpec.input} doesn't export any clan resources");
in
clanAttrs.modules;
resolvedModule =
resolvedModuleSet.${moduleSpec.name}
or (throw "flake doesn't provide clan-module with name ${moduleSpec.name}");
in
resolvedModule;
resolveModule = import ./resolveModule.nix { inherit lib; };
in
{
inherit evalClanService resolveModule;
mapInstances =
{
# This is used to resolve the module imports from 'flake.inputs'
@@ -151,7 +93,7 @@ in
# TODO: Eagerly check the _class of the resolved module
importedModulesEvaluated = lib.mapAttrs (
module_ident: instances:
evalClanService {
clanLib.evalService {
prefix = prefix ++ [ module_ident ];
modules =
[
@@ -201,5 +143,4 @@ in
importedModulesEvaluated
;
};
}

View File

@@ -0,0 +1,43 @@
{ lib }:
{
moduleSpec,
flakeInputs,
localModuleSet,
}:
let
resolvedModuleSet =
# If the module.name is self then take the modules defined in the flake
# Otherwise its an external input which provides the modules via 'clan.modules' attribute
if moduleSpec.input == null then
localModuleSet
else
let
input =
flakeInputs.${moduleSpec.input} or (throw ''
Flake doesn't provide input with name '${moduleSpec.input}'
Choose one of the following inputs:
- ${
builtins.concatStringsSep "\n- " (
lib.attrNames (lib.filterAttrs (_name: input: input ? clan) flakeInputs)
)
}
To import a local module from 'clan.modules' remove the 'input' attribute from the module definition
Remove the following line from the module definition:
...
- module.input = "${moduleSpec.input}"
'');
clanAttrs =
input.clan
or (throw "It seems the flake input ${moduleSpec.input} doesn't export any clan resources");
in
clanAttrs.modules;
resolvedModule =
resolvedModuleSet.${moduleSpec.name}
or (throw "flake doesn't provide clan-module with name ${moduleSpec.name}");
in
resolvedModule

Some files were not shown because too many files have changed in this diff Show More