Compare commits

...

383 Commits

Author SHA1 Message Date
f4283982b3 Merge pull request 'fix fake-etc build on machines without sandbox' (#1645) from fix-macos-deploy into main 2024-06-21 15:05:45 +00:00
6086f27263 fix fake-etc build on machines without sandbox
If we have no sandbox enabled or on macos with sandbox enabled, /etc
contains a lot more files than we actually want.
Instead of copying some random files, we now just create those files
ourself.
2024-06-21 17:01:40 +02:00
0dfa1d969f Merge pull request 'clan-cli: Add validity check for age key generation' (#1642) from Qubasa/clan-core:Qubasa-main into main 2024-06-21 13:18:34 +00:00
1ff58adcef clan-cli: Add validity check for age key generation 2024-06-21 15:07:53 +02:00
641ec7e097 Merge pull request 'clan-cli: Disable stack trace on KeyboardInterrupt' (#1641) from Qubasa/clan-core:Qubasa-main into main 2024-06-21 11:14:47 +00:00
8ee33950e6 clan-cli: Disable stack trace on KeyboardInterrupt 2024-06-21 13:11:33 +02:00
b3123b150f Merge pull request 'clan.core.state: wrap all commands in shell scripts' (#1639) from refactor-state into main 2024-06-20 16:20:31 +00:00
20b952b4cd fix dropping non-existing database 2024-06-19 18:00:51 +02:00
aa5ccfb8bd clanCore -> clan.core 2024-06-19 17:55:59 +02:00
ef9ed1ebea clan.core.state: wrap all commands in shell scripts
Otherwise we cannot execute them via ssh and also have nix store
dependencies.
2024-06-19 17:54:46 +02:00
117aed49e3 postgresql: don't prepend postgresql- for states 2024-06-19 17:38:31 +02:00
9bbf7f668a Merge pull request 'Inventory: add concrete use-case examples' (#1636) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-19 11:08:04 +00:00
afdfa6181b
Inventory: add concrete use-case examples 2024-06-19 13:04:10 +02:00
6c11e0ced7 Merge pull request 'UI: display block devices' (#1635) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-19 09:39:41 +00:00
399ce2e35c
UI: display block devices 2024-06-19 11:36:19 +02:00
e575c2e769 Merge pull request 'UI: display known network hosts' (#1633) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-19 09:11:01 +00:00
56b2347a30
UI: display known network hosts 2024-06-19 11:07:45 +02:00
70954acf3d Merge pull request 'Inventory: init draft ideas' (#1632) from hsjobeki/clan-core:hsjobeki-inventory into main 2024-06-19 07:50:12 +00:00
13aa60529f
Inventory: init draft ideas 2024-06-19 09:47:13 +02:00
7474f01193
Inventory: init draft ideas 2024-06-19 09:40:23 +02:00
bd9883baaf Merge pull request 'refactor: rename clanCore -> clan.core' (#1629) from DavHau/clan-core:DavHau-rename-clanCore into main 2024-06-18 11:35:57 +00:00
313db5643f refactor: rename clanCore -> clan.core 2024-06-18 18:32:40 +07:00
93a6d7a476 Merge pull request 'update matrix address' (#1631) from new-matrix-address into main 2024-06-17 13:32:07 +00:00
d221d90972 update matrix address 2024-06-17 15:26:23 +02:00
30fd5dcfb8 Merge pull request 'matrix-synapse: restart service on restore' (#1630) from clan-name into main 2024-06-17 12:30:03 +00:00
c79680344d fix restore if database does not exists 2024-06-17 14:21:45 +02:00
ad544a7d24 matrix-synapse: restart service on restore 2024-06-17 14:21:45 +02:00
1cd606b879 Merge pull request 'fix: remove IFD in nix flake show' (#1628) from DavHau/clan-core:DavHau-dave into main 2024-06-17 08:09:39 +00:00
39f74c0f52 fix: remove IFD in nix flake show 2024-06-17 15:06:25 +07:00
8feea28a19 Merge pull request 'API: init methods: hw_generate, dns discovery' (#1626) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-16 14:32:42 +00:00
b73246bdfd
API: init methods: hw_generate, dns discovery 2024-06-16 16:29:18 +02:00
36a418b6ac Merge pull request 'Docs: update machine hardware config instructions' (#1625) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-15 20:30:50 +00:00
43e8804eb4
Docs: update machine hardware config instructions 2024-06-15 22:27:46 +02:00
8790e5a0eb Merge pull request 'CLI: init hw-generate command' (#1624) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-15 19:35:56 +00:00
5e39514251
CLI: init hw-generate command 2024-06-15 21:31:23 +02:00
b28950f310 Merge pull request 'API: init op_key, improve seralisation & signature typing' (#1622) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-15 09:38:29 +00:00
3ebee252aa
Webview: init machine details 2024-06-15 11:35:15 +02:00
720fb4af63
Webview: minor improvements 2024-06-15 11:34:54 +02:00
af19950dfa
Webview: init global state for current clan path 2024-06-15 11:34:20 +02:00
149be249fa
Webview: init api event registry 2024-06-15 11:33:53 +02:00
0cf86806b2
API: mock echo op_key 2024-06-15 11:32:42 +02:00
cb847cab82
API: init op_key, improve seralisation & signature typing 2024-06-15 11:32:09 +02:00
a89fd31844 Merge pull request 'matrix-synapse: user creation fixes' (#1620) from matrix into main 2024-06-14 09:36:41 +00:00
870948306d postgres: handle restores without associated systemd service 2024-06-14 11:29:59 +02:00
ec49d1f844 container-driver: source nixos environment variables in test commands 2024-06-14 11:27:06 +02:00
e3d84a5daf matrix-synapse: use upstream patch to create users declarativly 2024-06-14 11:27:06 +02:00
79b5ad0754 matrix-synapse: use registration_shared_secret_path instead 2024-06-14 11:18:09 +02:00
24b0d72d96 matrix-synapse: fix user check 2024-06-14 11:18:09 +02:00
084cd8751f postgresql: move postRestoreCommand to a dedicated command
We need to call this command from the cli
2024-06-14 11:18:09 +02:00
3d77e0a3a9 Merge pull request 'fix: outside of direnv clan-li warns show-config deprecated' (#1619) from samrose/clan-core:sam/show-config into main
Reviewed-on: clan/clan-core#1619
Reviewed-by: kenji <aks.kenji@protonmail.com>
2024-06-14 08:10:29 +00:00
06bbae6d14 fix: trying run_no_stdout with original show-config 2024-06-13 18:44:50 -04:00
5f22493361 fix: formatting cli command correctly 2024-06-13 12:59:26 -04:00
56a4caf39b fix: outside of direnv clan-li warns this is going to be deprecated 2024-06-13 12:44:48 -04:00
83056f743d Merge pull request 'API: init icon resolve' (#1616) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-12 11:24:45 +00:00
6743ff96a9
API: init icon resolve 2024-06-12 13:21:39 +02:00
1f3c4f4ac3 Merge pull request 'vm.nix: fix typo in comment' (#1611) from DavHau/clan-core:DavHau-dave into main 2024-06-11 21:49:18 +00:00
7766829fb1 vm.nix: fix typo in comment 2024-06-11 14:44:08 -07:00
175b219246 Merge pull request 'API: improve type & class construction' (#1610) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-11 17:23:42 +00:00
48aee84547
Webview: add form handling for create clan 2024-06-11 19:20:40 +02:00
d587b326b5
API: improve type & class construction 2024-06-11 19:20:40 +02:00
ac099d9e6f Merge pull request 'Webview/API: init open clan workflow' (#1609) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-11 14:31:51 +00:00
913ab4627c
Webview: init 'open clan' workflow 2024-06-11 16:28:02 +02:00
be868ee107 Merge pull request 'matrix-synapse: add missing xkcdpass to password generator' (#1608) from matrix into main 2024-06-11 13:44:08 +00:00
36b1bb65af matrix-synapse: add missing xkcdpass to password generator 2024-06-11 15:40:58 +02:00
4a752bb951 Merge pull request 'matrix-synapse: drop drop security.wrappers' (#1607) from nixos-images-input into main
Reviewed-on: clan/clan-core#1607
2024-06-11 13:32:58 +00:00
3dabb4e89a matrix-synapse: drop drop security.wrappers
This was debug code and not meant for production.
2024-06-11 13:32:58 +00:00
e2474f4e66 Merge pull request 'matrix-synapse: don't require to set default users' (#1606) from Mic92-nixos-images-input into main 2024-06-11 13:18:37 +00:00
f4ee0b0387 Merge pull request 'drop nixos-stable' (#1605) from nixos-images-input into main 2024-06-11 13:13:48 +00:00
5df1f9f9d2 matrix-synapse: don't require to set default users 2024-06-11 15:12:41 +02:00
3368255473 drop nixos-stable 2024-06-11 15:03:57 +02:00
1cbb2d6aa4 Merge pull request 'matrix-synapse: add automatic user creation' (#1603) from synapse into main 2024-06-11 11:22:32 +00:00
bc0e0088a0 matrix-synapse: add automatic user creation 2024-06-11 13:19:18 +02:00
a6a9f763db Merge pull request 'api: refactor create flake into create clan' (#1602) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-11 10:15:44 +00:00
8dcb009e5b
api: refactor create flake into create clan 2024-06-11 12:11:29 +02:00
9f0f44b470 Merge pull request 'borbackup: set IdentitiesOnly=Yes' (#1601) from kenji/clan-core:identities into main
Reviewed-on: clan/clan-core#1601
2024-06-10 14:09:14 +00:00
67aa84760d borbackup: set IdentitiesOnly=Yes
Since `borgbackup` is run as root user it might try other ssh keys.
2024-06-10 14:09:14 +00:00
b05c937151 Merge pull request 'backups: extend tests to also check state.preBackupCommand' (#1600) from synapse into main 2024-06-10 14:01:53 +00:00
3322bbd681 backups: extend tests to also check state.preBackupCommand 2024-06-10 15:57:41 +02:00
a1acf0b05d Merge pull request 'Expand backup and restore capabilities w.r.t. postgresql.' (#1582) from synapse into main 2024-06-10 13:24:08 +00:00
66bdc61e3d borgbackup: move preBackupScript to a different systemd context 2024-06-10 15:17:46 +02:00
dd2bd2f989 Merge pull request 'test: extend minimal flake test with verification' (#1599) from DavHau/clan-core:DavHau-dave into main 2024-06-10 05:24:17 +00:00
6f18a5de92 test: extend minimal flake test with verification 2024-06-09 22:19:38 -07:00
1d542d4396 Merge pull request 'tests: add test for creating machine on minimal clan' (#1596) from DavHau/clan-core:DavHau-dave into main 2024-06-10 04:58:02 +00:00
07fb01d9db tests: add test for creating machine on minimal clan 2024-06-09 21:54:04 -07:00
8a5d4a0f8f Merge pull request 'Automatic flake update - 2024-06-10T00:00+00:00' (#1598) from flake-update-2024-06-10 into main 2024-06-10 00:05:18 +00:00
Clan Merge Bot
48069f99cd update flake lock - 2024-06-10T00:00+00:00
Flake lock file updates:

• Updated input 'disko':
    'github:nix-community/disko/0274af4c92531ebfba4a5bd493251a143bc51f3c' (2024-05-31)
  → 'github:nix-community/disko/1bbdb06f14e2621290b250e631cf3d8948e4d19b' (2024-06-09)
• Updated input 'nixos-images':
    'github:nix-community/nixos-images/47bfb55316e105390dd761e0b6e8e0be09462b67' (2024-05-30)
  → 'github:nix-community/nixos-images/72771bd35f4e19e32d6f652528483b5e07fc317b' (2024-06-07)
• Removed input 'nixos-images/nixos-2311'
• Added input 'nixos-images/nixos-stable':
    'github:NixOS/nixpkgs/0b8e7a1ae5a94da2e1ee3f3030a32020f6254105' (2024-06-05)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/6634a0509e9e81e980b129435fbbec518ab246d0' (2024-06-02)
  → 'github:NixOS/nixpkgs/7d916e720af6b2ca355e4d0cfb8e4f742c172239' (2024-06-09)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/ab2a43b0d21d1d37d4d5726a892f714eaeb4b075' (2024-06-02)
  → 'github:Mic92/sops-nix/f0922ad001829b400f0160ba85b47d252fa3d925' (2024-06-09)
• Updated input 'treefmt-nix':
    'github:numtide/treefmt-nix/3eb96ca1ae9edf792a8e0963cc92fddfa5a87706' (2024-06-01)
  → 'github:numtide/treefmt-nix/4fc1c45a5f50169f9f29f6a98a438fb910b834ed' (2024-06-08)
2024-06-10 00:00:22 +00:00
1eaf6cec39 Merge pull request 'gui-installer: fix maintainer name' (#1597) from kenji/clan-core:fix-name into main
Reviewed-on: clan/clan-core#1597
2024-06-09 12:49:14 +00:00
f0c9de9e50 gui-installer: fix maintainer name 2024-06-09 14:28:54 +02:00
ef42bcc525 Merge pull request 'templates: add minimal clan flake template for (G)UI' (#1595) from DavHau/clan-core:DavHau-dave into main 2024-06-09 00:05:02 +00:00
e7995ad344 templates: add minimal clan flake template for (G)UI 2024-06-08 17:00:18 -07:00
6e3c2506c9 Merge pull request 'Clan-cli/show: more detailed description' (#1594) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-08 16:28:36 +00:00
5473e2733c
Clan-cli/show: more detailed description 2024-06-08 18:24:54 +02:00
006a7044f1 Merge pull request 'Webview: add solid-toast feeback system' (#1593) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-08 16:17:59 +00:00
c647197b8c
Webview: add solid-toast feeback system 2024-06-08 18:14:15 +02:00
62735ebfe2 Merge pull request 'API: add show clan to retrieve the buildClan meta' (#1592) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-08 16:11:43 +00:00
8ff00fd8fe
API: include show into docs 2024-06-08 18:07:41 +02:00
bd586575b3
API: add show clan to retrieve the buildClan meta 2024-06-08 17:53:17 +02:00
f14f7368d7 Merge pull request 'API: add abstract open_file method, implement open_file' (#1591) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-08 15:09:35 +00:00
6adcd1fdf2
API: add abstract open_file method, implement open_file 2024-06-08 17:04:56 +02:00
6e99beb335 Merge pull request 'UI: add open clan button' (#1590) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-08 13:28:18 +00:00
6689d45a4f
UI: add open clan button 2024-06-08 15:24:18 +02:00
6d82a5851b Merge pull request 'api: list files' (#1589) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-08 13:05:52 +00:00
337ba1f8f6
api: list files 2024-06-08 15:01:53 +02:00
bf7b148592 Merge pull request 'clan: fix backup provider completions' (#1587) from kenji/clan-core:clan-complete-providers into main
Reviewed-on: clan/clan-core#1587
2024-06-07 19:16:13 +00:00
a7f724a804 clan: fix backup provider completions 2024-06-07 19:16:13 +00:00
7c06b65def Merge pull request 'gui-installer: calculate bugfix version from lastModifiedDate' (#1588) from DavHau/clan-core:DavHau-dave into main 2024-06-07 18:39:28 +00:00
7286c7250c gui-installer: calculate bugfix version from lastModifiedDate 2024-06-07 11:35:25 -07:00
4e841d3087 Merge pull request 'clan: remove very obvious comments' (#1586) from kenji/clan-core:clan/package/clean into main
Reviewed-on: clan/clan-core#1586
2024-06-07 13:20:23 +00:00
2ce704dd40 clan: remove very obvious comments
Remove some very obvious comments as to not lose meaning of the
comments.

We want comments that convey non-obvious behavior so they will be
actually read.
2024-06-07 14:45:53 +02:00
6279610691 Merge pull request 'syncthing: automatically add zt network ip to devices' (#1585) from kenji/clan-core:syncthing/add-ip into main
Reviewed-on: clan/clan-core#1585
2024-06-07 12:33:09 +00:00
297d53dac8 syncthing: automatically add zt network ip to devices 2024-06-07 14:25:21 +02:00
6f1300f819 Merge pull request 'clan: install shell completions for zsh' (#1584) from kenji/clan-core:enable-zsh-completions into main
Reviewed-on: clan/clan-core#1584
2024-06-07 07:57:40 +00:00
02a015a1b6 clan: install shell completions for zsh 2024-06-06 23:20:54 +02:00
5c11a30b46 backup: add a way to stop services before restoring a state. 2024-06-06 17:30:35 +02:00
0dc3b9f056 postgresql: add backup and restore 2024-06-06 14:28:50 +02:00
c0d8aaf73a postgresql: add new method to create users and databases 2024-06-06 14:07:56 +02:00
2a0019457d matrix-synapse: create with utf-8 encoding 2024-06-06 14:07:56 +02:00
6dec2a9222 add postgresql backup hooks 2024-06-06 13:27:30 +02:00
f71295e640 fix running cli without arguments 2024-06-06 13:27:30 +02:00
c1aedc5bb8 matrix-enable: drop enable option 2024-06-06 13:27:30 +02:00
d6a9f6d3f9 change clan url to gitea archive url 2024-06-06 11:11:48 +02:00
ba6840d978 matrix-synapse: create database with right collation also when postgresql already exists #1108 2024-06-06 11:11:48 +02:00
86b08258dd Merge pull request 'syncthing-remove-newline' (#1581) from kenji/clan-core:syncthing-remove-newline into main
Reviewed-on: clan/clan-core#1581
2024-06-06 08:34:08 +00:00
9ccff4ab2e syncthing: remove trailing newline 2024-06-06 08:34:08 +00:00
cf310be1c8 Merge pull request 'syncthing: update facts to new system' (#1580) from kenji/clan-core:syncthing/update into main
Reviewed-on: clan/clan-core#1580
2024-06-06 08:21:31 +00:00
d8e80bb0c8 syncthing: update facts to new system 2024-06-06 08:21:31 +00:00
9206182e15 Merge pull request 'modules/syncthing-static-peers: init' (#1579) from kenji/clan-core:init/static-syncthing into main
Reviewed-on: clan/clan-core#1579
2024-06-06 08:01:09 +00:00
d25eaa48d0 modules/syncthing-static-peers: init 2024-06-06 09:55:57 +02:00
5a2c91959a Merge pull request 'borbackup-static: impl' (#1577) from kenji/clan-core:modules/init/borbackup-static-impl into main
Reviewed-on: clan/clan-core#1577
2024-06-05 21:17:24 +00:00
193d54153d borbackup-static: impl
Implements sane defaults implementing borgbackup

Fixes: #1551
2024-06-05 21:17:24 +00:00
510634bc04 Merge pull request 'zerotier-static-peers: filter out non existing Ip' (#1576) from kenji/clan-core:fix/static-zerotier into main
Reviewed-on: clan/clan-core#1576
2024-06-05 17:52:59 +00:00
954f1fe605 zerotier-static-peers: filter out non existing Ip 2024-06-05 19:46:55 +02:00
764b53275f Merge pull request 'static-hosts: filter out non existing Ip's' (#1574) from kenji/clan-core:static-hosts-fix into main
Reviewed-on: clan/clan-core#1574
2024-06-05 15:32:57 +00:00
44fc1be270 static-hosts: filter out non existing Ip's 2024-06-05 17:28:35 +02:00
5ef170020d Merge pull request 'clan-cli: Fix passwordstore clan facts generate requiring CTRL+D for every secret' (#1573) from Qubasa/clan-core:Qubasa-main into main 2024-06-05 12:37:02 +00:00
5f7099fc89 clan-cli: Fix passwordstore clan facts generate requiring CTRL+D for every secret 2024-06-05 14:31:45 +02:00
fe08fef015 Merge pull request 'clan-cli: temporary_home, set XDG_RUNTIME_DIR' (#1571) from Qubasa/clan-core:Qubasa-main into main 2024-06-05 11:39:14 +00:00
edb744f654 Merge pull request 'clan: improve machine completions' (#1572) from kenji/clan-core:clan/dynamic-completions into main
Reviewed-on: clan/clan-core#1572
2024-06-05 11:38:50 +00:00
5ff5b46896 clan-cli: temporary_home, set XDG_RUNTIME_DIR 2024-06-05 13:34:17 +02:00
49e67ac46c clan: improve machine completions
In recent nix versions the `nix flake show` command busts the eval
cache, which made the function that used to be faster, slower.

On benchmarks the completion was around 180-200ms.
2024-06-05 13:32:23 +02:00
5024973896 Merge pull request 'Hsjobeki Main' (#1570) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-05 10:14:53 +00:00
7dce6ad6c4
clan-app: switch default view to webui 2024-06-05 12:10:26 +02:00
779229a907 Merge pull request 'clan-app: rename clan-vm-manager' (#1569) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-05 09:41:05 +00:00
af23ed027a Merge pull request 'clan: fix backup description' (#1567) from kenji/clan-core:clan/fix/backup-description into main
Reviewed-on: clan/clan-core#1567
2024-06-05 09:40:01 +00:00
06412865bb
clan-app: rename clan-vm-manager 2024-06-05 11:36:02 +02:00
fab311b53a clan: fix backup description 2024-06-05 11:35:04 +02:00
bc602dbf3c Merge pull request 'clan-app: Rename clan-vm-manager to clan-app.' (#1566) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-05 09:31:22 +00:00
0fb207bb59
clan-app: rename clan-vm-manager 2024-06-05 11:24:59 +02:00
c751bc78d8 Merge pull request 'clan: add dynamic completions to clan backups' (#1565) from kenji/clan-core:clan/backups/dynamic-completions into main
Reviewed-on: clan/clan-core#1565
2024-06-05 09:23:02 +00:00
c9038ad0b3 clan: add dynamic completions to clan backups providers 2024-06-05 09:23:02 +00:00
b4699cd8a3 clan: add dynamic completion function for backup providers 2024-06-05 09:23:02 +00:00
d0a87d8e3c Merge pull request 'web-ui: init type API checks' (#1564) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-05 09:11:44 +00:00
78dbabf901
web-ui: init type API checks 2024-06-05 11:07:55 +02:00
ad771ae6a0 Merge pull request 'web-ui: remove type test method' (#1563) from hsjobeki/clan-core:hsjobeki-main into main 2024-06-05 07:58:08 +00:00
92bc2962b8
web-ui: remove type test method 2024-06-05 09:54:17 +02:00
836754d7ad Merge pull request 'hsjobeki-main' (#1562) from hsjobeki-main into main 2024-06-05 07:52:38 +00:00
6576290160
clan-api: wrap all api responses with error/success envelop type 2024-06-05 09:46:48 +02:00
db88e63148
clan-cli: create flake refactor to create clan 2024-06-05 09:45:47 +02:00
f2d2102127
clan-cli: refactor CmdOut to serializable dataclass 2024-06-05 09:44:44 +02:00
b9bf453731
clan-api: add support for generic types & annotated types 2024-06-05 09:43:45 +02:00
fb98247a8d Merge pull request 'demo.sh: fix tags' (#1561) from DavHau/clan-core:DavHau-dave into main 2024-06-04 22:27:39 +00:00
4bd927cbcf demo.sh: fix tags 2024-06-04 15:23:39 -07:00
3725d5703e Merge pull request 'documentation(backups): make exampe more robust' (#1560) from kenji/clan-core:improve/backup-docs into main
Reviewed-on: clan/clan-core#1560
2024-06-04 15:17:29 +00:00
bf0cc19c8f documentation(backups): make exampe more robust 2024-06-04 17:09:26 +02:00
8af137545f Merge pull request 'borgbackup: fixes error when specifying multiple backup directories' (#1559) from kenji/clan-core:improve/backup-docs into main
Reviewed-on: clan/clan-core#1559
2024-06-04 14:54:39 +00:00
3d71ebcc5f borgbackup: try to fix 2024-06-04 16:27:53 +02:00
c6fcb833b3 Merge pull request 'clan/improve/dynamic-completions-config' (#1558) from kenji/clan-core:clan/improve/dynamic-completions-config into main
Reviewed-on: clan/clan-core#1558
2024-06-04 13:57:18 +00:00
c926f23c09 clan: add dynamic completions to clan vms inspect 2024-06-04 15:50:50 +02:00
21ac1f7204 clan: add dynamic completions to clan vms run 2024-06-04 15:48:12 +02:00
05ff7bd261 clan: add dynamic completions to clan config 2024-06-04 15:44:39 +02:00
b2109351ff Merge pull request 'clan/improve/dynamic-completions' (#1557) from kenji/clan-core:clan/improve/dynamic-completions into main
Reviewed-on: clan/clan-core#1557
2024-06-04 13:28:09 +00:00
0bd13727de clan: add dynamic-completions to clan secrets set 2024-06-04 15:21:00 +02:00
e1d6d04b48 clan: add dynamic completions to clan secrets machines 2024-06-04 15:02:35 +02:00
9dbbb6f2f6 clan: add dynamic completions for clan secrets import-sops 2024-06-04 13:40:24 +02:00
836170e5b6 Merge pull request 'clan: add dynamic completions to clan secrets {users,groups} and add completion functions' (#1556) from kenji/clan-core:add/completion/to-groups into main
Reviewed-on: clan/clan-core#1556
2024-06-04 11:35:42 +00:00
d4fabff7f4 clan: add dynamic completions for secret groups 2024-06-04 13:30:38 +02:00
b21bef0b98 clan: add dynamic completions for clan secrets users 2024-06-04 13:30:38 +02:00
533ed97fc1 clan: add dynamic completion for clan secret groups 2024-06-04 13:30:38 +02:00
e7e5a1ded8 clan: add completion function for clan users 2024-06-04 13:30:11 +02:00
4e95030e55 clan: clan secrets groups add machine completions 2024-06-04 13:30:11 +02:00
b331a8c730 Merge pull request 'clan: fix help message' (#1553) from kenji/clan-core:add/completion/groups into main
Reviewed-on: clan/clan-core#1553
2024-06-04 10:28:34 +00:00
2923051a12 clan: fix help message 2024-06-04 10:28:34 +00:00
fe96137c56 Merge pull request 'clan: add more machine completion functions to secrets' (#1552) from kenji/clan-core:add/completion/secret-subcommands into main
Reviewed-on: clan/clan-core#1552
2024-06-04 09:30:02 +00:00
addc4de735 clan: add more machine completion functions to secrets 2024-06-04 11:07:24 +02:00
2460ba9b67 Merge pull request 'demo.sh: fix tag' (#1550) from DavHau/clan-core:DavHau-dave into main 2024-06-04 05:00:07 +00:00
62be27ec62 demo.sh: fix tag 2024-06-03 21:55:09 -07:00
8515d41fe3 Merge pull request 'distro-packages: add test for deb installation' (#1549) from DavHau/clan-core:DavHau-dave into main 2024-06-04 04:17:21 +00:00
d4d69d6990 distro-packages: add test for deb installation 2024-06-04 06:09:58 +02:00
0027c46313 Merge pull request 'zerotier-static-peers: use correct exclusion source' (#1548) from kenji/clan-core:modules/fix/static into main
Reviewed-on: clan/clan-core#1548
2024-06-03 21:24:29 +00:00
ca2001040b zerotier-static-peers: use correct exclusion source 2024-06-03 22:53:44 +02:00
d6725100ac Merge pull request 'zerotier-static-peers: add guard condition' (#1547) from kenji/clan-core:modules/add/zerotier-guard into main
Reviewed-on: clan/clan-core#1547
2024-06-03 20:47:03 +00:00
503ce29c84 zerotier-static-peers: add guard condition 2024-06-03 22:42:04 +02:00
87444cd2b8 Merge pull request 'clan: add dyncamic completions for secrets' (#1546) from kenji/clan-core:kenji-clan/secrets-dynamic/add-completion into main
Reviewed-on: clan/clan-core#1546
2024-06-03 19:55:12 +00:00
31eca9e8bc clan: add dyncamic completions for secrets 2024-06-03 21:47:14 +02:00
822afe08b5 Merge pull request 'clan: add dynamic machine completions to clan secrets subcommands' (#1545) from clan/secrets/add-completions into main
Reviewed-on: clan/clan-core#1545
2024-06-03 15:42:37 +00:00
cfb78b0edb clan: add dynamic machine completions to clan secrets subcommands 2024-06-03 17:32:33 +02:00
65fd7d3efe Merge pull request 'clan: add dynamic completion to clan machines show' (#1544) from kenji-clan/machine-show/add-commpletion into main
Reviewed-on: clan/clan-core#1544
2024-06-03 15:15:45 +00:00
e8241fb7c9 clan: add dynamic completion to clan machines show 2024-06-03 17:06:03 +02:00
259d51bdc8 Merge pull request 'clan.static-hosts: excludeHosts should be empty if topLevelDomain is defined.' (#1538) from mrvandalo/clan-core:feature/static-hosts-exclude-nothing-when-tld-is-given into main
Reviewed-on: clan/clan-core#1538
Reviewed-by: kenji <aks.kenji@protonmail.com>
2024-06-03 10:44:41 +00:00
f6fb52afbf clan.static-hosts: excludeHosts should be empty if topLevelDomain is defined. 2024-06-03 10:44:41 +00:00
8089b87bbb Merge pull request 'Revert "clan-cli: cmd.py uses pseudo terminal now. Remove tty.py. Refactor password_store.py to use cmd.py."' (#1543) from lassulus/clan-core:lassulus-HEAD into main 2024-06-03 10:30:50 +00:00
578162425d Revert "clan-cli: cmd.py uses pseudo terminal now. Remove tty.py. Refactor password_store.py to use cmd.py."
This reverts commit ba86b49952.
2024-06-03 12:25:20 +02:00
dbad63f155 Merge pull request 'clan_cli secrets_upload: fix permissions' (#1542) from lassulus/clan-core:lassulus-HEAD into main 2024-06-03 08:58:49 +00:00
da8a733899 clan_cli secrets_upload: fix permissions 2024-06-03 10:52:18 +02:00
8f58f1998d Merge pull request 'Automatic flake update - 2024-06-03T00:00+00:00' (#1540) from flake-update-2024-06-03 into main 2024-06-03 00:05:17 +00:00
Clan Merge Bot
c43fe5187f update flake lock - 2024-06-03T00:00+00:00
Flake lock file updates:

• Updated input 'disko':
    'github:nix-community/disko/10986091e47fb1180620b78438512b294b7e8f67' (2024-05-27)
  → 'github:nix-community/disko/0274af4c92531ebfba4a5bd493251a143bc51f3c' (2024-05-31)
• Updated input 'flake-parts':
    'github:hercules-ci/flake-parts/8dc45382d5206bd292f9c2768b8058a8fd8311d9' (2024-05-16)
  → 'github:hercules-ci/flake-parts/2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8' (2024-06-01)
• Updated input 'nixos-images':
    'github:nix-community/nixos-images/2478833ef8cc6de3d9e331f53b6f3682e425f207' (2024-05-27)
  → 'github:nix-community/nixos-images/47bfb55316e105390dd761e0b6e8e0be09462b67' (2024-05-30)
• Updated input 'nixos-images/nixos-2311':
    'github:NixOS/nixpkgs/0c007b36981bdbd69ccf0c7df30a174e63660667' (2024-05-26)
  → 'github:NixOS/nixpkgs/64e468fd2652105710d86cd2ae3e65a5a6d58dec' (2024-05-29)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/4ae13643e7f2cd4bc6555fce074865d9d14e7c24' (2024-05-28)
  → 'github:NixOS/nixpkgs/6634a0509e9e81e980b129435fbbec518ab246d0' (2024-06-02)
• Updated input 'sops-nix':
    'github:Mic92/sops-nix/962797a8d7f15ed7033031731d0bb77244839960' (2024-05-26)
  → 'github:Mic92/sops-nix/ab2a43b0d21d1d37d4d5726a892f714eaeb4b075' (2024-06-02)
• Updated input 'treefmt-nix':
    'github:numtide/treefmt-nix/2fba33a182602b9d49f0b2440513e5ee091d838b' (2024-05-17)
  → 'github:numtide/treefmt-nix/3eb96ca1ae9edf792a8e0963cc92fddfa5a87706' (2024-06-01)
2024-06-03 00:00:22 +00:00
0993fe45f6 Merge pull request 'clan-cli: cmd.py uses pseudo terminal now. Remove tty.py. Refactor password_store.py to use cmd.py' (#1536) from Qubasa/clan-core:Qubasa-main into main 2024-06-02 14:56:41 +00:00
ba86b49952 clan-cli: cmd.py uses pseudo terminal now. Remove tty.py. Refactor password_store.py to use cmd.py. 2024-06-02 16:52:31 +02:00
0b34c340fc Merge pull request 'clan-cli: Refactor machines/update.py to cmd.run' (#1535) from Qubasa/clan-core:Qubasa-main into main 2024-06-02 08:04:18 +00:00
d513f66170 clan-cli: Refactor machines/update.py to cmd.run 2024-06-02 10:00:23 +02:00
320fb776ea Merge pull request 'clan-cli: Add input arg to cmd.run. Replace subprocess.run in password_store' (#1533) from Qubasa/clan-core:Qubasa-main into main 2024-06-02 07:57:18 +00:00
1a39957dbb clan-cli: Refactor subprocess.run to cmd.run. tea-create-pr: Fix missing fail-on-change for treefmt 2024-06-02 09:53:24 +02:00
b5abe4025a Merge pull request 'docs: Add meta tags for link preview and fix js loading issue.' (#1531) from Qubasa/clan-core:Qubasa-main into main 2024-06-01 20:23:30 +00:00
55f4dcc460 docs: Add meta tags for link preview and fix js loading issue. 2024-06-01 22:19:37 +02:00
ef4a83f739 Merge pull request 'clan-core: add clan meta for ui usage' (#1529) from hsjobeki-main into main
Reviewed-on: clan/clan-core#1529
2024-05-31 16:26:46 +00:00
133f2b705f clan-core: add template to impure tests 2024-05-31 16:26:46 +00:00
83fe58e003 clan-core: add clan meta for ui usage 2024-05-31 16:26:46 +00:00
481f926b17 Merge pull request 'split list machines into show machine command' (#1521) from machines-show into main 2024-05-31 15:00:03 +00:00
788eae432a split list machines into show machine command 2024-05-31 16:56:09 +02:00
b7936c4ed2 Merge pull request 'upgrade nix in development to latest' (#1528) from nix-latest into main 2024-05-31 14:41:21 +00:00
750c8df003 upgrade nix in development to latest
Better error messages!!
2024-05-31 16:37:07 +02:00
276c39aba4 Merge pull request 'Contributing.md: Fix incorrect formating.' (#1527) from Qubasa/clan-core:Qubasa-main into main 2024-05-31 14:02:18 +00:00
90e25eeb76 Contributing.md: Fix incorrect formating. 2024-05-31 15:58:29 +02:00
56676701ae Merge pull request 'clan: add dynamic completions for fact generation services' (#1525) from a-kenji-clan/complete-services into main 2024-05-31 13:25:15 +00:00
bcccf301f0 clan: add dynamic completions for fact generation services 2024-05-31 15:21:07 +02:00
e343ba5635 Merge pull request 'Contributing.md: Explain merge-after-ci for externals.' (#1524) from Qubasa/clan-core:Qubasa-main into main 2024-05-31 12:02:02 +00:00
66fe5ec4fd Contributing.md: Explain merge-after-ci for externals. 2024-05-31 13:58:13 +02:00
f2a884ec30 Merge pull request 'clan: add completion timeout as static' (#1523) from a-kenji-clan/completions into main 2024-05-31 11:10:52 +00:00
d31aa7cf88 clan: add completion timeout as static 2024-05-31 13:06:46 +02:00
9f19a8e605 Merge pull request 'clan: add dynamic completions' (#1522) from a-kenji-clan/cli/init-dynamic-completions into main 2024-05-31 11:00:50 +00:00
23ef39a2d9 clan: add dynamic completions
Add dynamic completion scaffolding to the clan `cli`.
Also add a dynamic completion mechanism for machines for commands that
have machines as their sole argument.

More intricate dynamic completions will be implemented in follow up
PR's.
2024-05-31 12:55:41 +02:00
dda82c49b0 Merge pull request 'tea-create-pr: Add automatic rebase and autostash' (#1518) from Qubasa/clan-core:Qubasa-main into main 2024-05-30 22:03:38 +00:00
c91c90a2a6 tea-create-pr: Add automatic rebase and autostash 2024-05-30 23:59:27 +02:00
5794cdf8fa Merge pull request 'docs: Fix installer wrong indentation' (#1516) from Qubasa/clan-core:Qubasa-main into main 2024-05-30 21:44:41 +00:00
01a4748d6b tea-create-pr: Fix non working assignees label 2024-05-30 23:37:53 +02:00
a8762522c8 tea-create-pr: Better username detection 2024-05-30 23:29:59 +02:00
adef52a938 docs: Fix installer wrong indentation 2024-05-30 22:41:30 +02:00
c8fbf87fc8 Merge pull request 'Change clan favicon to one without text' (#1506) from Qubasa/clan-core:Qubasa-main into main 2024-05-30 20:30:02 +00:00
f63e3618c2 tea-create-pr: Require fork and upstream branch 2024-05-30 22:25:25 +02:00
b18d7bfeac Change clan favicon to one without text 2024-05-30 21:59:48 +02:00
076b98ff00 Merge pull request 'Webview: css font and icon import transformation' (#1501) from hsjobeki-main into main 2024-05-30 16:28:14 +00:00
6999685bba
Webview: css font and icon import transformation 2024-05-30 18:23:49 +02:00
f1c02bbd46 Merge pull request 'Add top level domain option for zerotier machines.' (#1499) from mrvandalo/clan-core:feature/static-host-tld into main
Reviewed-on: clan/clan-core#1499
2024-05-29 18:40:15 +00:00
2caa837537 Add top level domain option for zerotier machines. 2024-05-29 18:40:15 +00:00
e1ddbf226a Merge pull request 'install.sh: improvements' (#1500) from DavHau-install-dev into main 2024-05-29 18:03:50 +00:00
7cb8c114c2 install.sh: improvements
- use either curl or wget
- add to PATH /nix/var/nix/profiles/default/bin
2024-05-29 18:51:34 +02:00
5945630870 Merge pull request 'gui-installer: depend on git + ignore flake config' (#1498) from DavHau-dave into main 2024-05-29 15:48:54 +00:00
ccadac4bb3 gui-installer: depend on git + ignore flake config 2024-05-29 17:42:44 +02:00
15b77f6b8a Merge pull request 'Webview: bootstrap layout' (#1497) from hsjobeki-main into main 2024-05-29 14:45:45 +00:00
9bf76037aa
Webview: bootstrap layout 2024-05-29 16:40:54 +02:00
d0d973b797 Merge pull request 'make config command read-only' (#1319) from config into main
Reviewed-on: clan/clan-core#1319
2024-05-29 11:25:27 +00:00
c1e2bc9ea9 make config command read-only 2024-05-29 13:17:55 +02:00
0eef21e2ef Merge pull request 'Update flakes' (#1492) from pass-nix-options into main 2024-05-29 10:58:19 +00:00
461aa579c2 fmt more stuff 2024-05-29 12:51:43 +02:00
da442c47f6 drop non-compiling wayland-proxy-virtwl 2024-05-29 12:51:18 +02:00
491d37ea67 update flake 2024-05-29 12:51:04 +02:00
7e087d18ee Merge pull request 'fix offline build of flash command' (#1491) from pass-nix-options into main 2024-05-29 10:49:15 +00:00
5c75a6490b fix offline build of flash command 2024-05-29 12:45:50 +02:00
750b6aec59 flash: make configuration more explicit
Injecting nixos configuration and potentially overriding settings a user
made and can cause surprises.
In most cases, users want to just make these option part of their NixOS
configuration and by having the rest in the command line
we make it more explicit what other configuration is being applied.
2024-05-29 12:45:50 +02:00
d138e29a53 Merge pull request 'Consistently pass nix options to underlying tools' (#1488) from pass-nix-options into main 2024-05-29 08:25:53 +00:00
a7febba9c8 Merge pull request 'clan: clarify default backend' (#1490) from a-kenji-cli/facts-clarify into main 2024-05-29 08:23:06 +00:00
f0f97baa65 drop global argparse flags
They get shadowed by subargparser options.
2024-05-29 10:21:35 +02:00
c2dc94507e clan: clarify default backend 2024-05-29 10:17:22 +02:00
7c0aaab463 Merge pull request 'clan: add epilog to facts subcommands' (#1489) from a-kenji-cli/expand-examples into main 2024-05-29 08:15:46 +00:00
5dcac604d1 backup cli: make sure we have a flake 2024-05-29 10:14:14 +02:00
96746b7c98 flash: add write-efi-boot-entries flag 2024-05-29 10:14:14 +02:00
2ae50b7398 allow to override nix options in update/install/flash commands 2024-05-29 10:14:14 +02:00
3c905c5072 clan: add epilog to facts subcommands 2024-05-29 10:10:23 +02:00
5b926f57cc cli: also register common flags in subcommands
When a user runs --help on a subcommand they don't see some options such
as --options or --flake. To fix this we now register all common flags
also in subcommands.
2024-05-29 09:29:49 +02:00
b9788a5dba Merge pull request 'clan/docs.py: remove epilog from the reference overview' (#1487) from a-kenji-cli/docs/reference-overview into main 2024-05-28 18:05:07 +00:00
7078f09872 clan/docs.py: remove epilog from the reference overview 2024-05-28 20:01:48 +02:00
1aa7808c02 Merge pull request 'Update Contributing guide to external developers' (#1484) from Qubasa/clan-core:main into main
Reviewed-on: clan/clan-core#1484
2024-05-28 16:12:11 +00:00
ba8a51101d Update Contributing guide to external developers 2024-05-28 18:06:31 +02:00
de69c970aa Merge pull request 'packaging: package clan gui for many distros' (#1485) from DavHau-dave into main 2024-05-28 15:54:08 +00:00
fe5fa6a85d packaging: package clan gui for many distros 2024-05-28 17:50:32 +02:00
de74febf64 Merge pull request 'packaging: package clan gui for many distros' (#1483) from DavHau-dave into main 2024-05-28 15:37:18 +00:00
3b6483e819 packaging: package clan gui for many distros 2024-05-28 17:33:55 +02:00
dcd6ad0983 Merge pull request 'Docs: fix relative links to git.clan.lol' (#1482) from hsjobeki-main into main 2024-05-28 15:18:45 +00:00
567d979243
Docs: fix relative links to git.clan.lol 2024-05-28 17:14:16 +02:00
c81a8681b0 Merge pull request 'clan/docs.py: add epilog to reference docs' (#1481) from a-kenji-docs/epilog into main 2024-05-28 15:13:57 +00:00
31cde90819 clan/docs.py: add epilog to reference docs
Fixes #1469
2024-05-28 17:08:46 +02:00
a77bf5bf21 Merge pull request 'Docs: use offline fonts' (#1480) from hsjobeki-main into main 2024-05-28 15:05:22 +00:00
4befa80eb8
Docs: use offline fonts 2024-05-28 16:58:59 +02:00
52584662a8 Merge pull request 'Fix typos' (#1477) from a-kenji-fix/typos into main 2024-05-28 13:02:19 +00:00
de147f63e9 Fix typos 2024-05-28 14:58:38 +02:00
96c33dec7a Merge pull request 'consistent rename cLAN -> Clan' (#1475) from rename into main 2024-05-28 11:38:57 +00:00
3c0b5f0867 drop deprecated mdDoc 2024-05-28 13:35:11 +02:00
c252f11c1f Merge pull request 'docs/secrets: improve chapter assigning access' (#1474) from DavHau-dave into main 2024-05-28 11:11:46 +00:00
f1f040397d docs/secrets: improve chapter assigning access
Since we already walk the user through creating a secret in an earlier step, it makes more sense explain first how to add machines/users to an existing secret instead of creating  a new one
2024-05-28 13:08:19 +02:00
418e9937cb Merge pull request 'clan: add descriptions for reference documentation' (#1473) from a-kenji-cli/doc into main 2024-05-28 09:40:50 +00:00
c34664429c clan: add descriptions for reference documentation 2024-05-28 11:37:32 +02:00
6fe5928297 Merge pull request 'clan: add run_no_stdout function suppressing stdout' (#1472) from a-kenji-run_no_stdout into main 2024-05-28 09:17:14 +00:00
eee99730d1 clan: add run_no_stdout function suppressing stdout
Add the `run_no_stdout` function suppressing stdout by default.This
keeps the noise down on most commands, while still
stayingdebuggable.Stdout will be active when the `--debug` flag is
passed to the cli.

Fixes #1443
2024-05-28 11:13:55 +02:00
9394760e3b Merge pull request 'editor: improve nixpkgs option completions' (#1470) from a-kenji-improve/editor into main 2024-05-28 07:38:09 +00:00
a0b0e1a0ac editor: improve nixpkgs option completions 2024-05-28 09:34:57 +02:00
dbaa26ccaa Merge pull request 'clan: machines --help add examples to help output' (#1468) from a-kenji-clan/cli/machines-examples into main 2024-05-27 19:04:30 +00:00
d1591d4485 clan: machines --help add examples to help output 2024-05-27 21:01:05 +02:00
c68a8306ba Merge pull request 'clan: duplicate description field for generation of the reference documentation' (#1467) from a-kenji-clan/cli/add-description into main 2024-05-27 18:32:54 +00:00
ec9f605004 clan: duplicate description field for generation of the reference documentation 2024-05-27 20:29:34 +02:00
e60efea1f7 Merge pull request 'clan: ssh --help add examples' (#1466) from a-kenji-clan/help/ssh into main 2024-05-27 18:18:08 +00:00
efacb7f184 clan: ssh --help add examples
Add examples to the output of `clan ssh --help`.
2024-05-27 20:14:37 +02:00
67275aac63 Merge pull request 'clan: rename cLan to clan' (#1465) from a-kenji-rename-clan into main 2024-05-27 17:56:32 +00:00
a704a05b15 clan: rename cLan to clan 2024-05-27 19:52:51 +02:00
01aafc520d Merge pull request 'consistent rename cLAN -> Clan' (#1464) from rename into main
Reviewed-on: clan/clan-core#1464
2024-05-27 13:58:32 +00:00
c0a54f539a consistent rename cLAN -> Clan 2024-05-27 13:58:32 +00:00
e2d7e6e86c consistent rename cLAN -> Clan 2024-05-27 15:54:17 +02:00
1df4e361f7 Merge pull request 'clan: add examples and description to most help' (#1463) from a-kenji-clan/examples into main 2024-05-27 12:37:22 +00:00
e8bd5ad24b clan: add examples and description to most help
Add examples and description to most toplevel help outputs.
2024-05-27 14:33:58 +02:00
775f993ecc Merge pull request 'clan-cli: Fix nix develop not working in template because of symlink' (#1462) from Qubasa-main into main 2024-05-27 12:05:17 +00:00
0e1478edcd clan-cli: Fix nix develop not working in template because of symlink 2024-05-27 14:00:31 +02:00
bfc1203a8a Merge pull request 'init: vscode .#editor' (#1461) from Qubasa-init/editors into main 2024-05-27 12:00:26 +00:00
2bd8b144b9 init: vscode .#editor 2024-05-27 13:52:54 +02:00
b52b2221b0 Merge pull request 'drop offline in nix shell' (#1459) from fix-mass-rebuilds into main 2024-05-27 11:43:32 +00:00
64adf17368 drop offline in nix shell
Otherwise we become gentoo!
2024-05-27 13:40:11 +02:00
509d8c1dae Merge pull request 'make git-hooks opt-in' (#1453) from git-hooks into main 2024-05-27 10:34:07 +00:00
295de17640 Merge pull request 'docs: secrets: list the main steps of the guide' (#1456) from DavHau-dave into main 2024-05-27 10:05:55 +00:00
b158c2706f docs: secrets: list the main steps of the guide
... so the user has a routh idea about the mein steps
2024-05-27 12:02:29 +02:00
750979c988 Merge pull request 'A Kenji Clan/Cli/Fix Naming' (#1455) from a-kenji-clan/cli/fix-naming into main 2024-05-27 09:54:36 +00:00
6d7849a03c clan: fix description of cli tool 2024-05-27 11:51:25 +02:00
f46fd3ace6 make git-hooks opt-in
pre-commit hook break git commits and are disruptive.
Therefore people that want to enable this feature, should enable it locally instead.
I.e. treefmt will also check untracked files that are not meant for the current commit.
2024-05-27 11:08:17 +02:00
6e9f1515d3 Merge pull request 'clan: facts generate allow regeneration of facts' (#1447) from a-kenji-clan/feat/facts-regenerate-1403 into main 2024-05-26 21:00:38 +00:00
81e0700826 clan: facts generate allow regeneration of facts
Add `--regenerate` flag to `clan facts generate` which allows forcing
the generation of facts, regardless of their current existence.

Examples:
```
clan facts generate [MACHINE] --regenerate
```
or
```
clan facts generate [MACHINE] --service [SERVICE] --regenerate
```
2024-05-26 22:55:48 +02:00
4daf036a3c Merge pull request 'clan: facts generate specific service' (#1446) from a-kenji-feat/clan/facts-generate-service-1395 into main 2024-05-26 19:57:17 +00:00
4faab0a20f clan: facts generate specific service
Add `--service` flag to the `clan` cli which allows specifying a certain
service to be generated.

Example:

```
clan facts generate [MACHINE] --service [SERVICE]
```

Fixes #1395
2024-05-26 21:52:56 +02:00
76622557c4 Merge pull request 'Webview: improve linting & typechecks' (#1445) from hsjobeki-main into main 2024-05-26 16:41:11 +00:00
4c4c94c508
Webview: improve linting & typechecks 2024-05-26 18:37:29 +02:00
b0d5ef01ca Merge pull request 'Api: init response envelop' (#1444) from hsjobeki-feat/api-improvements into main 2024-05-26 16:08:02 +00:00
ab656d5655
API: handle functions with multiple arguments 2024-05-26 18:04:49 +02:00
ed171f0264
Api: init response envelop 2024-05-26 15:57:10 +02:00
270f9d54cb Merge pull request 'clan: fix clan facts list [MACHINE]' (#1442) from a-kenji-fix/clan-facts-list into main 2024-05-26 12:29:37 +00:00
73f486fe13 clan: fix clan facts list [MACHINE]
Fix `clan facts list [MACHINE]`.
The get command returned a dictionary of bytestrings.
We now convert them to strings.
2024-05-26 14:26:08 +02:00
7da6826344 Merge pull request 'api: improve message serialisation' (#1440) from hsjobeki-feat/api-improvements into main 2024-05-26 12:20:11 +00:00
f54c518fd7
api: fix breaking tests 2024-05-26 14:17:17 +02:00
522fd1bcaa
api: convert name casing 2024-05-26 13:54:21 +02:00
be5c3accfe
webview: fix typo 2024-05-26 13:41:07 +02:00
3998efac78
fix: tests 2024-05-26 13:41:05 +02:00
691ae9fb15
api: improve message serialisation 2024-05-26 13:40:47 +02:00
fc8a64ef49 Merge pull request 'Add draft: Git Based Machine Deployment with Clan-Core' (#1439) from Qubasa-main into main 2024-05-25 16:37:39 +00:00
c0f3810e01 Add draft: Git Based Machine Deployment with Clan-Core 2024-05-25 18:34:19 +02:00
39d8cf91cf Merge pull request 'blog: fix typos' (#1436) from a-kenji-fix/typos-1 into main 2024-05-25 10:34:05 +00:00
233b973120 blog: fix typos 2024-05-25 11:57:28 +02:00
f3f2f6df69 Merge pull request 'blog: fix typo on jsonschema post' (#1435) from DavHau-dave into main 2024-05-25 08:41:03 +00:00
ec824becc8 blog: fix typo on jsonschema post 2024-05-25 10:37:56 +02:00
7fbb50fcc8 Merge pull request 'blog: add link for discourse comments' (#1434) from DavHau-dave into main 2024-05-25 07:47:56 +00:00
33695f7470 blog: add link for discourse comments 2024-05-25 09:44:49 +02:00
001ed3283a Merge pull request 'blog: custom slug for jsonschema converter post' (#1433) from DavHau-dave into main 2024-05-25 07:37:54 +00:00
9ae7d4a24b blog: custom slug for jsonschema converter post 2024-05-25 09:34:50 +02:00
e39911d99c Merge pull request 'blog: improve description of jsonschema post' (#1432) from DavHau-dave into main 2024-05-25 07:12:35 +00:00
9c3da78792 blog: improve description of jsonschema post 2024-05-25 09:09:20 +02:00
69ddda24c9 Merge pull request 'blog: add jsonschema blog post' (#1431) from DavHau-dave into main 2024-05-25 07:01:10 +00:00
c6f078fafc blog: add jsonschema blog post 2024-05-25 08:57:57 +02:00
4e3ed011da Merge pull request 'blog: Remove asciinema player' (#1430) from Qubasa-main into main 2024-05-24 15:13:58 +00:00
a71191486c blog: Fix remote url 2024-05-24 17:10:47 +02:00
d3e6276d04 Merge pull request 'blog: Remove asciinema player' (#1429) from Qubasa-main into main 2024-05-24 14:58:52 +00:00
a1e2d1017e blog: Remove asciinema player 2024-05-24 16:57:26 +02:00
114b0b02d0 blog: Remove asciinema player 2024-05-24 16:54:51 +02:00
de3e133981 Merge pull request 'blog: Remove pictures.' (#1428) from Qubasa-main into main 2024-05-24 13:53:28 +00:00
083e30f468 blog: Remove pictures. 2024-05-24 15:50:14 +02:00
d7ef88c67c Merge pull request 'add-pre-commit' (#1413) from fricklerhandwerk/clan-core:add-pre-commit into main
Reviewed-on: clan/clan-core#1413
2024-05-24 12:39:56 +00:00
055b17c01b add pre-commit check
make sure things are sane before they hit CI, re-purposing the existing
treefmt configuration.

this adds a custom installer for pre-commit hooks, which is inspired by
pre-commit.nix[0], but is much more minimal than the underlying
pre-commit[1] and builds on a historic idea[2] from this repository.

[0]: https://github.com/cachix/git-hooks.nix
[1]: https://github.com/pre-commit/pre-commit
[2]: 930923512c
2024-05-24 12:39:56 +00:00
4b07bf363b Merge pull request 'documentation: add keys' (#1426) from a-kenji-add-keys into main 2024-05-24 11:49:09 +00:00
97928801f9 documentation: add keys 2024-05-24 13:46:05 +02:00
fdacfb8ecf Merge pull request 'documenation: use monospace font for code blocks' (#1425) from a-kenji-fix-monospace into main 2024-05-24 11:11:02 +00:00
508a26d68d documenation: use monospace font for code blocks
Use monospace font for code blocks.

Fixes: #1337
2024-05-24 13:08:00 +02:00
8055c21984 Merge pull request 'clan machines list: reduce noise' (#1418) from a-kenji-fix/output-noisy/1115 into main 2024-05-24 10:58:13 +00:00
9bb6ed313f clan machines list: reduce noise
Don't log nix error output by default on `clan machines list`.
Log it, if `--debug` is passed.

Fixes #1115
2024-05-24 12:55:14 +02:00
8c36df77cc Merge pull request 'documentation: improve legibility of command output' (#1423) from a-kenji-fix/lsblk into main 2024-05-24 10:40:34 +00:00
2284b060be documentation: improve legibility of command output
Improve legibility of command output.
2024-05-24 12:37:27 +02:00
491b5d28f2 Merge pull request 'documenation: fix flake-parts what's next section' (#1422) from a-kenji-fix/docs/flake-parts into main 2024-05-24 10:14:55 +00:00
bf212ce9c4 documenation: fix flake-parts what's next section 2024-05-24 12:11:42 +02:00
35be09feaa Merge pull request 'impure-checks: unset CLAN_DIR' (#1420) from a-kenji-fix/env into main 2024-05-24 10:06:10 +00:00
4ee90b4b9f impure-checks: unset CLAN_DIR
Unset `CLAN_DIR` in the impure checks, so that it won't reference the
users configuration.

Fixes #1419
2024-05-24 12:03:11 +02:00
cab69935ef Merge pull request 'lib.jsonschema: parse some more types' (#1417) from DavHau-dave into main 2024-05-23 14:17:56 +00:00
54fcfda43e lib.jsonschema: parse some more types 2024-05-23 16:12:49 +02:00
d137342243 Merge pull request 'modules: init trusted-nix-cache module' (#1414) from a-kenji-add/cache-module into main 2024-05-23 07:32:36 +00:00
3eba6e85cc modules: init trusted-nix-cache module 2024-05-23 09:29:31 +02:00
d395e2abf3 Merge pull request 'flake.nix: change disko back to nix-community' (#1409) from change_disko_input into main 2024-05-22 19:17:48 +00:00
b971156df1 flake.nix: change disko back to nix-community 2024-05-22 21:14:30 +02:00
c885a3fec8 Merge pull request 'Revert "Merge pull request 'add pre-commit-check' (#1369) from fricklerhandwerk/clan-core:add-pre-commit into main"' (#1408) from Qubasa-revert_hooks into main 2024-05-22 12:36:23 +00:00
ae7794dddd Revert "Merge pull request 'add pre-commit-check' (#1369) from fricklerhandwerk/clan-core:add-pre-commit into main"
This reverts commit acaa69e2bf, reversing
changes made to a78f5b2bec.
2024-05-22 14:31:53 +02:00
acaa69e2bf Merge pull request 'add pre-commit-check' (#1369) from fricklerhandwerk/clan-core:add-pre-commit into main
Reviewed-on: clan/clan-core#1369
2024-05-22 11:49:57 +00:00
e37f7e2760 use a custom installer for pre-commit hooks 2024-05-22 11:49:57 +00:00
245b615209 add pre-commit check
make sure things are sane before they hit CI.
this re-purposes the existing treefmt configuration.
2024-05-22 11:49:57 +00:00
290 changed files with 10363 additions and 3874 deletions

View File

@ -1,4 +1,4 @@
# Contributing to cLAN
# Contributing to Clan
## Live-reloading documentation

View File

@ -1,6 +1,6 @@
# Clan Core Repository
Welcome to the Clan Core Repository, the heart of the [clan.lol](https://clan.lol/) project! This monorepo is the foundation of Clan, a revolutionary open-source project aimed at restoring fun, freedom, and functionality to computing. Here, you'll find all the essential packages, NixOS modules, CLI tools, and tests needed to contribute to and work with the cLAN project. Clan leverages the Nix system to ensure reliability, security, and seamless management of digital environments, putting the power back into the hands of users.
Welcome to the Clan Core Repository, the heart of the [clan.lol](https://clan.lol/) project! This monorepo is the foundation of Clan, a revolutionary open-source project aimed at restoring fun, freedom, and functionality to computing. Here, you'll find all the essential packages, NixOS modules, CLI tools, and tests needed to contribute to and work with the Clan project. Clan leverages the Nix system to ensure reliability, security, and seamless management of digital environments, putting the power back into the hands of users.
## Why Clan?
@ -40,6 +40,6 @@ Clan is more than a tool; it's a movement towards a better digital future. By co
Connect with us and the Clan community for support and discussion:
- [Matrix channel](https://matrix.to/#/#clan:lassul.us) for live discussions.
- [Matrix channel](https://matrix.to/#/#clan:clan.lol) for live discussions.
- IRC bridges (coming soon) for real-time chat support.

View File

@ -68,17 +68,9 @@
};
};
};
clanCore.facts.secretStore = "vm";
clan.core.facts.secretStore = "vm";
environment.systemPackages = [
self.packages.${pkgs.system}.clan-cli
(pkgs.writeShellScriptBin "pre-restore-command" ''
touch /var/test-service/pre-restore-command
'')
(pkgs.writeShellScriptBin "post-restore-command" ''
touch /var/test-service/post-restore-command
'')
];
environment.systemPackages = [ self.packages.${pkgs.system}.clan-cli ];
environment.etc.install-closure.source = "${closureInfo}/store-paths";
nix.settings = {
substituters = lib.mkForce [ ];
@ -87,11 +79,18 @@
flake-registry = pkgs.writeText "flake-registry" ''{"flakes":[],"version":2}'';
};
system.extraDependencies = dependencies;
clanCore.state.test-backups.folders = [ "/var/test-backups" ];
clan.core.state.test-backups.folders = [ "/var/test-backups" ];
clanCore.state.test-service = {
preRestoreCommand = "pre-restore-command";
postRestoreCommand = "post-restore-command";
clan.core.state.test-service = {
preBackupScript = ''
touch /var/test-service/pre-backup-command
'';
preRestoreScript = ''
touch /var/test-service/pre-restore-command
'';
postRestoreScript = ''
touch /var/test-service/post-restore-command
'';
folders = [ "/var/test-service" ];
};
clan.borgbackup.destinations.test-backup.repo = "borg@machine:.";
@ -145,14 +144,14 @@
machine.succeed("echo testing > /var/test-backups/somefile")
# create
machine.succeed("clan --debug --flake ${self} backups create test-backup")
machine.succeed("clan backups create --debug --flake ${self} test-backup")
machine.wait_until_succeeds("! systemctl is-active borgbackup-job-test-backup >&2")
machine.succeed("test -f /run/mount-external-disk")
machine.succeed("test -f /run/unmount-external-disk")
# list
backup_id = json.loads(machine.succeed("borg-job-test-backup list --json"))["archives"][0]["archive"]
out = machine.succeed("clan --debug --flake ${self} backups list test-backup").strip()
out = machine.succeed("clan backups list --debug --flake ${self} test-backup").strip()
print(out)
assert backup_id in out, f"backup {backup_id} not found in {out}"
localbackup_id = "hdd::/mnt/external-disk/snapshot.0"
@ -160,17 +159,19 @@
## borgbackup restore
machine.succeed("rm -f /var/test-backups/somefile")
machine.succeed(f"clan --debug --flake ${self} backups restore test-backup borgbackup 'test-backup::borg@machine:.::{backup_id}' >&2")
machine.succeed(f"clan backups restore --debug --flake ${self} test-backup borgbackup 'test-backup::borg@machine:.::{backup_id}' >&2")
assert machine.succeed("cat /var/test-backups/somefile").strip() == "testing", "restore failed"
machine.succeed("test -f /var/test-service/pre-restore-command")
machine.succeed("test -f /var/test-service/post-restore-command")
machine.succeed("test -f /var/test-service/pre-backup-command")
## localbackup restore
machine.succeed("rm -f /var/test-backups/somefile /var/test-service/{pre,post}-restore-command")
machine.succeed(f"clan --debug --flake ${self} backups restore test-backup localbackup '{localbackup_id}' >&2")
machine.succeed("rm -rf /var/test-backups/somefile /var/test-service/ && mkdir -p /var/test-service")
machine.succeed(f"clan backups restore --debug --flake ${self} test-backup localbackup '{localbackup_id}' >&2")
assert machine.succeed("cat /var/test-backups/somefile").strip() == "testing", "restore failed"
machine.succeed("test -f /var/test-service/pre-restore-command")
machine.succeed("test -f /var/test-service/post-restore-command")
machine.succeed("test -f /var/test-service/pre-backup-command")
'';
} { inherit pkgs self; };
};

View File

@ -16,9 +16,9 @@
};
}
{
clanCore.machineName = "machine";
clanCore.clanDir = ./.;
clanCore.state.testState.folders = [ "/etc/state" ];
clan.core.machineName = "machine";
clan.core.clanDir = ./.;
clan.core.state.testState.folders = [ "/etc/state" ];
environment.etc.state.text = "hello world";
systemd.tmpfiles.settings."vmsecrets" = {
"/etc/secrets/borgbackup.ssh" = {
@ -36,7 +36,7 @@
};
};
};
clanCore.facts.secretStore = "vm";
clan.core.facts.secretStore = "vm";
clan.borgbackup.destinations.test.repo = "borg@localhost:.";
}

View File

@ -10,8 +10,8 @@
self.clanModules.deltachat
self.nixosModules.clanCore
{
clanCore.machineName = "machine";
clanCore.clanDir = ./.;
clan.core.machineName = "machine";
clan.core.clanDir = ./.;
}
];
};

View File

@ -23,7 +23,7 @@
options =
(pkgs.nixos {
imports = [ self.nixosModules.clanCore ];
clanCore.clanDir = ./.;
clan.core.clanDir = ./.;
}).options;
warningsAreErrors = false;
};
@ -44,6 +44,7 @@
zt-tcp-relay = import ./zt-tcp-relay nixosTestArgs;
borgbackup = import ./borgbackup nixosTestArgs;
syncthing = import ./syncthing nixosTestArgs;
postgresql = import ./postgresql nixosTestArgs;
wayland-proxy-virtwl = import ./wayland-proxy-virtwl nixosTestArgs;
};

View File

@ -1,33 +1,50 @@
{ ... }:
{ self, ... }:
{
perSystem =
{ ... }:
{
# checks = pkgs.lib.mkIf (pkgs.stdenv.isLinux) {
# flash = (import ../lib/test-base.nix) {
# name = "flash";
# nodes.target = {
# virtualisation.emptyDiskImages = [ 4096 ];
# virtualisation.memorySize = 3000;
# environment.systemPackages = [ self.packages.${pkgs.system}.clan-cli ];
# environment.etc."install-closure".source = "${closureInfo}/store-paths";
nodes,
pkgs,
lib,
...
}:
let
dependencies = [
pkgs.disko
self.clanInternals.machines.${pkgs.hostPlatform.system}.test_install_machine.config.system.build.toplevel
self.clanInternals.machines.${pkgs.hostPlatform.system}.test_install_machine.config.system.build.diskoScript
self.clanInternals.machines.${pkgs.hostPlatform.system}.test_install_machine.config.system.build.diskoScript.drvPath
self.clanInternals.machines.${pkgs.hostPlatform.system}.test_install_machine.config.system.clan.deployment.file
] ++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
in
{
# Currently disabled...
checks = pkgs.lib.mkIf (pkgs.stdenv.isLinux) {
flash = (import ../lib/test-base.nix) {
name = "flash";
nodes.target = {
virtualisation.emptyDiskImages = [ 4096 ];
virtualisation.memorySize = 3000;
environment.systemPackages = [ self.packages.${pkgs.system}.clan-cli ];
environment.etc."install-closure".source = "${closureInfo}/store-paths";
# nix.settings = {
# substituters = lib.mkForce [ ];
# hashed-mirrors = null;
# connect-timeout = lib.mkForce 3;
# flake-registry = pkgs.writeText "flake-registry" ''{"flakes":[],"version":2}'';
# experimental-features = [
# "nix-command"
# "flakes"
# ];
# };
# };
# testScript = ''
# start_all()
# machine.succeed("clan --debug --flake ${../..} flash --yes --disk main /dev/vdb test_install_machine")
# '';
# } { inherit pkgs self; };
# };
nix.settings = {
substituters = lib.mkForce [ ];
hashed-mirrors = null;
connect-timeout = lib.mkForce 3;
flake-registry = pkgs.writeText "flake-registry" ''{"flakes":[],"version":2}'';
experimental-features = [
"nix-command"
"flakes"
];
};
};
testScript = ''
start_all()
machine.succeed("clan flash --debug --flake ${../..} --yes --disk main /dev/vdb test_install_machine")
'';
} { inherit pkgs self; };
};
};
}

View File

@ -7,6 +7,8 @@
#!${pkgs.bash}/bin/bash
set -euo pipefail
unset CLAN_DIR
export PATH="${
lib.makeBinPath [
pkgs.gitMinimal

View File

@ -2,8 +2,8 @@
{
clan.machines.test_install_machine = {
clan.networking.targetHost = "test_install_machine";
fileSystems."/".device = lib.mkDefault "/dev/null";
boot.loader.grub.device = lib.mkDefault "/dev/null";
fileSystems."/".device = lib.mkDefault "/dev/vdb";
boot.loader.grub.device = lib.mkDefault "/dev/vdb";
imports = [ self.nixosModules.test_install_machine ];
};
@ -98,7 +98,7 @@
client.succeed("${pkgs.coreutils}/bin/install -Dm 600 ${../lib/ssh/privkey} /root/.ssh/id_ed25519")
client.wait_until_succeeds("ssh -o StrictHostKeyChecking=accept-new -v root@target hostname")
client.succeed("clan --debug --flake ${../..} machines install --yes test_install_machine root@target >&2")
client.succeed("clan machines install --debug --flake ${../..} --yes test_install_machine root@target >&2")
try:
target.shutdown()
except BrokenPipeError:

View File

@ -151,7 +151,7 @@ class Machine:
"""
# Always run command with shell opts
command = f"set -euo pipefail; {command}"
command = f"set -eo pipefail; source /etc/profile; set -u; {command}"
proc = subprocess.run(
[

View File

@ -10,6 +10,7 @@ in
hostPkgs = pkgs;
# speed-up evaluation
defaults = {
nix.package = pkgs.nixVersions.latest;
documentation.enable = lib.mkDefault false;
boot.isContainer = true;

View File

@ -10,6 +10,7 @@ in
defaults = {
documentation.enable = lib.mkDefault false;
nix.settings.min-free = 0;
nix.package = pkgs.nixVersions.latest;
};
# to accept external dependencies such as disko

View File

@ -4,26 +4,61 @@
name = "matrix-synapse";
nodes.machine =
{ self, lib, ... }:
{
config,
self,
lib,
...
}:
{
imports = [
self.clanModules.matrix-synapse
self.nixosModules.clanCore
{
clanCore.machineName = "machine";
clanCore.clanDir = ./.;
clan.matrix-synapse = {
enable = true;
domain = "clan.test";
};
}
{
# secret override
clanCore.facts.services.matrix-synapse.secret.synapse-registration_shared_secret.path = "${./synapse-registration_shared_secret}";
clan.core.machineName = "machine";
clan.core.clanDir = ./.;
services.nginx.virtualHosts."matrix.clan.test" = {
enableACME = lib.mkForce false;
forceSSL = lib.mkForce false;
};
clan.matrix-synapse.domain = "clan.test";
clan.matrix-synapse.users.admin.admin = true;
clan.matrix-synapse.users.someuser = { };
clan.core.facts.secretStore = "vm";
# because we use systemd-tmpfiles to copy the secrets, we need to a seperate systemd-tmpfiles call to provison them.
boot.postBootCommands = "${config.systemd.package}/bin/systemd-tmpfiles --create /etc/tmpfiles.d/00-vmsecrets.conf";
systemd.tmpfiles.settings."00-vmsecrets" = {
# run before 00-nixos.conf
"/etc/secrets" = {
d.mode = "0700";
z.mode = "0700";
};
"/etc/secrets/synapse-registration_shared_secret" = {
f.argument = "supersecret";
z = {
mode = "0400";
user = "root";
};
};
"/etc/secrets/matrix-password-admin" = {
f.argument = "matrix-password1";
z = {
mode = "0400";
user = "root";
};
};
"/etc/secrets/matrix-password-someuser" = {
f.argument = "matrix-password2";
z = {
mode = "0400";
user = "root";
};
};
};
}
];
};
@ -32,6 +67,12 @@
machine.wait_for_unit("matrix-synapse")
machine.succeed("${pkgs.netcat}/bin/nc -z -v ::1 8008")
machine.succeed("${pkgs.curl}/bin/curl -Ssf -L http://localhost/_matrix/static/ -H 'Host: matrix.clan.test'")
machine.systemctl("restart matrix-synapse >&2") # check if user creation is idempotent
machine.execute("journalctl -u matrix-synapse --no-pager >&2")
machine.wait_for_unit("matrix-synapse")
machine.succeed("${pkgs.netcat}/bin/nc -z -v ::1 8008")
machine.succeed("${pkgs.curl}/bin/curl -Ssf -L http://localhost/_matrix/static/ -H 'Host: matrix.clan.test'")
'';
}
)

View File

@ -0,0 +1,72 @@
(import ../lib/container-test.nix) ({
name = "postgresql";
nodes.machine =
{ self, config, ... }:
{
imports = [
self.nixosModules.clanCore
self.clanModules.postgresql
self.clanModules.localbackup
];
clan.postgresql.users.test = { };
clan.postgresql.databases.test.create.options.OWNER = "test";
clan.postgresql.databases.test.restore.stopOnRestore = [ "sample-service" ];
clan.localbackup.targets.hdd.directory = "/mnt/external-disk";
systemd.services.sample-service = {
wantedBy = [ "multi-user.target" ];
script = ''
while true; do
echo "Hello, world!"
sleep 5
done
'';
};
environment.systemPackages = [ config.services.postgresql.package ];
};
testScript =
{ nodes, ... }:
''
start_all()
machine.wait_for_unit("postgresql")
machine.wait_for_unit("sample-service")
# Create a test table
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -c 'CREATE TABLE test (id serial PRIMARY KEY);' test")
machine.succeed("/run/current-system/sw/bin/localbackup-create >&2")
timestamp_before = int(machine.succeed("systemctl show --property=ExecMainStartTimestampMonotonic sample-service | cut -d= -f2").strip())
machine.succeed("test -e /mnt/external-disk/snapshot.0/machine/var/backup/postgres/test/pg-dump || { echo 'pg-dump not found'; exit 1; }")
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c 'INSERT INTO test DEFAULT VALUES;'")
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c 'DROP TABLE test;'")
machine.succeed("test -e /var/backup/postgres/test/pg-dump || { echo 'pg-dump not found'; exit 1; }")
machine.succeed("rm -rf /var/backup/postgres")
machine.succeed("NAME=/mnt/external-disk/snapshot.0 FOLDERS=/var/backup/postgres/test /run/current-system/sw/bin/localbackup-restore >&2")
machine.succeed("test -e /var/backup/postgres/test/pg-dump || { echo 'pg-dump not found'; exit 1; }")
machine.succeed("""
set -x
${nodes.machine.clan.core.state.test.postRestoreCommand}
""")
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -l >&2")
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c '\dt' >&2")
timestamp_after = int(machine.succeed("systemctl show --property=ExecMainStartTimestampMonotonic sample-service | cut -d= -f2").strip())
assert timestamp_before < timestamp_after, f"{timestamp_before} >= {timestamp_after}: expected sample-service to be restarted after restore"
# Check that the table is still there
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c 'SELECT * FROM test;'")
output = machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql --csv -c \"SELECT datdba::regrole FROM pg_database WHERE datname = 'test'\"")
owner = output.split("\n")[1]
assert owner == "test", f"Expected database owner to be 'test', got '{owner}'"
# check if restore works if the database does not exist
machine.succeed("runuser -u postgres -- dropdb test")
machine.succeed("${nodes.machine.clan.core.state.test.postRestoreCommand}")
machine.succeed("runuser -u postgres -- /run/current-system/sw/bin/psql -d test -c '\dt' >&2")
'';
})

View File

@ -10,8 +10,8 @@
environment.etc."group-secret".source = config.sops.secrets.group-secret.path;
sops.age.keyFile = "/etc/privkey.age";
clanCore.clanDir = "${./.}";
clanCore.machineName = "machine";
clan.core.clanDir = "${./.}";
clan.core.machineName = "machine";
networking.hostName = "machine";
};

View File

@ -12,14 +12,14 @@
self.clanModules.syncthing
self.nixosModules.clanCore
{
clanCore.machineName = "introducer";
clanCore.clanDir = ./.;
clan.core.machineName = "introducer";
clan.core.clanDir = ./.;
environment.etc = {
"syncthing.pam".source = ./introducer/introducer_test_cert;
"syncthing.key".source = ./introducer/introducer_test_key;
"syncthing.api".source = ./introducer/introducer_test_api;
};
clanCore.facts.services.syncthing.secret."syncthing.api".path = "/etc/syncthing.api";
clan.core.facts.services.syncthing.secret."syncthing.api".path = "/etc/syncthing.api";
services.syncthing.cert = "/etc/syncthing.pam";
services.syncthing.key = "/etc/syncthing.key";
# Doesn't test zerotier!
@ -53,8 +53,8 @@
self.clanModules.syncthing
self.nixosModules.clanCore
{
clanCore.machineName = "peer1";
clanCore.clanDir = ./.;
clan.core.machineName = "peer1";
clan.core.clanDir = ./.;
clan.syncthing.introducer = lib.strings.removeSuffix "\n" (
builtins.readFile ./introducer/introducer_device_id
);
@ -75,8 +75,8 @@
self.clanModules.syncthing
self.nixosModules.clanCore
{
clanCore.machineName = "peer2";
clanCore.clanDir = ./.;
clan.core.machineName = "peer2";
clan.core.clanDir = ./.;
clan.syncthing.introducer = lib.strings.removeSuffix "\n" (
builtins.readFile ./introducer/introducer_device_id
);

View File

@ -14,8 +14,8 @@ import ../lib/test-base.nix (
imports = [
self.nixosModules.clanCore
{
clanCore.machineName = "machine";
clanCore.clanDir = ./.;
clan.core.machineName = "machine";
clan.core.clanDir = ./.;
}
];
services.wayland-proxy-virtwl.enable = true;

View File

@ -10,8 +10,8 @@
self.nixosModules.clanCore
self.clanModules.zt-tcp-relay
{
clanCore.machineName = "machine";
clanCore.clanDir = ./.;
clan.core.machineName = "machine";
clan.core.clanDir = ./.;
}
];
};

View File

@ -0,0 +1,10 @@
Statically configure borgbackup with sane defaults.
---
This module implements the `borgbackup` backend and implements sane defaults
for backup management through `borgbackup` for members of the clan.
Configure target machines where the backups should be sent to through `targets`.
Configure machines that should be backuped either through `includeMachines`
which will exclusively add the included machines to be backuped, or through
`excludeMachines`, which will add every machine except the excluded machine to the backup.

View File

@ -0,0 +1,101 @@
{ lib, config, ... }:
let
clanDir = config.clan.core.clanDir;
machineDir = clanDir + "/machines/";
in
{
imports = [ ../borgbackup ];
options.clan.borgbackup-static = {
excludeMachines = lib.mkOption {
type = lib.types.listOf lib.types.str;
example = [ config.clan.core.machineName ];
default = [ ];
description = ''
Machines that should not be backuped.
Mutually exclusive with includeMachines.
If this is not empty, every other machine except the targets in the clan will be backuped by this module.
If includeMachines is set, only the included machines will be backuped.
'';
};
includeMachines = lib.mkOption {
type = lib.types.listOf lib.types.str;
example = [ config.clan.core.machineName ];
default = [ ];
description = ''
Machines that should be backuped.
Mutually exclusive with excludeMachines.
'';
};
targets = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = ''
Machines that should act as target machines for backups.
'';
};
};
config.services.borgbackup.repos =
let
machines = builtins.readDir machineDir;
borgbackupIpMachinePath = machines: machineDir + machines + "/facts/borgbackup.ssh.pub";
filteredMachines =
if ((builtins.length config.clan.borgbackup-static.includeMachines) != 0) then
lib.filterAttrs (name: _: (lib.elem name config.clan.borgbackup-static.includeMachines)) machines
else
lib.filterAttrs (name: _: !(lib.elem name config.clan.borgbackup-static.excludeMachines)) machines;
machinesMaybeKey = lib.mapAttrsToList (
machine: _:
let
fullPath = borgbackupIpMachinePath machine;
in
if builtins.pathExists fullPath then machine else null
) filteredMachines;
machinesWithKey = lib.filter (x: x != null) machinesMaybeKey;
hosts = builtins.map (machine: {
name = machine;
value = {
path = "/var/lib/borgbackup/${machine}";
authorizedKeys = [ (builtins.readFile (borgbackupIpMachinePath machine)) ];
};
}) machinesWithKey;
in
lib.mkIf
(builtins.any (
target: target == config.clan.core.machineName
) config.clan.borgbackup-static.targets)
(if (builtins.listToAttrs hosts) != null then builtins.listToAttrs hosts else { });
config.clan.borgbackup.destinations =
let
destinations = builtins.map (d: {
name = d;
value = {
repo = "borg@${d}:/var/lib/borgbackup/${config.clan.core.machineName}";
};
}) config.clan.borgbackup-static.targets;
in
lib.mkIf (builtins.any (
target: target == config.clan.core.machineName
) config.clan.borgbackup-static.includeMachines) (builtins.listToAttrs destinations);
config.assertions = [
{
assertion =
!(
((builtins.length config.clan.borgbackup-static.excludeMachines) != 0)
&& ((builtins.length config.clan.borgbackup-static.includeMachines) != 0)
);
message = ''
The options:
config.clan.borgbackup-static.excludeMachines = [${builtins.toString config.clan.borgbackup-static.excludeMachines}]
and
config.clan.borgbackup-static.includeMachines = [${builtins.toString config.clan.borgbackup-static.includeMachines}]
are mutually exclusive.
Use excludeMachines to exclude certain machines and backup the other clan machines.
Use include machines to only backup certain machines.
'';
}
];
}

View File

@ -6,6 +6,27 @@
}:
let
cfg = config.clan.borgbackup;
preBackupScript = ''
declare -A preCommandErrors
${lib.concatMapStringsSep "\n" (
state:
lib.optionalString (state.preBackupCommand != null) ''
echo "Running pre-backup command for ${state.name}"
if ! /run/current-system/sw/bin/${state.preBackupCommand}; then
preCommandErrors["${state.name}"]=1
fi
''
) (lib.attrValues config.clan.core.state)}
if [[ ''${#preCommandErrors[@]} -gt 0 ]]; then
echo "pre-backup commands failed for the following services:"
for state in "''${!preCommandErrors[@]}"; do
echo " $state"
done
exit 1
fi
'';
in
{
options.clan.borgbackup.destinations = lib.mkOption {
@ -26,9 +47,9 @@ in
rsh = lib.mkOption {
type = lib.types.str;
default = "ssh -i ${
config.clanCore.facts.services.borgbackup.secret."borgbackup.ssh".path
} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null";
defaultText = "ssh -i \${config.clanCore.facts.services.borgbackup.secret.\"borgbackup.ssh\".path} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null";
config.clan.core.facts.services.borgbackup.secret."borgbackup.ssh".path
} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=Yes";
defaultText = "ssh -i \${config.clan.core.facts.services.borgbackup.secret.\"borgbackup.ssh\".path} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null";
description = "the rsh to use for the backup";
};
};
@ -50,21 +71,30 @@ in
];
config = lib.mkIf (cfg.destinations != { }) {
systemd.services = lib.mapAttrs' (
_: dest:
lib.nameValuePair "borgbackup-job-${dest.name}" {
# since borgbackup mounts the system read-only, we need to run in a ExecStartPre script, so we can generate additional files.
serviceConfig.ExecStartPre = [
(''+${pkgs.writeShellScript "borgbackup-job-${dest.name}-pre-backup-commands" preBackupScript}'')
];
}
) cfg.destinations;
services.borgbackup.jobs = lib.mapAttrs (_: dest: {
paths = lib.flatten (map (state: state.folders) (lib.attrValues config.clanCore.state));
paths = lib.unique (
lib.flatten (map (state: state.folders) (lib.attrValues config.clan.core.state))
);
exclude = [ "*.pyc" ];
repo = dest.repo;
environment.BORG_RSH = dest.rsh;
compression = "auto,zstd";
startAt = "*-*-* 01:00:00";
persistentTimer = true;
preHook = ''
set -x
'';
encryption = {
mode = "repokey";
passCommand = "cat ${config.clanCore.facts.services.borgbackup.secret."borgbackup.repokey".path}";
passCommand = "cat ${config.clan.core.facts.services.borgbackup.secret."borgbackup.repokey".path}";
};
prune.keep = {
@ -75,7 +105,7 @@ in
};
}) cfg.destinations;
clanCore.facts.services.borgbackup = {
clan.core.facts.services.borgbackup = {
public."borgbackup.ssh.pub" = { };
secret."borgbackup.ssh" = { };
secret."borgbackup.repokey" = { };
@ -111,7 +141,7 @@ in
(pkgs.writeShellScriptBin "borgbackup-restore" ''
set -efux
cd /
IFS=';' read -ra FOLDER <<< "$FOLDERS"
IFS=':' read -ra FOLDER <<< "$FOLDERS"
job_name=$(echo "$NAME" | ${pkgs.gawk}/bin/awk -F'::' '{print $1}')
backup_name=''${NAME#"$job_name"::}
if ! command -v borg-job-"$job_name" &> /dev/null; then
@ -122,7 +152,7 @@ in
'')
];
clanCore.backups.providers.borgbackup = {
clan.core.backups.providers.borgbackup = {
list = "borgbackup-list";
create = "borgbackup-create";
restore = "borgbackup-restore";

View File

@ -5,7 +5,7 @@
services.maddy =
let
domain = "${config.clanCore.machineName}.local";
domain = "${config.clan.core.machineName}.local";
in
{
enable = true;

View File

@ -10,5 +10,5 @@ _: {
};
};
clanCore.state.ergochat.folders = [ "/var/lib/ergo" ];
clan.core.state.ergochat.folders = [ "/var/lib/ergo" ];
}

View File

@ -5,18 +5,22 @@
imports = [ ./disk-layouts ];
};
borgbackup = ./borgbackup;
borgbackup-static = ./borgbackup-static;
deltachat = ./deltachat;
ergochat = ./ergochat;
localbackup = ./localbackup;
localsend = ./localsend;
matrix-synapse = ./matrix-synapse;
moonlight = ./moonlight;
postgresql = ./postgresql;
root-password = ./root-password;
sshd = ./sshd;
sunshine = ./sunshine;
static-hosts = ./static-hosts;
syncthing = ./syncthing;
syncthing-static-peers = ./syncthing-static-peers;
thelounge = ./thelounge;
trusted-nix-caches = ./trusted-nix-caches;
user-password = ./user-password;
xfce = ./xfce;
zerotier-static-peers = ./zerotier-static-peers;

View File

@ -6,7 +6,10 @@
}:
let
cfg = config.clan.localbackup;
rsnapshotConfig = target: states: ''
uniqueFolders = lib.unique (
lib.flatten (lib.mapAttrsToList (_name: state: state.folders) config.clan.core.state)
);
rsnapshotConfig = target: ''
config_version 1.2
snapshot_root ${target.directory}
sync_first 1
@ -17,12 +20,6 @@ let
cmd_logger ${pkgs.inetutils}/bin/logger
cmd_du ${pkgs.coreutils}/bin/du
cmd_rsnapshot_diff ${pkgs.rsnapshot}/bin/rsnapshot-diff
${lib.optionalString (target.preBackupHook != null) ''
cmd_preexec ${pkgs.writeShellScript "preexec.sh" ''
set -efu -o pipefail
${target.preBackupHook}
''}
''}
${lib.optionalString (target.postBackupHook != null) ''
cmd_postexec ${pkgs.writeShellScript "postexec.sh" ''
@ -31,11 +28,9 @@ let
''}
''}
retain snapshot ${builtins.toString config.clan.localbackup.snapshots}
${lib.concatMapStringsSep "\n" (state: ''
${lib.concatMapStringsSep "\n" (folder: ''
backup ${folder} ${config.networking.hostName}/
'') state.folders}
'') states}
${lib.concatMapStringsSep "\n" (folder: ''
backup ${folder} ${config.networking.hostName}/
'') uniqueFolders}
'';
in
{
@ -129,14 +124,29 @@ in
]
}
${lib.concatMapStringsSep "\n" (target: ''
(
${mountHook target}
echo "Creating backup '${target.name}'"
rsnapshot -c "${pkgs.writeText "rsnapshot.conf" (rsnapshotConfig target (lib.attrValues config.clanCore.state))}" sync
rsnapshot -c "${pkgs.writeText "rsnapshot.conf" (rsnapshotConfig target (lib.attrValues config.clanCore.state))}" snapshot
)
'') (builtins.attrValues cfg.targets)}
'')
${mountHook target}
echo "Creating backup '${target.name}'"
${lib.optionalString (target.preBackupHook != null) ''
(
${target.preBackupHook}
)
''}
declare -A preCommandErrors
${lib.concatMapStringsSep "\n" (
state:
lib.optionalString (state.preBackupCommand != null) ''
echo "Running pre-backup command for ${state.name}"
if ! /run/current-system/sw/bin/${state.preBackupCommand}; then
preCommandErrors["${state.name}"]=1
fi
''
) (builtins.attrValues config.clan.core.state)}
rsnapshot -c "${pkgs.writeText "rsnapshot.conf" (rsnapshotConfig target)}" sync
rsnapshot -c "${pkgs.writeText "rsnapshot.conf" (rsnapshotConfig target)}" snapshot
'') (builtins.attrValues cfg.targets)}'')
(pkgs.writeShellScriptBin "localbackup-list" ''
set -efu -o pipefail
export PATH=${
@ -167,6 +177,14 @@ in
pkgs.gawk
]
}
if [[ "''${NAME:-}" == "" ]]; then
echo "No backup name given via NAME environment variable"
exit 1
fi
if [[ "''${FOLDERS:-}" == "" ]]; then
echo "No folders given via FOLDERS environment variable"
exit 1
fi
name=$(awk -F'::' '{print $1}' <<< $NAME)
backupname=''${NAME#$name::}
@ -182,8 +200,9 @@ in
exit 1
fi
IFS=';' read -ra FOLDER <<< "$FOLDERS"
IFS=':' read -ra FOLDER <<< "''$FOLDERS"
for folder in "''${FOLDER[@]}"; do
mkdir -p "$folder"
rsync -a "$backupname/${config.networking.hostName}$folder/" "$folder"
done
'')
@ -213,7 +232,7 @@ in
''
) cfg.targets;
clanCore.backups.providers.localbackup = {
clan.core.backups.providers.localbackup = {
# TODO list needs to run locally or on the remote machine
list = "localbackup-list";
create = "localbackup-create";

View File

@ -9,7 +9,7 @@
# - cli frontend: https://github.com/localsend/localsend/issues/11
# - ipv6 support: https://github.com/localsend/localsend/issues/549
options.clan.localsend = {
enable = lib.mkEnableOption (lib.mdDoc "enable the localsend module");
enable = lib.mkEnableOption "enable the localsend module";
defaultLocation = lib.mkOption {
type = lib.types.str;
description = "The default download location";
@ -18,7 +18,7 @@
};
config = lib.mkIf config.clan.localsend.enable {
clanCore.state.localsend.folders = [
clan.core.state.localsend.folders = [
"/var/localsend"
config.clan.localsend.defaultLocation
];

View File

@ -0,0 +1,100 @@
From bc199a27f23b0fcf175b116f7cf606c0d22b422a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= <joerg@thalheim.io>
Date: Tue, 11 Jun 2024 11:40:47 +0200
Subject: [PATCH 1/2] register_new_matrix_user: add password-file flag
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
getpass in python expects stdin to be a tty, hence we cannot just pipe
into register_new_matrix_user. --password-file instead works better and
it would also allow the use of stdin if /dev/stdin is passed.
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
Signed-off-by: Jörg Thalheim <joerg@thalheim.io>
---
changelog.d/17294.feature | 2 ++
debian/register_new_matrix_user.ronn | 9 +++++++--
synapse/_scripts/register_new_matrix_user.py | 20 +++++++++++++++-----
3 files changed, 24 insertions(+), 7 deletions(-)
create mode 100644 changelog.d/17294.feature
diff --git a/changelog.d/17294.feature b/changelog.d/17294.feature
new file mode 100644
index 000000000..33aac7b0b
--- /dev/null
+++ b/changelog.d/17294.feature
@@ -0,0 +1,2 @@
+`register_new_matrix_user` now supports a --password-file flag, which
+is useful for scripting.
diff --git a/debian/register_new_matrix_user.ronn b/debian/register_new_matrix_user.ronn
index 0410b1f4c..d99e9215a 100644
--- a/debian/register_new_matrix_user.ronn
+++ b/debian/register_new_matrix_user.ronn
@@ -31,8 +31,13 @@ A sample YAML file accepted by `register_new_matrix_user` is described below:
Local part of the new user. Will prompt if omitted.
* `-p`, `--password`:
- New password for user. Will prompt if omitted. Supplying the password
- on the command line is not recommended. Use the STDIN instead.
+ New password for user. Will prompt if this option and `--password-file` are omitted.
+ Supplying the password on the command line is not recommended.
+ Use `--password-file` if possible.
+
+ * `--password-file`:
+ File containing the new password for user. If set, overrides `--password`.
+ This is a more secure alternative to specifying the password on the command line.
* `-a`, `--admin`:
Register new user as an admin. Will prompt if omitted.
diff --git a/synapse/_scripts/register_new_matrix_user.py b/synapse/_scripts/register_new_matrix_user.py
index 77a7129ee..972b35e2d 100644
--- a/synapse/_scripts/register_new_matrix_user.py
+++ b/synapse/_scripts/register_new_matrix_user.py
@@ -173,11 +173,18 @@ def main() -> None:
default=None,
help="Local part of the new user. Will prompt if omitted.",
)
- parser.add_argument(
+ password_group = parser.add_mutually_exclusive_group()
+ password_group.add_argument(
"-p",
"--password",
default=None,
- help="New password for user. Will prompt if omitted.",
+ help="New password for user. Will prompt for a password if "
+ "this flag and `--password-file` are both omitted.",
+ )
+ password_group.add_argument(
+ "--password-file",
+ default=None,
+ help="File containing the new password for user. If set, will override `--password`.",
)
parser.add_argument(
"-t",
@@ -247,6 +254,11 @@ def main() -> None:
print(_NO_SHARED_SECRET_OPTS_ERROR, file=sys.stderr)
sys.exit(1)
+ if args.password_file:
+ password = _read_file(args.password_file, "password-file").strip()
+ else:
+ password = args.password
+
if args.server_url:
server_url = args.server_url
elif config is not None:
@@ -269,9 +281,7 @@ def main() -> None:
if args.admin or args.no_admin:
admin = args.admin
- register_new_user(
- args.user, args.password, server_url, secret, admin, args.user_type
- )
+ register_new_user(args.user, password, server_url, secret, admin, args.user_type)
def _read_file(file_path: Any, config_path: str) -> str:
--
2.44.1

View File

@ -0,0 +1,94 @@
From 1789416df425d22693b0055a6688d8686e0ee4a1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= <joerg@thalheim.io>
Date: Thu, 13 Jun 2024 14:38:19 +0200
Subject: [PATCH 2/2] register-new-matrix-user: add a flag to ignore already
existing users
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This allows to register users in a more declarative and stateless way.
Signed-off-by: Jörg Thalheim <joerg@thalheim.io>
---
synapse/_scripts/register_new_matrix_user.py | 22 ++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/synapse/_scripts/register_new_matrix_user.py b/synapse/_scripts/register_new_matrix_user.py
index 972b35e2d..233e7267d 100644
--- a/synapse/_scripts/register_new_matrix_user.py
+++ b/synapse/_scripts/register_new_matrix_user.py
@@ -52,6 +52,7 @@ def request_registration(
user_type: Optional[str] = None,
_print: Callable[[str], None] = print,
exit: Callable[[int], None] = sys.exit,
+ exists_ok: bool = False,
) -> None:
url = "%s/_synapse/admin/v1/register" % (server_location.rstrip("/"),)
@@ -97,6 +98,10 @@ def request_registration(
r = requests.post(url, json=data)
if r.status_code != 200:
+ response = r.json()
+ if exists_ok and response["errcode"] == "M_USER_IN_USE":
+ _print("User already exists. Skipping.")
+ return
_print("ERROR! Received %d %s" % (r.status_code, r.reason))
if 400 <= r.status_code < 500:
try:
@@ -115,6 +120,7 @@ def register_new_user(
shared_secret: str,
admin: Optional[bool],
user_type: Optional[str],
+ exists_ok: bool = False,
) -> None:
if not user:
try:
@@ -154,7 +160,13 @@ def register_new_user(
admin = False
request_registration(
- user, password, server_location, shared_secret, bool(admin), user_type
+ user,
+ password,
+ server_location,
+ shared_secret,
+ bool(admin),
+ user_type,
+ exists_ok=exists_ok,
)
@@ -173,6 +185,11 @@ def main() -> None:
default=None,
help="Local part of the new user. Will prompt if omitted.",
)
+ parser.add_argument(
+ "--exists-ok",
+ action="store_true",
+ help="Do not fail if user already exists.",
+ )
password_group = parser.add_mutually_exclusive_group()
password_group.add_argument(
"-p",
@@ -192,6 +209,7 @@ def main() -> None:
default=None,
help="User type as specified in synapse.api.constants.UserTypes",
)
+
admin_group = parser.add_mutually_exclusive_group()
admin_group.add_argument(
"-a",
@@ -281,7 +299,7 @@ def main() -> None:
if args.admin or args.no_admin:
admin = args.admin
- register_new_user(args.user, password, server_url, secret, admin, args.user_type)
+ register_new_user(args.user, password, server_url, secret, admin, args.user_type, exists_ok=args.exists_ok)
def _read_file(file_path: Any, config_path: str) -> str:
--
2.44.1

View File

@ -6,17 +6,93 @@
}:
let
cfg = config.clan.matrix-synapse;
nginx-vhost = "matrix.${config.clan.matrix-synapse.domain}";
element-web =
pkgs.runCommand "element-web-with-config" { nativeBuildInputs = [ pkgs.buildPackages.jq ]; }
''
cp -r ${pkgs.element-web} $out
chmod -R u+w $out
jq '."default_server_config"."m.homeserver" = { "base_url": "https://${nginx-vhost}:443", "server_name": "${config.clan.matrix-synapse.domain}" }' \
> $out/config.json < ${pkgs.element-web}/config.json
ln -s $out/config.json $out/config.${nginx-vhost}.json
'';
# FIXME: This was taken from upstream. Drop this when our patch is upstream
synapseCfg = config.services.matrix-synapse;
wantedExtras =
synapseCfg.extras
++ lib.optional (synapseCfg.settings ? oidc_providers) "oidc"
++ lib.optional (synapseCfg.settings ? jwt_config) "jwt"
++ lib.optional (synapseCfg.settings ? saml2_config) "saml2"
++ lib.optional (synapseCfg.settings ? redis) "redis"
++ lib.optional (synapseCfg.settings ? sentry) "sentry"
++ lib.optional (synapseCfg.settings ? user_directory) "user-search"
++ lib.optional (synapseCfg.settings.url_preview_enabled) "url-preview"
++ lib.optional (synapseCfg.settings.database.name == "psycopg2") "postgres";
in
{
options.services.matrix-synapse.package = lib.mkOption { readOnly = false; };
options.clan.matrix-synapse = {
enable = lib.mkEnableOption "Enable matrix-synapse";
domain = lib.mkOption {
type = lib.types.str;
description = "The domain name of the matrix server";
example = "example.com";
};
users = lib.mkOption {
default = { };
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
options = {
name = lib.mkOption {
type = lib.types.str;
default = name;
description = "The name of the user";
};
admin = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether the user should be an admin";
};
};
}
)
);
description = "A list of users. Not that only new users will be created and existing ones are not modified.";
example.alice = {
admin = true;
};
};
};
config = lib.mkIf cfg.enable {
imports = [
../postgresql
(lib.mkRemovedOptionModule [
"clan"
"matrix-synapse"
"enable"
] "Importing the module will already enable the service.")
../postgresql
];
config = {
services.matrix-synapse = {
package = lib.mkForce (
pkgs.matrix-synapse.override {
matrix-synapse-unwrapped = pkgs.matrix-synapse.unwrapped.overrideAttrs (_old: {
doInstallCheck = false; # too slow, nixpkgs maintainer already run this.
patches = [
# see: https://github.com/element-hq/synapse/pull/17304
./0001-register_new_matrix_user-add-password-file-flag.patch
./0002-register-new-matrix-user-add-a-flag-to-ignore-alread.patch
];
});
extras = wantedExtras;
plugins = synapseCfg.plugins;
}
);
enable = true;
settings = {
server_name = cfg.domain;
@ -29,6 +105,7 @@ in
"turn:turn.matrix.org?transport=udp"
"turn:turn.matrix.org?transport=tcp"
];
registration_shared_secret_path = "/run/synapse-registration-shared-secret";
listeners = [
{
port = 8008;
@ -49,45 +126,76 @@ in
}
];
};
extraConfigFiles = [ "/var/lib/matrix-synapse/registration_shared_secret.yaml" ];
};
systemd.services.matrix-synapse.serviceConfig.ExecStartPre = [
"+${pkgs.writeScript "copy_registration_shared_secret" ''
#!/bin/sh
cp ${config.clanCore.facts.services.matrix-synapse.secret.synapse-registration_shared_secret.path} /var/lib/matrix-synapse/registration_shared_secret.yaml
chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/registration_shared_secret.yaml
chmod 600 /var/lib/matrix-synapse/registration_shared_secret.yaml
''}"
];
clanCore.facts.services."matrix-synapse" = {
secret."synapse-registration_shared_secret" = { };
generator.path = with pkgs; [
coreutils
pwgen
];
generator.script = ''
echo "registration_shared_secret: $(pwgen -s 32 1)" > "$secrets"/synapse-registration_shared_secret
'';
};
services.postgresql.enable = true;
# we need to use both ensusureDatabases and initialScript, because the former runs everytime but with the wrong collation
services.postgresql = {
ensureDatabases = [ "matrix-synapse" ];
ensureUsers = [
{
name = "matrix-synapse";
ensureDBOwnership = true;
systemd.tmpfiles.settings."01-matrix" = {
"/run/synapse-registration-shared-secret" = {
C.argument =
config.clan.core.facts.services.matrix-synapse.secret.synapse-registration_shared_secret.path;
z = {
mode = "0400";
user = "matrix-synapse";
};
};
};
clan.postgresql.users.matrix-synapse = { };
clan.postgresql.databases.matrix-synapse.create.options = {
TEMPLATE = "template0";
LC_COLLATE = "C";
LC_CTYPE = "C";
ENCODING = "UTF8";
OWNER = "matrix-synapse";
};
clan.postgresql.databases.matrix-synapse.restore.stopOnRestore = [ "matrix-synapse" ];
clan.core.facts.services =
{
"matrix-synapse" = {
secret."synapse-registration_shared_secret" = { };
generator.path = with pkgs; [
coreutils
pwgen
];
generator.script = ''
echo -n "$(pwgen -s 32 1)" > "$secrets"/synapse-registration_shared_secret
'';
};
}
// lib.mapAttrs' (
name: user:
lib.nameValuePair "matrix-password-${user.name}" {
secret."matrix-password-${user.name}" = { };
generator.path = with pkgs; [ xkcdpass ];
generator.script = ''
xkcdpass -n 4 -d - > "$secrets"/${lib.escapeShellArg "matrix-password-${user.name}"}
'';
}
];
initialScript = pkgs.writeText "synapse-init.sql" ''
CREATE DATABASE "matrix-synapse"
TEMPLATE template0
LC_COLLATE = "C"
LC_CTYPE = "C";
'';
};
) cfg.users;
systemd.services.matrix-synapse =
let
usersScript =
''
while ! ${pkgs.netcat}/bin/nc -z -v ::1 8008; do
if ! kill -0 "$MAINPID"; then exit 1; fi
sleep 1;
done
''
+ lib.concatMapStringsSep "\n" (user: ''
# only create user if it doesn't exist
/run/current-system/sw/bin/matrix-synapse-register_new_matrix_user --exists-ok --password-file ${
config.clan.core.facts.services."matrix-password-${user.name}".secret."matrix-password-${user.name}".path
} --user "${user.name}" ${if user.admin then "--admin" else "--no-admin"}
'') (lib.attrValues cfg.users);
in
{
path = [ pkgs.curl ];
serviceConfig.ExecStartPost = [
(''+${pkgs.writeShellScript "matrix-synapse-create-users" usersScript}'')
];
};
services.nginx = {
enable = true;
virtualHosts = {
@ -102,7 +210,7 @@ in
return 200 '${
builtins.toJSON {
"m.homeserver" = {
"base_url" = "https://matrix.${cfg.domain}";
"base_url" = "https://${nginx-vhost}";
};
"m.identity_server" = {
"base_url" = "https://vector.im";
@ -111,15 +219,12 @@ in
}';
'';
};
"matrix.${cfg.domain}" = {
${nginx-vhost} = {
forceSSL = true;
enableACME = true;
locations."/_matrix" = {
proxyPass = "http://localhost:8008";
};
locations."/test".extraConfig = ''
return 200 "Hello, world!";
'';
locations."/_matrix".proxyPass = "http://localhost:8008";
locations."/_synapse".proxyPass = "http://localhost:8008";
locations."/".root = element-web;
};
};
};

View File

@ -13,10 +13,10 @@ in
systemd.tmpfiles.rules = [
"d '/var/lib/moonlight' 0770 'user' 'users' - -"
"C '/var/lib/moonlight/moonlight.cert' 0644 'user' 'users' - ${
config.clanCore.facts.services.moonlight.secret."moonlight.cert".path or ""
config.clan.core.facts.services.moonlight.secret."moonlight.cert".path or ""
}"
"C '/var/lib/moonlight/moonlight.key' 0644 'user' 'users' - ${
config.clanCore.facts.services.moonlight.secret."moonlight.key".path or ""
config.clan.core.facts.services.moonlight.secret."moonlight.key".path or ""
}"
];
@ -45,7 +45,7 @@ in
systemd.user.services.moonlight-join = {
description = "Join sunshine hosts";
script = ''${ms-accept}/bin/moonlight-sunshine-accept moonlight join --port ${builtins.toString defaultPort} --cert '${
config.clanCore.facts.services.moonlight.public."moonlight.cert".value or ""
config.clan.core.facts.services.moonlight.public."moonlight.cert".value or ""
}' --host fd2e:25da:6035:c98f:cd99:93e0:b9b8:9ca1'';
serviceConfig = {
Type = "oneshot";
@ -68,7 +68,7 @@ in
};
};
clanCore.facts.services.moonlight = {
clan.core.facts.services.moonlight = {
secret."moonlight.key" = { };
secret."moonlight.cert" = { };
public."moonlight.cert" = { };

View File

@ -0,0 +1,2 @@
A free and open-source relational database management system (RDBMS) emphasizing extensibility and SQL compliance.
---

View File

@ -0,0 +1,222 @@
{
pkgs,
lib,
config,
...
}:
let
createDatatbaseState =
db:
let
folder = "/var/backup/postgres/${db.name}";
current = "${folder}/pg-dump";
compression = lib.optionalString (lib.versionAtLeast config.services.postgresql.package.version "16") "--compress=zstd";
in
{
folders = [ folder ];
preBackupScript = ''
export PATH=${
lib.makeBinPath [
config.services.postgresql.package
config.systemd.package
pkgs.coreutils
pkgs.util-linux
pkgs.zstd
]
}
while [[ "$(systemctl is-active postgresql)" == activating ]]; do
sleep 1
done
mkdir -p "${folder}"
runuser -u postgres -- pg_dump ${compression} --dbname=${db.name} -Fc -c > "${current}.tmp"
mv "${current}.tmp" ${current}
'';
postRestoreScript = ''
export PATH=${
lib.makeBinPath [
config.services.postgresql.package
config.systemd.package
pkgs.coreutils
pkgs.util-linux
pkgs.zstd
pkgs.gnugrep
]
}
while [[ "$(systemctl is-active postgresql)" == activating ]]; do
sleep 1
done
echo "Waiting for postgres to be ready..."
while ! runuser -u postgres -- psql --port=${builtins.toString config.services.postgresql.settings.port} -d postgres -c "" ; do
if ! systemctl is-active postgresql; then exit 1; fi
sleep 0.1
done
if [[ -e "${current}" ]]; then
(
systemctl stop ${lib.concatStringsSep " " db.restore.stopOnRestore}
trap "systemctl start ${lib.concatStringsSep " " db.restore.stopOnRestore}" EXIT
mkdir -p "${folder}"
if runuser -u postgres -- psql -d postgres -c "SELECT 1 FROM pg_database WHERE datname = '${db.name}'" | grep -q 1; then
runuser -u postgres -- dropdb "${db.name}"
fi
runuser -u postgres -- pg_restore -C -d postgres "${current}"
)
else
echo No database backup found, skipping restore
fi
'';
};
createDatabase = db: ''
CREATE DATABASE "${db.name}" ${
lib.concatStringsSep " " (
lib.mapAttrsToList (name: value: "${name} = '${value}'") db.create.options
)
}
'';
cfg = config.clan.postgresql;
userClauses = lib.mapAttrsToList (
_: user:
''$PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname='${user.name}'" | grep -q 1 || $PSQL -tAc 'CREATE USER "${user.name}"' ''
) cfg.users;
databaseClauses = lib.mapAttrsToList (
name: db:
lib.optionalString db.create.enable ''$PSQL -d postgres -c "SELECT 1 FROM pg_database WHERE datname = '${name}'" | grep -q 1 || $PSQL -d postgres -c ${lib.escapeShellArg (createDatabase db)} ''
) cfg.databases;
in
{
options.clan.postgresql = {
# we are reimplemeting ensureDatabase and ensureUser options here to allow to create databases with options
databases = lib.mkOption {
default = { };
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
options = {
name = lib.mkOption {
type = lib.types.str;
default = name;
description = "Database name.";
};
service = lib.mkOption {
type = lib.types.str;
default = name;
description = "Service name that we associate with the database.";
};
# set to false, in case the upstream module uses ensureDatabase option
create.enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Create the database if it does not exist.";
};
create.options = lib.mkOption {
type = lib.types.lazyAttrsOf lib.types.str;
default = { };
example = {
TEMPLATE = "template0";
LC_COLLATE = "C";
LC_CTYPE = "C";
ENCODING = "UTF8";
OWNER = "foo";
};
};
restore.stopOnRestore = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "List of systemd services to stop before restoring the database.";
};
};
}
)
);
};
users = lib.mkOption {
default = { };
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
options.name = lib.mkOption {
type = lib.types.str;
default = name;
};
}
)
);
};
};
config = {
services.postgresql.settings = {
wal_level = "replica";
max_wal_senders = 3;
};
services.postgresql.enable = true;
# We are duplicating a bit the upstream module but allow to create databases with options
systemd.services.postgresql.postStart = ''
PSQL="psql --port=${builtins.toString config.services.postgresql.settings.port}"
while ! $PSQL -d postgres -c "" 2> /dev/null; do
if ! kill -0 "$MAINPID"; then exit 1; fi
sleep 0.1
done
${lib.concatStringsSep "\n" userClauses}
${lib.concatStringsSep "\n" databaseClauses}
'';
clan.core.state = lib.mapAttrs' (
_: db: lib.nameValuePair db.service (createDatatbaseState db)
) config.clan.postgresql.databases;
environment.systemPackages = builtins.map (
db:
let
folder = "/var/backup/postgres/${db.name}";
current = "${folder}/pg-dump";
in
pkgs.writeShellScriptBin "postgres-db-restore-command-${db.name}" ''
export PATH=${
lib.makeBinPath [
config.services.postgresql.package
config.systemd.package
pkgs.coreutils
pkgs.util-linux
pkgs.zstd
pkgs.gnugrep
]
}
while [[ "$(systemctl is-active postgresql)" == activating ]]; do
sleep 1
done
echo "Waiting for postgres to be ready..."
while ! runuser -u postgres -- psql --port=${builtins.toString config.services.postgresql.settings.port} -d postgres -c "" ; do
if ! systemctl is-active postgresql; then exit 1; fi
sleep 0.1
done
if [[ -e "${current}" ]]; then
(
${
lib.optionalString (db.restore.stopOnRestore != [ ]) ''
systemctl stop ${builtins.toString db.restore.stopOnRestore}
trap "systemctl start ${builtins.toString db.restore.stopOnRestore}" EXIT
''
}
mkdir -p "${folder}"
if runuser -u postgres -- psql -d postgres -c "SELECT 1 FROM pg_database WHERE datname = '${db.name}'" | grep -q 1; then
runuser -u postgres -- dropdb "${db.name}"
fi
runuser -u postgres -- pg_restore -C -d postgres "${current}"
)
else
echo No database backup found, skipping restore
fi
''
) (builtins.attrValues config.clan.postgresql.databases);
};
}

View File

@ -2,9 +2,9 @@
{
users.mutableUsers = false;
users.users.root.hashedPasswordFile =
config.clanCore.facts.services.root-password.secret.password-hash.path;
sops.secrets."${config.clanCore.machineName}-password-hash".neededForUsers = true;
clanCore.facts.services.root-password = {
config.clan.core.facts.services.root-password.secret.password-hash.path;
sops.secrets."${config.clan.core.machineName}-password-hash".neededForUsers = true;
clan.core.facts.services.root-password = {
secret.password = { };
secret.password-hash = { };
generator.path = with pkgs; [

View File

@ -5,12 +5,12 @@
services.openssh.hostKeys = [
{
path = config.clanCore.facts.services.openssh.secret."ssh.id_ed25519".path;
path = config.clan.core.facts.services.openssh.secret."ssh.id_ed25519".path;
type = "ed25519";
}
];
clanCore.facts.services.openssh = {
clan.core.facts.services.openssh = {
secret."ssh.id_ed25519" = { };
public."ssh.id_ed25519.pub" = { };
generator.path = [

View File

@ -3,20 +3,36 @@
options.clan.static-hosts = {
excludeHosts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ config.clanCore.machineName ];
default =
if config.clan.static-hosts.topLevelDomain != "" then [ ] else [ config.clan.core.machineName ];
description = "Hosts that should be excluded";
};
topLevelDomain = lib.mkOption {
type = lib.types.str;
default = "";
description = "Top level domain to reach hosts";
};
};
config.networking.hosts =
let
clanDir = config.clanCore.clanDir;
clanDir = config.clan.core.clanDir;
machineDir = clanDir + "/machines/";
zerotierIpMachinePath = machines: machineDir + machines + "/facts/zerotier-ip";
machines = builtins.readDir machineDir;
machinesFileSet = builtins.readDir machineDir;
machines = lib.mapAttrsToList (name: _: name) machinesFileSet;
networkIpsUnchecked = builtins.map (
machine:
let
fullPath = zerotierIpMachinePath machine;
in
if builtins.pathExists fullPath then machine else null
) machines;
networkIps = lib.filter (machine: machine != null) networkIpsUnchecked;
machinesWithIp = lib.filterAttrs (name: _: (lib.elem name networkIps)) machinesFileSet;
filteredMachines = lib.filterAttrs (
name: _: !(lib.elem name config.clan.static-hosts.excludeHosts)
) machines;
) machinesWithIp;
in
lib.filterAttrs (_: value: value != null) (
lib.mapAttrs' (
@ -24,7 +40,15 @@
let
path = zerotierIpMachinePath machine;
in
if builtins.pathExists path then lib.nameValuePair (builtins.readFile path) [ machine ] else null
if builtins.pathExists path then
lib.nameValuePair (builtins.readFile path) (
if (config.clan.static-hosts.topLevelDomain == "") then
[ machine ]
else
[ "${machine}.${config.clan.static-hosts.topLevelDomain}" ]
)
else
{ }
) filteredMachines
);
}

View File

@ -97,10 +97,10 @@ in
systemd.tmpfiles.rules = [
"d '/var/lib/sunshine' 0770 'user' 'users' - -"
"C '/var/lib/sunshine/sunshine.cert' 0644 'user' 'users' - ${
config.clanCore.facts.services.sunshine.secret."sunshine.cert".path or ""
config.clan.core.facts.services.sunshine.secret."sunshine.cert".path or ""
}"
"C '/var/lib/sunshine/sunshine.key' 0644 'user' 'users' - ${
config.clanCore.facts.services.sunshine.secret."sunshine.key".path or ""
config.clan.core.facts.services.sunshine.secret."sunshine.key".path or ""
}"
];
@ -117,8 +117,8 @@ in
RestartSec = "5s";
ReadWritePaths = [ "/var/lib/sunshine" ];
ReadOnlyPaths = [
(config.clanCore.facts.services.sunshine.secret."sunshine.key".path or "")
(config.clanCore.facts.services.sunshine.secret."sunshine.cert".path or "")
(config.clan.core.facts.services.sunshine.secret."sunshine.key".path or "")
(config.clan.core.facts.services.sunshine.secret."sunshine.cert".path or "")
];
};
wantedBy = [ "graphical-session.target" ];
@ -137,7 +137,7 @@ in
startLimitIntervalSec = 500;
script = ''
${ms-accept}/bin/moonlight-sunshine-accept sunshine init-state --uuid ${
config.clanCore.facts.services.sunshine.public.sunshine-uuid.value or null
config.clan.core.facts.services.sunshine.public.sunshine-uuid.value or null
} --state-file /var/lib/sunshine/state.json
'';
serviceConfig = {
@ -173,9 +173,9 @@ in
startLimitIntervalSec = 500;
script = ''
${ms-accept}/bin/moonlight-sunshine-accept sunshine listen --port ${builtins.toString listenPort} --uuid ${
config.clanCore.facts.services.sunshine.public.sunshine-uuid.value or null
config.clan.core.facts.services.sunshine.public.sunshine-uuid.value or null
} --state /var/lib/sunshine/state.json --cert '${
config.clanCore.facts.services.sunshine.public."sunshine.cert".value or null
config.clan.core.facts.services.sunshine.public."sunshine.cert".value or null
}'
'';
serviceConfig = {
@ -187,7 +187,7 @@ in
wantedBy = [ "graphical-session.target" ];
};
clanCore.facts.services.ergochat = {
clan.core.facts.services.ergochat = {
secret."sunshine.key" = { };
secret."sunshine.cert" = { };
public."sunshine-uuid" = { };

View File

@ -0,0 +1,2 @@
Statically configure syncthing peers through clan
---

View File

@ -0,0 +1,108 @@
{
lib,
config,
pkgs,
...
}:
let
clanDir = config.clan.core.clanDir;
machineDir = clanDir + "/machines/";
syncthingPublicKeyPath = machines: machineDir + machines + "/facts/syncthing.pub";
machinesFileSet = builtins.readDir machineDir;
machines = lib.mapAttrsToList (name: _: name) machinesFileSet;
syncthingPublicKeysUnchecked = builtins.map (
machine:
let
fullPath = syncthingPublicKeyPath machine;
in
if builtins.pathExists fullPath then machine else null
) machines;
syncthingPublicKeyMachines = lib.filter (machine: machine != null) syncthingPublicKeysUnchecked;
zerotierIpMachinePath = machines: machineDir + machines + "/facts/zerotier-ip";
networkIpsUnchecked = builtins.map (
machine:
let
fullPath = zerotierIpMachinePath machine;
in
if builtins.pathExists fullPath then machine else null
) machines;
networkIpMachines = lib.filter (machine: machine != null) networkIpsUnchecked;
devices = builtins.map (machine: {
name = machine;
value = {
name = machine;
id = (lib.removeSuffix "\n" (builtins.readFile (syncthingPublicKeyPath machine)));
addresses =
[ "dynamic" ]
++ (
if (lib.elem machine networkIpMachines) then
[ "tcp://[${(lib.removeSuffix "\n" (builtins.readFile (zerotierIpMachinePath machine)))}]:22000" ]
else
[ ]
);
};
}) syncthingPublicKeyMachines;
in
{
options.clan.syncthing-static-peers = {
excludeMachines = lib.mkOption {
type = lib.types.listOf lib.types.str;
example = [ config.clan.core.machineName ];
default = [ ];
description = ''
Machines that should not be added.
'';
};
};
config.services.syncthing.settings.devices = (builtins.listToAttrs devices);
imports = [
{
# Syncthing ports: 8384 for remote access to GUI
# 22000 TCP and/or UDP for sync traffic
# 21027/UDP for discovery
# source: https://docs.syncthing.net/users/firewall.html
networking.firewall.interfaces."zt+".allowedTCPPorts = [
8384
22000
];
networking.firewall.allowedTCPPorts = [ 8384 ];
networking.firewall.interfaces."zt+".allowedUDPPorts = [
22000
21027
];
# Activates inotify compatibility on syncthing
# use mkOverride 900 here as it otherwise would collide with the default of the
# upstream nixos xserver.nix
boot.kernel.sysctl."fs.inotify.max_user_watches" = lib.mkOverride 900 524288;
services.syncthing = {
enable = true;
configDir = "/var/lib/syncthing";
group = "syncthing";
key = lib.mkDefault config.clan.core.facts.services.syncthing.secret."syncthing.key".path or null;
cert = lib.mkDefault config.clan.core.facts.services.syncthing.secret."syncthing.cert".path or null;
};
clan.core.facts.services.syncthing = {
secret."syncthing.key" = { };
secret."syncthing.cert" = { };
public."syncthing.pub" = { };
generator.path = [
pkgs.coreutils
pkgs.gnugrep
pkgs.syncthing
];
generator.script = ''
syncthing generate --config "$secrets"
mv "$secrets"/key.pem "$secrets"/syncthing.key
mv "$secrets"/cert.pem "$secrets"/syncthing.cert
cat "$secrets"/config.xml | grep -oP '(?<=<device id=")[^"]+' | uniq > "$facts"/syncthing.pub
'';
};
}
];
}

View File

@ -9,8 +9,8 @@
id = lib.mkOption {
type = lib.types.nullOr lib.types.str;
example = "BABNJY4-G2ICDLF-QQEG7DD-N3OBNGF-BCCOFK6-MV3K7QJ-2WUZHXS-7DTW4AS";
default = config.clanCore.facts.services.syncthing.public."syncthing.pub".value or null;
defaultText = "config.clanCore.facts.services.syncthing.public.\"syncthing.pub\".value";
default = config.clan.core.facts.services.syncthing.public."syncthing.pub".value or null;
defaultText = "config.clan.core.facts.services.syncthing.public.\"syncthing.pub\".value";
};
introducer = lib.mkOption {
description = ''
@ -119,7 +119,7 @@
getPendingDevices = "/rest/cluster/pending/devices";
postNewDevice = "/rest/config/devices";
SharedFolderById = "/rest/config/folders/";
apiKey = config.clanCore.facts.services.syncthing.secret."syncthing.api".path or null;
apiKey = config.clan.core.facts.services.syncthing.secret."syncthing.api".path or null;
in
lib.mkIf config.clan.syncthing.autoAcceptDevices {
description = "Syncthing auto accept devices";
@ -161,7 +161,7 @@
systemd.services.syncthing-init-api-key =
let
apiKey = config.clanCore.facts.services.syncthing.secret."syncthing.api".path or null;
apiKey = config.clan.core.facts.services.syncthing.secret."syncthing.api".path or null;
in
lib.mkIf config.clan.syncthing.autoAcceptDevices {
description = "Set the api key";
@ -183,7 +183,7 @@
};
};
clanCore.facts.services.syncthing = {
clan.core.facts.services.syncthing = {
secret."syncthing.key" = { };
secret."syncthing.cert" = { };
secret."syncthing.api" = { };

View File

@ -11,5 +11,5 @@ _: {
};
};
clanCore.state.thelounde.folders = [ "/var/lib/thelounge" ];
clan.core.state.thelounde.folders = [ "/var/lib/thelounge" ];
}

View File

@ -0,0 +1,2 @@
This module sets the `clan.lol` and `nix-community` cache up as a trusted cache.
----

View File

@ -0,0 +1,10 @@
{
nix.settings.trusted-substituters = [
"https://cache.clan.lol"
"https://nix-community.cachix.org"
];
nix.settings.trusted-public-keys = [
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
"cache.clan.lol-1:3KztgSAB5R1M+Dz7vzkBGzXdodizbgLXGXKXlcQLA28="
];
}

View File

@ -22,9 +22,9 @@
config = {
users.mutableUsers = false;
users.users.${config.clan.user-password.user}.hashedPasswordFile =
config.clanCore.facts.services.user-password.secret.user-password-hash.path;
sops.secrets."${config.clanCore.machineName}-user-password-hash".neededForUsers = true;
clanCore.facts.services.user-password = {
config.clan.core.facts.services.user-password.secret.user-password-hash.path;
sops.secrets."${config.clan.core.machineName}-user-password-hash".neededForUsers = true;
clan.core.facts.services.user-password = {
secret.user-password = { };
secret.user-password-hash = { };
generator.prompt = (

View File

@ -6,7 +6,7 @@
...
}:
let
clanDir = config.clanCore.clanDir;
clanDir = config.clan.core.clanDir;
machineDir = clanDir + "/machines/";
machinesFileSet = builtins.readDir machineDir;
machines = lib.mapAttrsToList (name: _: name) machinesFileSet;
@ -20,7 +20,7 @@ let
if builtins.pathExists fullPath then builtins.readFile fullPath else null
) machines;
networkIds = lib.filter (machine: machine != null) networkIdsUnchecked;
networkId = builtins.elemAt networkIds 0;
networkId = if builtins.length networkIds == 0 then null else builtins.elemAt networkIds 0;
in
#TODO:trace on multiple found network-ids
#TODO:trace on no single found networkId
@ -28,28 +28,33 @@ in
options.clan.zerotier-static-peers = {
excludeHosts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ config.clanCore.machineName ];
default = [ config.clan.core.machineName ];
description = "Hosts that should be excluded";
};
};
config.systemd.services.zerotier-static-peers-autoaccept =
let
machines = builtins.readDir machineDir;
zerotierIpMachinePath = machines: machineDir + machines + "/facts/zerotier-ip";
filteredMachines = lib.filterAttrs (
name: _: !(lib.elem name config.clan.static-hosts.excludeHosts)
networkIpsUnchecked = builtins.map (
machine:
let
fullPath = zerotierIpMachinePath machine;
in
if builtins.pathExists fullPath then machine else null
) machines;
networkIps = lib.filter (machine: machine != null) networkIpsUnchecked;
machinesWithIp = lib.filterAttrs (name: _: (lib.elem name networkIps)) machinesFileSet;
filteredMachines = lib.filterAttrs (
name: _: !(lib.elem name config.clan.zerotier-static-peers.excludeHosts)
) machinesWithIp;
hosts = lib.mapAttrsToList (host: _: host) (
lib.mapAttrs' (
machine: _:
let
fullPath = zerotierIpMachinePath machine;
in
if builtins.pathExists fullPath then
lib.nameValuePair (builtins.readFile fullPath) [ machine ]
else
null
lib.nameValuePair (builtins.readFile fullPath) [ machine ]
) filteredMachines
);
in

View File

@ -1,3 +1,4 @@
{ ... }:
{
perSystem =
{
@ -26,7 +27,8 @@
packages = [
select-shell
pkgs.tea
pkgs.nix
# Better error messages than nix 2.18
pkgs.nixVersions.latest
self'.packages.tea-create-pr
self'.packages.merge-after-ci
self'.packages.pending-reviews
@ -34,9 +36,6 @@
config.treefmt.build.wrapper
];
shellHook = ''
# no longer used
rm -f "$(git rev-parse --show-toplevel)/.git/hooks/pre-commit"
echo -e "${ansiEscapes.green}switch to another dev-shell using: select-shell${ansiEscapes.reset}"
'';
};

4
docs/.gitignore vendored
View File

@ -1 +1,3 @@
/site/reference
/site/reference
/site/static/Roboto-Regular.ttf
/site/static/FiraCode-VF.ttf

View File

@ -15,92 +15,124 @@ Let's get your development environment up and running:
1. **Install Nix Package Manager**:
- You can install the Nix package manager by either [downloading the Nix installer](https://github.com/DeterminateSystems/nix-installer/releases) or running this command:
```bash
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
```
- You can install the Nix package manager by either [downloading the Nix installer](https://github.com/DeterminateSystems/nix-installer/releases) or running this command:
```bash
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
```
2. **Install direnv**:
- Download the direnv package from [here](https://direnv.net/docs/installation.html) or run the following command:
```bash
curl -sfL https://direnv.net/install.sh | bash
```
- To automatically setup a devshell on entering the directory
```bash
nix profile install nixpkgs#nix-direnv-flakes
```
3. **Add direnv to your shell**:
- Direnv needs to [hook into your shell](https://direnv.net/docs/hook.html) to work.
You can do this by executing following command. The example below will setup direnv for `zsh` and `bash`
- Direnv needs to [hook into your shell](https://direnv.net/docs/hook.html) to work.
You can do this by executing following command. The example below will setup direnv for `zsh` and `bash`
```bash
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc && echo 'eval "$(direnv hook bash)"' >> ~/.bashrc && eval "$SHELL"
```
4. **Clone the Repository and Navigate**:
- Clone this repository and navigate to it.
5. **Allow .envrc**:
- When you enter the directory, you'll receive an error message like this:
```bash
direnv: error .envrc is blocked. Run `direnv allow` to approve its content
```
- Execute `direnv allow` to automatically execute the shell script `.envrc` when entering the directory.
# Setting Up Your Git Workflow
Let's set up your Git workflow to collaborate effectively:
1. **Register Your Gitea Account Locally**:
- Execute the following command to add your Gitea account locally:
```bash
tea login add
```
- Fill out the prompt as follows:
- URL of Gitea instance: `https://git.clan.lol`
- Name of new Login [gitea.gchq.icu]: `gitea.gchq.icu:7171`
- Do you have an access token? No
- Username: YourUsername
- Password: YourPassword
- Set Optional settings: No
2. **Git Workflow**:
1. Add your changes to Git using `git add <file1> <file2>`.
2. Run `nix fmt` to lint your files.
3. Commit your changes with a descriptive message: `git commit -a -m "My descriptive commit message"`.
4. Make sure your branch has the latest changes from upstream by executing:
```bash
git fetch && git rebase origin/main --autostash
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc && echo 'eval "$(direnv hook bash)"' >> ~/.bashrc && eval "$SHELL"
```
5. Use `git status` to check for merge conflicts.
6. If conflicts exist, resolve them. Here's a tutorial for resolving conflicts in [VSCode](https://code.visualstudio.com/docs/sourcecontrol/overview#_merge-conflicts).
7. After resolving conflicts, execute `git merge --continue` and repeat step 5 until there are no conflicts.
3. **Create a Pull Request**:
4. **Create a Gitea Account**:
- Register an account on https://git.clan.lol
- Fork the [clan-core](https://git.clan.lol/clan/clan-core) repository
- Clone the repository and navigate to it
- Add a new remote called upstream:
```bash
git remote add upstream gitea@git.clan.lol:clan/clan-core.git
```
- To automatically open a pull request that gets merged if all tests pass, execute:
```bash
merge-after-ci
```
5. **Register Your Gitea Account Locally**:
4. **Review Your Pull Request**:
- Execute the following command to add your Gitea account locally:
```bash
tea login add
```
- Fill out the prompt as follows:
- URL of Gitea instance: `https://git.clan.lol`
- Name of new Login [git.clan.lol]:
- Do you have an access token? No
- Username: YourUsername
- Password: YourPassword
- Set Optional settings: No
- Visit https://git.clan.lol and go to the project page. Check under "Pull Requests" for any issues with your pull request.
5. **Push Your Changes**:
- If there are issues, fix them and redo step 2. Afterward, execute:
```bash
git push origin HEAD:YourUsername-main
```
- This will directly push to your open pull request.
6. **Allow .envrc**:
- When you enter the directory, you'll receive an error message like this:
```bash
direnv: error .envrc is blocked. Run `direnv allow` to approve its content
```
- Execute `direnv allow` to automatically execute the shell script `.envrc` when entering the directory.
7. **(Optional) Install Git Hooks**:
- To syntax check your code you can run:
```bash
nix fmt
```
- To make this automatic install the git hooks
```bash
./scripts/pre-commit
```
8. **Open a Pull Request**:
- To automatically open up a pull request you can use our tool called:
```
merge-after-ci --reviewers Mic92 Lassulus Qubasa
```
# Debugging
Here are some methods for debugging and testing the clan-cli:
## See all possible packages and tests
To quickly show all possible packages and tests execute:
```bash
nix flake show --system no-eval
```
Under `checks` you will find all tests that are executed in our CI. Under `packages` you find all our projects.
```
git+file:///home/lhebendanz/Projects/clan-core
├───apps
│ └───x86_64-linux
│ ├───install-vm: app
│ └───install-vm-nogui: app
├───checks
│ └───x86_64-linux
│ ├───borgbackup omitted (use '--all-systems' to show)
│ ├───check-for-breakpoints omitted (use '--all-systems' to show)
│ ├───clan-dep-age omitted (use '--all-systems' to show)
│ ├───clan-dep-bash omitted (use '--all-systems' to show)
│ ├───clan-dep-e2fsprogs omitted (use '--all-systems' to show)
│ ├───clan-dep-fakeroot omitted (use '--all-systems' to show)
│ ├───clan-dep-git omitted (use '--all-systems' to show)
│ ├───clan-dep-nix omitted (use '--all-systems' to show)
│ ├───clan-dep-openssh omitted (use '--all-systems' to show)
│ ├───"clan-dep-python3.11-mypy" omitted (use '--all-systems' to show)
├───packages
│ └───x86_64-linux
│ ├───clan-cli omitted (use '--all-systems' to show)
│ ├───clan-cli-docs omitted (use '--all-systems' to show)
│ ├───clan-ts-api omitted (use '--all-systems' to show)
│ ├───clan-app omitted (use '--all-systems' to show)
│ ├───default omitted (use '--all-systems' to show)
│ ├───deploy-docs omitted (use '--all-systems' to show)
│ ├───docs omitted (use '--all-systems' to show)
│ ├───editor omitted (use '--all-systems' to show)
└───templates
├───default: template: Initialize a new clan flake
└───new-clan: template: Initialize a new clan flake
```
You can execute every test separately by following the tree path `nix build .#checks.x86_64-linux.clan-pytest` for example.
## Test Locally in Devshell with Breakpoints
To test the cli locally in a development environment and set breakpoints for debugging, follow these steps:
@ -150,12 +182,14 @@ If you need to inspect the Nix sandbox while running tests, follow these steps:
2. Use `cntr` and `psgrep` to attach to the Nix sandbox. This allows you to interactively debug your code while it's paused. For example:
```bash
cntr exec -w your_sandbox_name
psgrep -a -x your_python_process_name
cntr attach <container id, container name or process id>
```
Or you can also use the [nix breakpoint hook](https://nixos.org/manual/nixpkgs/stable/#breakpointhook)
# Standards
Every new module name should be in kebab-case.
Every fact definition, where possible should be in kebab-case.
- Every new module name should be in kebab-case.
- Every fact definition, where possible should be in kebab-case.

View File

@ -20,11 +20,11 @@ There are several reasons for choosing to self-host. These can include:
Alice wants to self-host a mumble server for her family.
- She visits to the cLAN website, and follows the instructions on how to install cLAN-OS on her server.
- Alice logs into a terminal on her server via SSH (alternatively uses cLAN GUI app)
- Using the cLAN CLI or GUI tool, alice creates a new private network for her family (VPN)
- Alice now browses a list of curated cLAN modules and finds a module for mumble.
- She adds this module to her network using the cLAN tool.
- She visits to the Clan website, and follows the instructions on how to install Clan-OS on her server.
- Alice logs into a terminal on her server via SSH (alternatively uses Clan GUI app)
- Using the Clan CLI or GUI tool, alice creates a new private network for her family (VPN)
- Alice now browses a list of curated Clan modules and finds a module for mumble.
- She adds this module to her network using the Clan tool.
- After that, she uses the clan tool to invite her family members to her network
- Other family members join the private network via the invitation.
- By accepting the invitation, other members automatically install all required software to interact with the network on their machine.
@ -33,7 +33,7 @@ Alice wants to self-host a mumble server for her family.
Alice wants to add a photos app to her private network
- She uses the clan CLI or GUI tool to manage her existing private cLAN family network
- She uses the clan CLI or GUI tool to manage her existing private Clan family network
- She discovers a module for photoprism, and adds it to her server using the tool
- Other members who are already part of her network, will receive a notification that an update is required to their environment
- After accepting, all new software and services to interact with the new photoprism service will be installed automatically.

View File

@ -1,4 +1,4 @@
# Joining a cLAN network
# Joining a Clan network
## General Description
@ -8,13 +8,13 @@ Joining a self-hosted infrastructure involves connecting to a network, server, o
### Story 1: Joining a private network
Alice' son Bob has never heard of cLAN, but receives an invitation URL from Alice who already set up private cLAN network for her family.
Alice' son Bob has never heard of Clan, but receives an invitation URL from Alice who already set up private Clan network for her family.
Bob opens the invitation link and lands on the cLAN website. He quickly learns about what cLAN is and can see that the invitation is for a private network of his family that hosts a number of services, like a private voice chat and a photo sharing platform.
Bob opens the invitation link and lands on the Clan website. He quickly learns about what Clan is and can see that the invitation is for a private network of his family that hosts a number of services, like a private voice chat and a photo sharing platform.
Bob decides to join the network and follows the instructions to install the cLAN tool on his computer.
Bob decides to join the network and follows the instructions to install the Clan tool on his computer.
Feeding the invitation link to the cLAN tool, bob registers his machine with the network.
Feeding the invitation link to the Clan tool, bob registers his machine with the network.
All programs required to interact with the network will be installed and configured automatically and securely.
@ -22,7 +22,7 @@ Optionally, bob can customize the configuration of these programs through a simp
### Story 2: Receiving breaking changes
The cLAN family network which Bob is part of received an update.
The Clan family network which Bob is part of received an update.
The existing photo sharing service has been removed and replaced with another alternative service. The new photo sharing service requires a different client app to view and upload photos.
@ -30,7 +30,7 @@ Bob accepts the update. Now his environment will be updated. The old client soft
Because Bob has customized the previous photo viewing app, he is notified that this customization is no longer valid, as the software has been removed (deprecation message).l
Optionally, Bob can now customize the new photo viewing software through his cLAN configuration app or via a config file.
Optionally, Bob can now customize the new photo viewing software through his Clan configuration app or via a config file.
## Challenges

View File

@ -1,10 +1,10 @@
# cLAN module maintaining
# Clan module maintaining
## General Description
cLAN modules are pieces of software that can be used by admins to build a private or public infrastructure.
Clan modules are pieces of software that can be used by admins to build a private or public infrastructure.
cLAN modules should have the following properties:
Clan modules should have the following properties:
1. Documented: It should be clear what the module does and how to use it.
1. Self contained: A module should be usable as is. If it requires any other software or settings, those should be delivered with the module itself.

View File

@ -16,15 +16,26 @@ def define_env(env: Any) -> None:
@env.macro
def asciinema(name: str) -> str:
return f"""<div id="{name}">
<script src="{asciinema_dir}/asciinema-player.min.js"></script>
<script>
AsciinemaPlayer.create('{video_dir + name}',
document.getElementById("{name}"), {{
loop: true,
autoPlay: true,
controls: false,
speed: 1.5,
theme: "solarized-light"
}});
// Function to load the script and then create the Asciinema player
function loadAsciinemaPlayer() {{
var script = document.createElement('script');
script.src = "{asciinema_dir}/asciinema-player.min.js";
script.onload = function() {{
AsciinemaPlayer.create('{video_dir + name}', document.getElementById("{name}"), {{
loop: true,
autoPlay: true,
controls: false,
speed: 1.5,
theme: "solarized-light"
}});
}};
document.head.appendChild(script);
}}
// Load the Asciinema player script
loadAsciinemaPlayer();
</script>
<link rel="stylesheet" type="text/css" href="{asciinema_dir}/asciinema-player.css" />
</div>"""

View File

@ -1,4 +1,4 @@
site_name: Clan Docs
site_name: Clan Documentation
site_url: https://docs.clan.lol
repo_url: https://git.clan.lol/clan/clan-core/
repo_name: clan-core
@ -28,6 +28,7 @@ markdown_extensions:
- pymdownx.highlight:
use_pygments: true
anchor_linenums: true
- pymdownx.keys
- toc:
title: On this page
@ -38,7 +39,7 @@ exclude_docs: |
nav:
- Blog:
- blog/index.md
- blog/index.md
- Getting started:
- index.md
- Installer: getting-started/installer.md
@ -50,6 +51,7 @@ nav:
- Flake-parts: getting-started/flake-parts.md
- Modules:
- Clan Modules:
- reference/clanModules/borgbackup-static.md
- reference/clanModules/borgbackup.md
- reference/clanModules/deltachat.md
- reference/clanModules/disk-layouts.md
@ -58,12 +60,15 @@ nav:
- reference/clanModules/localsend.md
- reference/clanModules/matrix-synapse.md
- reference/clanModules/moonlight.md
- reference/clanModules/postgresql.md
- reference/clanModules/root-password.md
- reference/clanModules/sshd.md
- reference/clanModules/sunshine.md
- reference/clanModules/syncthing.md
- reference/clanModules/static-hosts.md
- reference/clanModules/sunshine.md
- reference/clanModules/syncthing-static-peers.md
- reference/clanModules/syncthing.md
- reference/clanModules/thelounge.md
- reference/clanModules/trusted-nix-caches.md
- reference/clanModules/user-password.md
- reference/clanModules/xfce.md
- reference/clanModules/zerotier-static-peers.md
@ -78,6 +83,7 @@ nav:
- reference/cli/history.md
- reference/cli/machines.md
- reference/cli/secrets.md
- reference/cli/show.md
- reference/cli/ssh.md
- reference/cli/vms.md
- Clan Core:
@ -92,8 +98,9 @@ docs_dir: site
site_dir: out
theme:
logo: static/clan-white.png
favicon: static/clan-dark.png
font: false
logo: https://clan.lol/static/logo/clan-white.png
favicon: https://clan.lol/static/dark-favicon/128x128.png
name: material
features:
- navigation.instant
@ -102,7 +109,8 @@ theme:
- content.code.copy
- content.tabs.link
icon:
repo: fontawesome/brands/git
repo: fontawesome/brands/git-alt
custom_dir: overrides
palette:
# Palette toggle for light mode
@ -124,8 +132,7 @@ theme:
name: Switch to light mode
extra_css:
- static/asciinema-player/custom-theme.css
- static/asciinema-player/asciinema-player.css
- static/extra.css
extra:
social:
@ -138,7 +145,6 @@ extra:
- icon: fontawesome/solid/rss
link: /feed_rss_created.xml
plugins:
- search
- blog

View File

@ -2,6 +2,10 @@
pkgs,
module-docs,
clan-cli-docs,
asciinema-player-js,
asciinema-player-css,
roboto,
fira-code,
...
}:
let
@ -27,6 +31,14 @@ pkgs.stdenv.mkDerivation {
mkdir -p ./site/reference/cli
cp -af ${module-docs}/* ./site/reference/
cp -af ${clan-cli-docs}/* ./site/reference/cli/
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/
'';
buildPhase = ''

View File

@ -40,8 +40,17 @@
mypy --strict $out
'';
asciinema-player-js = pkgs.fetchurl {
url = "https://github.com/asciinema/asciinema-player/releases/download/v3.7.0/asciinema-player.min.js";
sha256 = "sha256-Ymco/+FinDr5YOrV72ehclpp4amrczjo5EU3jfr/zxs=";
};
asciinema-player-css = pkgs.fetchurl {
url = "https://github.com/asciinema/asciinema-player/releases/download/v3.7.0/asciinema-player.css";
sha256 = "sha256-GZMeZFFGvP5GMqqh516mjJKfQaiJ6bL38bSYOXkaohc=";
};
module-docs = pkgs.runCommand "rendered" { nativeBuildInputs = [ pkgs.python3 ]; } ''
export CLAN_CORE=${jsonDocs.clanCore}/share/doc/nixos/options.json
export CLAN_CORE=${jsonDocs.clanCore}/share/doc/nixos/options.json
# A file that contains the links to all clanModule docs
export CLAN_MODULES=${clanModulesFileInfo}
export CLAN_MODULES_READMES=${clanModulesReadmes}
@ -56,12 +65,16 @@
devShells.docs = pkgs.callPackage ./shell.nix {
inherit (self'.packages) docs clan-cli-docs;
inherit module-docs;
inherit asciinema-player-js;
inherit asciinema-player-css;
};
packages = {
docs = pkgs.python3.pkgs.callPackage ./default.nix {
inherit (self'.packages) clan-cli-docs;
inherit (inputs) nixpkgs;
inherit module-docs;
inherit asciinema-player-js;
inherit asciinema-player-css;
};
deploy-docs = pkgs.callPackage ./deploy-docs.nix { inherit (config.packages) docs; };
inherit module-docs;

View File

@ -13,7 +13,7 @@ let
clanCoreNixosModules = [
clanCore
{ clanCore.clanDir = ./.; }
{ clan.core.clanDir = ./.; }
] ++ allNixosModules;
# TODO: optimally we would not have to evaluate all nixos modules for every page
@ -25,6 +25,8 @@ let
# improves eval performance slightly (10%)
getOptions = modules: (clanCoreNixos.extendModules { inherit modules; }).options;
getOptionsWithoutCore = modules: builtins.removeAttrs (getOptions modules) [ "core" ];
evalDocs =
options:
pkgs.nixosOptionsDoc {
@ -34,7 +36,7 @@ let
# clanModules docs
clanModulesDocs = builtins.mapAttrs (
name: module: (evalDocs ((getOptions [ module ]).clan.${name} or { })).optionsJSON
name: module: (evalDocs ((getOptionsWithoutCore [ module ]).clan.${name} or { })).optionsJSON
) clanModules;
clanModulesReadmes = builtins.mapAttrs (
@ -42,7 +44,7 @@ let
) clanModules;
# clanCore docs
clanCoreDocs = (evalDocs (getOptions [ ]).clanCore).optionsJSON;
clanCoreDocs = (evalDocs (getOptions [ ]).clan.core).optionsJSON;
in
{
inherit clanModulesReadmes;

View File

@ -40,13 +40,14 @@ def sanitize(text: str) -> str:
return text.replace(">", "\\>")
def replace_store_path(text: str) -> Path:
def replace_store_path(text: str) -> tuple[str, str]:
res = text
if text.startswith("/nix/store/"):
res = "https://git.clan.lol/clan/clan-core/src/branch/main/" + str(
Path(*Path(text).parts[4:])
)
return Path(res)
name = Path(res).name
return (res, name)
def render_option_header(name: str) -> str:
@ -108,9 +109,10 @@ def render_option(name: str, option: dict[str, Any], level: int = 3) -> str:
"""
decls = option.get("declarations", [])
source_path = replace_store_path(decls[0])
source_path, name = replace_store_path(decls[0])
print(source_path, name)
res += f"""
:simple-git: [{source_path.name}]({source_path})
:simple-git: [{name}]({source_path})
"""
res += "\n"
@ -135,7 +137,7 @@ To use this module, import it like this:
"""
clan_core_descr = """ClanCore delivers all the essential features for every clan.
clan_core_descr = """ClanCore delivers all the essential features for every clan.
It's always included in your setup, and you can customize your clan's behavior with the configuration [options](#module-options) provided below.
"""
@ -160,8 +162,8 @@ def produce_clan_core_docs() -> None:
for option_name, info in options.items():
outfile = f"{module_name}/index.md"
# Create seperate files for nested options
if len(option_name.split(".")) <= 2:
# Create separate files for nested options
if len(option_name.split(".")) <= 3:
# i.e. clan-core.clanDir
output = core_outputs.get(
outfile,
@ -172,7 +174,7 @@ def produce_clan_core_docs() -> None:
core_outputs[outfile] = output
else:
# Clan sub-options
[_, sub] = option_name.split(".")[0:2]
[_, sub] = option_name.split(".")[1:3]
outfile = f"{module_name}/{sub}.md"
# Get the content or write the header
output = core_outputs.get(outfile, render_option_header(sub))

View File

@ -3,6 +3,10 @@
pkgs,
module-docs,
clan-cli-docs,
asciinema-player-js,
asciinema-player-css,
roboto,
fira-code,
...
}:
pkgs.mkShell {
@ -14,5 +18,14 @@ pkgs.mkShell {
chmod +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/
'';
}

12
docs/overrides/main.html Normal file
View File

@ -0,0 +1,12 @@
{% extends "base.html" %}
{% block extrahead %}
<meta property="og:title" content="Clan - Documentation, Blog & Getting Started Guide" />
<meta property="og:description" content="Documentation for Clan. The peer-to-peer machine deployment framework." />
<meta property="og:image" content="https://clan.lol/static/dark-favicon/128x128.png" />
<meta property="og:url" content="https://docs.clan.lol" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="Clan" />
<meta property="og:locale" content="en_US" />
{% endblock %}

View File

@ -1,21 +1,26 @@
authors:
DavHau:
name: "DavHau"
description: "Core Developer"
avatar: "https://clan.lol/static/profiles/davhau.jpg"
url: "https://DavHau.com"
Lassulus:
name: "Lassulus"
description: "Contributor to Clan"
avatar: "https://avatars.githubusercontent.com/u/621759?v=4"
description: "Core Developer"
avatar: "https://clan.lol/static/profiles/lassulus.jpg"
url: "https://http://lassul.us/"
Mic92:
name: "Mic92"
description: "Contributor to Clan"
avatar: "https://avatars.githubusercontent.com/u/96200?v=4"
description: "Core Developer"
avatar: "https://clan.lol/static/profiles/mic92.jpg"
url: "https://thalheim.io"
W:
name: "W"
description: "Founder of Clan"
avatar: "/static/w_profile.webp"
avatar: "https://clan.lol/static/profiles/w_profile.webp"
url: ""
Qubasa:
name: "Qubasa"
description: "Contributor to Clan"
avatar: "https://avatars.githubusercontent.com/u/22085373?v=4"
url: "https://github.com/Qubasa"
description: "Core Developer"
avatar: "https://clan.lol/static/profiles/qubasa.png"
url: "https://github.com/Qubasa"

View File

@ -61,7 +61,7 @@ Clan is for anyone and everyone who believes in the power of open source technol
Ready to control your digital world? Clan is more than a tool—it's a movement. Secure your data, manage your systems easily, or connect with others how you like. Start with Clan for a better digital future.
Connect with us on our [Matrix channel at clan.lol](https://matrix.to/#/#clan:lassul.us) or through our IRC bridges (coming soon).
Connect with us on our [Matrix channel at clan.lol](https://matrix.to/#/#clan:clan.lol) or through our IRC bridges (coming soon).
Want to see the code? Check it out [on our Gitea](https://git.clan.lol/clan/clan-core) or [on GitHub](https://github.com/clan-lol/clan-core).

View File

@ -0,0 +1,194 @@
---
title: "Dev Report: Introducing the NixOS to JSON Schema Converter"
description: "Discover our new library designed to extract JSON schema interfaces from NixOS modules, streamlining frontend development"
authors:
- DavHau
date: 2024-05-25
slug: jsonschema-converter
---
## Overview
Weve developed a new library designed to extract interfaces from NixOS modules and convert them into JSON schemas, paving the way for effortless GUI generation. This blog post outlines the motivations behind this development, demonstrates the capabilities of the library, and guides you through leveraging it to create GUIs seamlessly.
## Motivation
In recent months, our team has been exploring various graphical user interfaces (GUIs) to streamline NixOS machine configuration. While our opinionated Clan modules simplify NixOS configurations, there's a need to configure these modules from diverse frontends, such as:
- Command-line interfaces (CLIs)
- Web-based UIs
- Desktop applications
- Mobile applications
- Large Language Models (LLMs)
Given this need, a universal format like JSON is a natural choice. It is already possible as of now, to import json based NixOS configurations, as illustrated below:
`configuration.json`:
```json
{ "networking": { "hostName": "my-machine" } }
```
This configuration can be then imported inside a classic NixOS config:
```nix
{config, lib, pkgs, ...}: {
imports = [
(lib.importJSON ./configuration.json)
];
}
```
This straightforward approach allows us to build a frontend that generates JSON, enabling the configuration of NixOS machines. But, two critical questions arise:
1. How does the frontend learn about existing configuration options?
2. How can it verify user input without running Nix?
Introducing [JSON schema](https://json-schema.org/), a widely supported standard that defines interfaces in JSON and validates input against them.
Example schema for `networking.hostName`:
```json
{
"type": "object",
"properties": {
"networking": {
"type": "object",
"properties": {
"hostName": {
"type": "string",
"pattern": "^$|^[a-z0-9]([a-z0-9_-]{0,61}[a-z0-9])?$"
}
}
}
}
}
```
## Client-Side Input Validation
Validating input against JSON schemas is both efficient and well-supported across numerous programming languages. Using JSON schema validators, you can accurately check configurations like our `configuration.json`.
Validation example:
```shell
$ nix-shell -p check-jsonschema
$ jsonschema -o pretty ./schema.json -i ./configuration.json
===[SUCCESS]===(./configuration.json)===
```
In case of invalid input, schema validators provide explicit error messages:
```shell
$ echo '{ "networking": { "hostName": "my/machine" } }' > configuration.json
$ jsonschema -o pretty ./schema.json -i ./configuration.json
===[ValidationError]===(./configuration.json)===
'my/machine' does not match '^$|^[a-z0-9]([a-z0-9_-]{0,61}[a-z0-9])?$'
Failed validating 'pattern' in schema['properties']['networking']['properties']['hostName']:
{'pattern': '^$|^[a-z0-9]([a-z0-9_-]{0,61}[a-z0-9])?$',
'type': 'string'}
On instance['networking']['hostName']:
'my/machine'
```
## Automatic GUI Generation
Certain libraries facilitate straightforward GUI generation from JSON schemas. For instance, the [react-jsonschema-form playground](https://rjsf-team.github.io/react-jsonschema-form/) auto-generates a form for any given schema.
## NixOS Module to JSON Schema Converter
To enable the development of responsive frontends, our library allows the extraction of interfaces from NixOS modules to JSON schemas. Open-sourced for community collaboration, this library supports building sophisticated user interfaces for NixOS.
Heres a preview of our library's functions exposed through the [clan-core](https://git.clan.lol/clan/clan-core) flake:
- `lib.jsonschema.parseModule` - Generates a schema for a NixOS module.
- `lib.jsonschema.parseOption` - Generates a schema for a single NixOS option.
- `lib.jsonschema.parseOptions` - Generates a schema from an attrset of NixOS options.
Example:
`module.nix`:
```nix
{lib, config, pkgs, ...}: {
# a simple service with two options
options.services.example-web-service = {
enable = lib.mkEnableOption "Example web service";
port = lib.mkOption {
type = lib.types.int;
description = "Port used to serve the content";
};
};
}
```
Converted, using the `parseModule` function:
```shell
$ cd clan-core
$ nix eval --json --impure --expr \
'(import ./lib/jsonschema {}).parseModule ./module.nix' | jq | head
{
"properties": {
"services": {
"properties": {
"example-web-service": {
"properties": {
"enable": {
"default": false,
"description": "Whether to enable Example web service.",
"examples": [
...
```
This utility can also generate interfaces for existing NixOS modules or options.
## GUI for NGINX in Under a Minute
Creating a prototype GUI for the NGINX module using our library and [react-jsonschema-form playground](https://rjsf-team.github.io/react-jsonschema-form/) can be done quickly:
1. Export all NGINX options into a JSON schema using a Nix expression:
```nix
# export.nix
let
pkgs = import <nixpkgs> {};
clan-core = builtins.getFlake "git+https://git.clan.lol/clan/clan-core";
options = (pkgs.nixos {}).options.services.nginx;
in
clan-core.lib.jsonschema.parseOption options
```
2. Write the schema into a file:
```shell
$ nix eval --json -f ./export.nix | jq > nginx.json
```
3. Open the [react-jsonschema-form playground](https://rjsf-team.github.io/react-jsonschema-form/), select `Blank` and paste the `nginx.json` contents.
This provides a quick look at a potential GUI (screenshot is cropped).
![Image title](https://clan.lol/static/blog-post-jsonschema/nginx-gui.jpg)
## Limitations
### Laziness
JSON schema mandates the declaration of all required fields upfront, which might be configured implicitly or remain unused. For instance, `services.nginx.virtualHosts.<name>.sslCertificate` must be specified even if SSL isnt enabled.
### Limited Types
Certain NixOS module types, like `types.functionTo` and `types.package`, do not map straightforwardly to JSON. For full compatibility, adjustments to NixOS modules might be necessary, such as substituting `listOf package` with `listOf str`.
### Parsing NixOS Modules
Currently, our converter relies on the `options` attribute of evaluated NixOS modules, extracting information from the `type.name` attribute, which is suboptimal. Enhanced introspection capabilities within the NixOS module system would be beneficial.
## Future Prospects
We hope these experiments inspire the community, encourage contributions and further development in this space. Share your ideas and contributions through our issue tracker or matrix channel!
## Links
- [Comments on NixOS Discourse](https://discourse.nixos.org/t/introducing-the-nixos-to-json-schema-converter/45948)
- [Source Code of the JSON Schema Library](https://git.clan.lol/clan/clan-core/src/branch/main/lib/jsonschema)
- [Our Issue Tracker](https://git.clan.lol/clan/clan-core/issues)
- [Our Matrix Channel](https://matrix.to/#/#clan:clan.lol)
- [react-jsonschema-form Playground](https://rjsf-team.github.io/react-jsonschema-form/)

View File

@ -10,4 +10,4 @@ Last week, we added a new documentation hub for clan at [docs.clan.lol](https://
We are still working on improving the installation procedures, so stay tuned.
We now have weekly office hours where people are invited to hangout and ask questions.
They are every Wednesday 15:30 UTC (17:30 CEST) in our [jitsi](https://jitsi.lassul.us/clan.lol).
Otherwise drop by in our [matrix channel](https://matrix.to/#/#clan:lassul.us).
Otherwise drop by in our [matrix channel](https://matrix.to/#/#clan:clan.lol).

View File

@ -0,0 +1,63 @@
---
title: "Git Based Machine Deployment with Clan-Core"
description: ""
authors:
- Qubasa
date: 2024-05-25
---
## Revolutionizing Server Management
In the world of server management, countless tools claim to offer seamless deployment of multiple machines. Yet, many fall short, leaving server admins and self-hosting enthusiasts grappling with complexity. Enter the Clan-Core Framework—a groundbreaking all in one solution designed to transform decentralized self-hosting into an effortless and scalable endeavor.
### The Power of Clan-Core
Imagine having the power to manage your servers with unparalleled ease, scaling your IT infrastructure like never before. Clan-Core empowers you to do just that. At its core, Clan-Core leverages a single Git repository to define everything about your machines. This central repository utilizes Nix or JSON files to specify configurations, including disk formatting, ensuring a streamlined and unified approach.
### Simplified Deployment Process
With Clan-Core, the cumbersome task of bootstrapping a specific ISO is a thing of the past. All you need is SSH access to your Linux server. Clan-Core allows you to overwrite any existing Linux distribution live over SSH, eliminating time-consuming setup processes. This capability means you can deploy updates or new configurations swiftly and efficiently, maximizing uptime and minimizing hassle.
### Secure and Efficient Secret Management
Security is paramount in server management, and Clan-Core takes it seriously. Passwords and other sensitive information are encrypted within the Git repository, automatically decrypted during deployment. This not only ensures the safety of your secrets but also simplifies their management. Clan-Core supports sharing secrets with other admins, fostering collaboration and maintaining reproducibillity and security without sacrificing convenience.
### Services as Apps
Setting up a service can be quite difficult. Many server adjustments need to be made, from setting up a database to adjusting webserver configurations and generating the correct private keys. However, Clan-Core aims to make setting up a service as easy as installing an application. Through Clan-Core's Module system, everything down to secrets can be automatically set up. This transforms the often daunting task of service setup into a smooth, automated process, making it accessible to all.
### Decentralized Mesh VPN
Building on these features is a self-configuring decentralized mesh VPN that interconnects all your machines into a private darknet. This ensures that sensitive services, which might have too much attack surface to be hosted on the public internet, can still be made available privately without the need to worry about potential system compromise. By creating a secure, private network, Clan-Core offers an additional layer of protection for your most critical services.
### Decentralized Domain Name System
Current DNS implementations are distributed but not truly decentralized. For Clan-Core, we implemented our own truly decentralized DNS module. This module uses simple flooding and caching algorithms to discover available domains inside the darknet. This approach ensures that your internal domain name system is robust, reliable, and independent of external control, enhancing the resilience and security of your infrastructure.
### A New Era of Decentralized Self-Hosting
Clan-Core is more than just a tool; it's a paradigm shift in server management. By consolidating machine definitions, secrets and network configuration, into a single, secure repository, it transforms how you manage and scale your infrastructure. Whether you're a seasoned server admin or a self-hosting enthusiast, Clan-Core offers a powerful, user-friendly solution to take your capabilities to the next level.
### Key Features of Clan-Core:
- **Unified Git Repository**: All machine configurations and secrets stored in a single repository.
- **Live Overwrites**: Deploy configurations over existing Linux distributions via SSH.
- **Automated Service Setup**: Easily set up services with Clan-Core's Module system.
- **Decentralized Mesh VPN**: Securely interconnect all machines into a private darknet.
- **Decentralized DNS**: Robust, independent DNS using flooding and caching algorithms.
- **Automated Secret Management**: Encrypted secrets that are automatically decrypted during deployment.
- **Collaboration Support**: Share secrets securely with other admins.
## Clan-Cores Future
Our vision for Clan-Core extends far beyond being just another deployment tool. Clan-Core is a framework we've developed to achieve something much greater. We want to put the "personal" back into "personal computing." Our goal is for everyday users to fully customize their phones or laptops and create truly private spaces for friends and family.
Our first major step is to develop a Graphical User Interface (GUI) that makes configuring all this possible. Initial tests have shown that AI can be leveraged as an alternative to traditional GUIs. This paves the way for a future where people can simply talk to their computers, and they will configure themselves according to the users' wishes.
By adopting Clan, you're not just embracing a tool—you're joining a movement towards a more efficient, secure, and scalable approach to server management. Join us and revolutionize your IT infrastructure today.

View File

@ -98,7 +98,7 @@ Start by indicating where your backup data should be sent. Replace `hostname` wi
Decide which folders you want to back up. For example, to backup your home and root directories:
```nix
{ clanCore.state.userdata.folders = [ "/home" "/root" ]; }
{ clan.core.state.userdata.folders = [ "/home" "/root" ]; }
```
3. **Generate Backup Credentials:**
@ -116,7 +116,7 @@ On the server where backups will be stored, enable the SSH daemon and set up a r
services.borgbackup.repos.myhostname = {
path = "/var/lib/borgbackup/myhostname";
authorizedKeys = [
(builtins.readFile ./machines/myhostname/facts/borgbackup.ssh.pub)
(builtins.readFile (config.clan.core.clanDir + "/machines/myhostname/facts/borgbackup.ssh.pub"))
];
};
}

View File

@ -10,7 +10,7 @@ In the `flake.nix` file:
```nix title="clan-core.lib.buildClan"
buildClan {
# Set a unique name
# Set a unique name
clanName = "Lobsters";
# Should usually point to the directory of flake.nix
directory = ./.;
@ -30,7 +30,7 @@ In the `flake.nix` file:
```nix title="clan-core.flakeModules.default"
clan = {
# Set a unique name
# Set a unique name
clanName = "Lobsters";
machines = {
@ -59,15 +59,15 @@ Adding or configuring a new machine requires two simple steps:
Which should show something like:
```bash hl_lines="6"
```{.shellSession hl_lines="6" .no-copy}
NAME ID-LINK FSTYPE SIZE MOUNTPOINT
sda usb-ST_16GB_AA6271026J1000000509-0:0 14.9G
├─sda1 usb-ST_16GB_AA6271026J1000000509-0:0-part1 1M
sda usb-ST_16GB_AA6271026J1000000509-0:0 14.9G
├─sda1 usb-ST_16GB_AA6271026J1000000509-0:0-part1 1M
├─sda2 usb-ST_16GB_AA6271026J1000000509-0:0-part2 vfat 100M /boot
└─sda3 usb-ST_16GB_AA6271026J1000000509-0:0-part3 ext4 2.9G /
nvme0n1 nvme-eui.e8238fa6bf530001001b448b4aec2929 476.9G
├─nvme0n1p1 nvme-eui.e8238fa6bf530001001b448b4aec2929-part1 vfat 512M
├─nvme0n1p2 nvme-eui.e8238fa6bf530001001b448b4aec2929-part2 ext4 459.6G
nvme0n1 nvme-eui.e8238fa6bf530001001b448b4aec2929 476.9G
├─nvme0n1p1 nvme-eui.e8238fa6bf530001001b448b4aec2929-part1 vfat 512M
├─nvme0n1p2 nvme-eui.e8238fa6bf530001001b448b4aec2929-part2 ext4 459.6G
└─nvme0n1p3 nvme-eui.e8238fa6bf530001001b448b4aec2929-part3 swap 16.8G
```
@ -150,10 +150,17 @@ These steps will allow you to update your machine later.
Generate the `hardware-configuration.nix` file for your machine by executing the following command:
```bash
ssh root@flash-installer.local nixos-generate-config --no-filesystems --show-hardware-config > machines/jon/hardware-configuration.nix
clan machines hw-generate [MACHINE_NAME] [HOSTNAME]
```
This command connects to `flash-installer.local` as `root`, runs `nixos-generate-config` to detect hardware configurations (excluding filesystems), and writes them to `machines/jon/hardware-configuration.nix`.
replace `[MACHINE_NAME]` with the name of the machine i.e. `jon` and `[HOSTNAME]` with the `ip_adress` or `hostname` of the machine within the network. i.e. `flash-installer.local`
!!! Example
```bash
clan machines hw-generate jon flash-installer.local
```
This command connects to `flash-installer.local` as `root`, runs `nixos-generate-config` to detect hardware configurations (excluding filesystems), and writes them to `machines/jon/hardware-configuration.nix`.
### Step 3: Custom Disk Formatting

View File

@ -52,7 +52,7 @@ This process involves preparing a suitable hardware and disk partitioning config
This is an example of the booted installer.
```{ .bash .annotate .no-copy }
```{ .bash .annotate .no-copy .nohighlight}
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ ┌───────────────────────────┐ │
│ │███████████████████████████│ # This is the QR Code (1) │
@ -151,7 +151,7 @@ Clan CLI enables you to remotely update your machines over SSH. This requires se
### Setting the Target Host
Replace `root@jon` with the actual hostname or IP address of your target machine:
```nix hl_lines="9"
```{.nix hl_lines="9" .no-copy}
buildClan {
# ...
machines = {
@ -192,7 +192,7 @@ it is also possible to specify a build host instead.
During an update, the cli will ssh into the build host and run `nixos-rebuild` from there.
```nix hl_lines="5"
```{.nix hl_lines="5" .no-copy}
buildClan {
# ...
machines = {
@ -208,7 +208,7 @@ buildClan {
To exclude machines from being updated when running `clan machines update` without any machines specified,
one can set the `clan.deployment.requireExplicitUpdate` option to true:
```nix hl_lines="5"
```{.nix hl_lines="5" .no-copy}
buildClan {
# ...
machines = {

View File

@ -94,9 +94,4 @@ Below is a guide on how to structure this in your flake.nix:
For detailed information about configuring `flake-parts` and the available options within Clan,
refer to the Clan module documentation located [here](https://git.clan.lol/clan/clan-core/src/branch/main/flakeModules/clan.nix).
## Whats next?
- [Configure Machines](configure.md): Customize machine configuration
- [Deploying](deploy.md): Deploying a Machine configuration
---

View File

@ -22,7 +22,7 @@ Follow our step-by-step guide to create and transfer this image onto a bootable
lsblk
```
```shellSession hl_lines="2"
```{.shellSession hl_lines="2" .no-copy}
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sdb 8:0 1 117,2G 0 disk
└─sdb1 8:1 1 117,2G 0 part /run/media/qubasa/INTENSO
@ -42,13 +42,22 @@ sudo umount /dev/sdb1
=== "**Linux OS**"
### Step 2. Flash Custom Installer
Using clan flash enables the inclusion of ssh public keys and disables ssh password authentication.
It also includes the language and keymap currently used into the installer image.
Using clan flash enables the inclusion of ssh public keys.
It also allows to set language and keymap currently in the installer image.
```bash
clan --flake git+https://git.clan.lol/clan/clan-core flash flash-installer --disk main /dev/sd<X>
clan flash --flake git+https://git.clan.lol/clan/clan-core \
--ssh-pubkey $HOME/.ssh/id_ed25519.pub \
--keymap en \
--language en \
--disk main /dev/sd<X> \
flash-installer
```
The `--ssh-pubkey`, `--language` and `--keymap` are optional.
Replace `$HOME/.ssh/id_ed25519.pub` with a path to your SSH public key.
If you do not have an ssh key yet, you can generate one with `ssh-keygen -t ed25519` command.
!!! Danger "Specifying the wrong device can lead to unrecoverable data loss."
The `clan flash` utility will erase the disk. Make sure to specify the correct device
@ -123,7 +132,7 @@ This will enter `iwd`
Now run the following command to connect to your Wifi:
```shellSession
```{.shellSession .no-copy}
# Identify your network device.
device list
@ -148,10 +157,10 @@ Connected network FRITZ!Box (Your router device)
IPv4 address 192.168.188.50 (Your new local ip)
```
Press `ctrl-d` to exit `IWD`.
Press ++ctrl+d++ to exit `IWD`.
!!! Important
Press `ctrl-d` **again** to update the displayed QR code and connection information.
Press ++ctrl+d++ **again** to update the displayed QR code and connection information.
You're all set up
@ -161,4 +170,4 @@ You're all set up
- [Configure Machines](configure.md): Customize machine configuration
---
---

View File

@ -9,7 +9,7 @@ include a new machine into the VPN.
By default all machines within one clan are connected via a chosen network technology.
```
```{.no-copy}
Clan
Node A
<-> (zerotier / mycelium / ...)
@ -36,7 +36,7 @@ peers. Once addresses are allocated, the controller's continuous operation is no
```
3. **Update the Controller Machine**: Execute the following:
```bash
$ clan machines update <CONTROLLER>
clan machines update <CONTROLLER>
```
Your machine is now operational as the VPN controller.
@ -48,7 +48,7 @@ To introduce a new machine to the VPN, adhere to the following steps:
configuration, substituting `<CONTROLLER>` with the controller machine name:
```nix
{ config, ... }: {
clan.networking.zerotier.networkId = builtins.readFile (config.clanCore.clanDir + "/machines/<CONTROLLER>/facts/zerotier-network-id");
clan.networking.zerotier.networkId = builtins.readFile (config.clan.core.clanDir + "/machines/<CONTROLLER>/facts/zerotier-network-id");
}
```
1. **Update the New Machine**: Execute:

View File

@ -4,10 +4,15 @@ Clan enables encryption of secrets (such as passwords & keys) ensuring security
Clan utilizes the [sops](https://github.com/getsops/sops) format and integrates with [sops-nix](https://github.com/Mic92/sops-nix) on NixOS machines.
This guide will walk you through:
### Create Your Master Keypair
- **Creating a Keypair for Your User**: Learn how to generate a keypair for $USER to securely control all secrets.
- **Creating Your First Secret**: Step-by-step instructions on creating your initial secret.
- **Assigning Machine Access to the Secret**: Understand how to grant a machine access to the newly created secret.
To get started, you'll need to create **Your master keypair**.
## Create Your Admin Keypair
To get started, you'll need to create **Your admin keypair**.
!!! info
Don't worry — if you've already made one before, this step won't change or overwrite it.
@ -27,7 +32,7 @@ Also add your age public key to the repository with 'clan secrets users add YOUR
!!! warning
Make sure to keep a safe backup of the private key you've just created.
If it's lost, you won't be able to get to your secrets anymore because they all need the master key to be unlocked.
If it's lost, you won't be able to get to your secrets anymore because they all need the admin key to be unlocked.
!!! note
It's safe to add any secrets created by the clan CLI and placed in your repository to version control systems like `git`.
@ -35,7 +40,7 @@ Also add your age public key to the repository with 'clan secrets users add YOUR
### Add Your Public Key
```bash
clan secrets users add <your_username> <your_public_key>
clan secrets users add $USER <your_public_key>
```
It's best to choose the same username as on your Setup/Admin Machine that you use to control the deployment with.
@ -101,17 +106,20 @@ In your nixos configuration you can get a path to secrets like this `config.sops
### Assigning Access
By default, secrets are encrypted for your key. To specify which users and machines can access a secret:
When using `clan secrets set <secret>` without arguments, secrets are encrypted for the key of the user named like your current $USER.
```bash
clan secrets set --machine <machine1> --machine <machine2> --user <user1> --user <user2> <secret_name>
```
You can also just add machines/users to existing secrets:
To add machines/users to an existing secret use:
```bash
clan secrets machines add-secret <machine_name> <secret_name>
```
Alternatively specify users and machines while creating a secret:
```bash
clan secrets set --machine <machine1> --machine <machine2> --user <user1> --user <user2> <secret_name>
```
## Advanced
In this section we go into more advanced secret management topics.
@ -183,11 +191,9 @@ Since our clan secret module will auto-import secrets that are encrypted for a p
you can now remove `sops.secrets.<secrets> = { };` unless you need to specify more options for the secret like owner/group of the secret file.
## Indepth Explanation
The secrets system conceptually knows two different entities:
- **Machine**: consumes secrets

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
/nix/store/8y5h98wk5p94mv1wyb2c4gkrr7bswd19-asciinema-player.css

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
/nix/store/w0i3f9qzn9n6jmfnfgiw5wnab2f9ssdw-asciinema-player.min.js

View File

@ -1,45 +0,0 @@
.asciinema-player-theme-alabaster-auto {
--term-color-foreground: #000000; /* Black for foreground text */
--term-color-background: #f7f7f7; /* Very light gray for background */
--term-color-0: #000000; /* Black */
--term-color-1: #aa3731; /* Red */
--term-color-2: #448c37; /* Green */
--term-color-3: #cb9000; /* Yellow */
--term-color-4: #325cc0; /* Blue */
--term-color-5: #7a3e9d; /* Magenta */
--term-color-6: #0083b2; /* Cyan */
--term-color-7: #bbbbbb; /* White */
--term-color-8: #777777; /* Bright black (gray) */
--term-color-9: #f05050; /* Bright red */
--term-color-10: #60cb00; /* Bright green */
--term-color-11: #ffbc5d; /* Bright yellow */
--term-color-12: #007acc; /* Bright blue */
--term-color-13: #e64ce6; /* Bright magenta */
--term-color-14: #00aacb; /* Bright cyan */
--term-color-15: #ffffff; /* Bright white */
}
@media (prefers-color-scheme: dark) {
.asciinema-player-theme-solarized-auto {
--term-color-foreground: #839496;
--term-color-background: #002b36;
--term-color-0: #073642;
--term-color-1: #dc322f;
--term-color-2: #859900;
--term-color-3: #b58900;
--term-color-4: #268bd2;
--term-color-5: #d33682;
--term-color-6: #2aa198;
--term-color-7: #eee8d5;
--term-color-8: #002b36;
--term-color-9: #cb4b16;
--term-color-10: #586e75;
--term-color-11: #657b83;
--term-color-12: #839496;
--term-color-13: #6c71c4;
--term-color-14: #93a1a1;
--term-color-15: #fdf6e3;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,13 @@
@font-face {
font-family: "Roboto";
src: url(./Roboto-Regular.ttf) format('truetype');
}
@font-face {
font-family: "Fira Code";
src: url(./FiraCode-VF.ttf) format('truetype');
}
:root {
--md-text-font: "Roboto";
--md-code-font: "Fira Code";
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

View File

@ -7,15 +7,15 @@
]
},
"locked": {
"lastModified": 1714400597,
"narHash": "sha256-AA1TCyEl4O6+6F5man/V5VH9Zl9HPBpK91tSkZ16i2E=",
"owner": "Qubasa",
"lastModified": 1717915259,
"narHash": "sha256-VsGPboaleIlPELHY5cNTrXK4jHVmgUra8uC6h7KVC5c=",
"owner": "nix-community",
"repo": "disko",
"rev": "58785136b8c37aeb2f67081387b48f663b166331",
"rev": "1bbdb06f14e2621290b250e631cf3d8948e4d19b",
"type": "github"
},
"original": {
"owner": "Qubasa",
"owner": "nix-community",
"repo": "disko",
"type": "github"
}
@ -27,11 +27,11 @@
]
},
"locked": {
"lastModified": 1715865404,
"narHash": "sha256-/GJvTdTpuDjNn84j82cU6bXztE0MSkdnTWClUCRub78=",
"lastModified": 1717285511,
"narHash": "sha256-iKzJcpdXih14qYVcZ9QC9XuZYnPc6T8YImb6dX166kw=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "8dc45382d5206bd292f9c2768b8058a8fd8311d9",
"rev": "2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8",
"type": "github"
},
"original": {
@ -55,22 +55,6 @@
"type": "github"
}
},
"nixos-2311": {
"locked": {
"lastModified": 1715818734,
"narHash": "sha256-WvAJWCwPj/6quKcsgsvQYyZRxV8ho/yUzj0HZQ34DVU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "95742536dc6debb5a8b8b78b27001c38f369f1e7",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "release-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixos-generators": {
"inputs": {
"nixlib": "nixlib",
@ -79,11 +63,11 @@
]
},
"locked": {
"lastModified": 1716123454,
"narHash": "sha256-U2o4UPM/UsEyIX2p11+YEQgR9HY3PmjZ2mRl/x5e4xo=",
"lastModified": 1716210724,
"narHash": "sha256-iqQa3omRcHGpWb1ds75jS9ruA5R39FTmAkeR3J+ve1w=",
"owner": "nix-community",
"repo": "nixos-generators",
"rev": "a63e0c83dd83fe28cc571b97129e13373436bd82",
"rev": "d14b286322c7f4f897ca4b1726ce38cb68596c94",
"type": "github"
},
"original": {
@ -94,17 +78,17 @@
},
"nixos-images": {
"inputs": {
"nixos-2311": "nixos-2311",
"nixos-stable": [],
"nixos-unstable": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1716132123,
"narHash": "sha256-rATSWbPaKQfZGaemu0tHL2xfCzVIVwpuTjk+KSBC+k4=",
"lastModified": 1717770332,
"narHash": "sha256-NQmFHj0hTCUgnMAsaNTu6sNTRyo0rFQEe+/lVgV5yxU=",
"owner": "nix-community",
"repo": "nixos-images",
"rev": "8c9cab8c44434c12dafc465fbf61a710c5bceb08",
"rev": "72771bd35f4e19e32d6f652528483b5e07fc317b",
"type": "github"
},
"original": {
@ -115,11 +99,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1716127062,
"narHash": "sha256-2rk8FqB/iQV2d0vQLs684/Tj5PUHaS1sFwG7fng5vXE=",
"lastModified": 1717926692,
"narHash": "sha256-THcv8qDqobZefHHluPjx/8n+MtVVb8ag/oJbKMqKNRo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "8a2555763c48e2410054de3f52f7310ce3241ec5",
"rev": "7d916e720af6b2ca355e4d0cfb8e4f742c172239",
"type": "github"
},
"original": {
@ -148,11 +132,11 @@
"nixpkgs-stable": []
},
"locked": {
"lastModified": 1716087663,
"narHash": "sha256-zuSAGlx8Qk0OILGCC2GUyZ58/SJ5R3GZdeUNQ6IS0fQ=",
"lastModified": 1717902109,
"narHash": "sha256-OQTjaEZcByyVmHwJlKp/8SE9ikC4w+mFd3X0jJs6wiA=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "0bf1808e70ce80046b0cff821c019df2b19aabf5",
"rev": "f0922ad001829b400f0160ba85b47d252fa3d925",
"type": "github"
},
"original": {
@ -168,11 +152,11 @@
]
},
"locked": {
"lastModified": 1715940852,
"narHash": "sha256-wJqHMg/K6X3JGAE9YLM0LsuKrKb4XiBeVaoeMNlReZg=",
"lastModified": 1717850719,
"narHash": "sha256-npYqVg+Wk4oxnWrnVG7416fpfrlRhp/lQ6wQ4DHI8YE=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "2fba33a182602b9d49f0b2440513e5ee091d838b",
"rev": "4fc1c45a5f50169f9f29f6a98a438fb910b834ed",
"type": "github"
},
"original": {

View File

@ -8,7 +8,7 @@
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable-small";
disko.url = "github:Qubasa/disko";
disko.url = "github:nix-community/disko";
disko.inputs.nixpkgs.follows = "nixpkgs";
sops-nix.url = "github:Mic92/sops-nix";
sops-nix.inputs.nixpkgs.follows = "nixpkgs";
@ -17,6 +17,8 @@
nixos-generators.inputs.nixpkgs.follows = "nixpkgs";
nixos-images.url = "github:nix-community/nixos-images";
nixos-images.inputs.nixos-unstable.follows = "nixpkgs";
# unused input
nixos-images.inputs.nixos-stable.follows = "";
flake-parts.url = "github:hercules-ci/flake-parts";
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
treefmt-nix.url = "github:numtide/treefmt-nix";
@ -24,10 +26,14 @@
};
outputs =
inputs@{ flake-parts, ... }:
inputs@{ flake-parts, self, ... }:
flake-parts.lib.mkFlake { inherit inputs; } (
{ ... }:
{
clan = {
# meta.name = "clan-core";
directory = self;
};
systems = [
"x86_64-linux"
"aarch64-linux"
@ -47,6 +53,8 @@
./nixosModules/flake-module.nix
./pkgs/flake-module.nix
./templates/flake-module.nix
./inventory/flake-module.nix
];
}
);

View File

@ -17,6 +17,33 @@ let
cfg = config.clan;
in
{
imports = [
# TODO: figure out how to print the deprecation warning
# "${inputs.nixpkgs}/nixos/modules/misc/assertions.nix"
(lib.mkRenamedOptionModule
[
"clan"
"clanName"
]
[
"clan"
"meta"
"name"
]
)
(lib.mkRenamedOptionModule
[
"clan"
"clanIcon"
]
[
"clan"
"meta"
"icon"
]
)
];
options.clan = {
directory = mkOption {
type = types.path;
@ -33,15 +60,27 @@ in
default = { };
description = "Allows to include machine-specific modules i.e. machines.\${name} = { ... }";
};
clanName = mkOption {
type = types.str;
description = "Needs to be (globally) unique, as this determines the folder name where the flake gets downloaded to.";
};
clanIcon = mkOption {
type = types.nullOr types.path;
default = null;
description = "A path to an icon to be used for the clan, should be the same for all machines";
# Checks are performed in 'buildClan'
# Not everyone uses flake-parts
meta = {
name = lib.mkOption {
type = types.nullOr types.str;
default = null;
description = "Needs to be (globally) unique, as this determines the folder name where the flake gets downloaded to.";
};
icon = mkOption {
type = types.nullOr types.path;
default = null;
description = "A path to an icon to be used for the clan in the GUI";
};
description = mkOption {
type = types.nullOr types.str;
default = null;
description = "A short description of the clan";
};
};
pkgsForSystem = mkOption {
type = types.functionTo types.raw;
default = _system: null;
@ -52,6 +91,7 @@ in
clanInternals = lib.mkOption {
type = lib.types.submodule {
options = {
meta = lib.mkOption { type = lib.types.attrsOf lib.types.unspecified; };
all-machines-json = lib.mkOption { type = lib.types.attrsOf lib.types.unspecified; };
machines = lib.mkOption { type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified); };
machinesFunc = lib.mkOption { type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified); };
@ -65,9 +105,8 @@ in
directory
specialArgs
machines
clanName
clanIcon
pkgsForSystem
meta
;
};
};

View File

@ -10,10 +10,9 @@
treefmt.programs.mypy.enable = true;
treefmt.programs.mypy.directories = {
"pkgs/clan-cli".extraPythonPackages = self'.packages.clan-cli.testDependencies;
"pkgs/clan-vm-manager".extraPythonPackages =
# clan-vm-manager currently only exists on linux
(self'.packages.clan-vm-manager.externalTestDeps or [ ])
++ self'.packages.clan-cli.testDependencies;
"pkgs/clan-app".extraPythonPackages =
# clan-app currently only exists on linux
(self'.packages.clan-app.externalTestDeps or [ ]) ++ self'.packages.clan-cli.testDependencies;
};
treefmt.settings.formatter.nix = {

5
inventory/.envrc Normal file
View File

@ -0,0 +1,5 @@
source_up
watch_file flake-module.nix
use flake .#inventory-schema --builders ''

57
inventory/README.md Normal file
View File

@ -0,0 +1,57 @@
# Inventory
This part provides a specification for the inventory.
It is used for design phase and as validation helper.
> Cue is less verbose and easier to understand and maintain than json-schema.
> Json-schema, if needed can be easily generated on-the fly.
## Checking validity
Directly check a json against the schema
`cue vet inventory.json root.cue -d '#Root'`
## Json schema
Export the json-schema i.e. for usage in python / javascript / nix
`cue export --out openapi root.cue`
## Usage
Comments are rendered as descriptions in the json schema.
```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"
}
```

137
inventory/example_flake.nix Normal file
View File

@ -0,0 +1,137 @@
{
description = "<Put your description here>";
inputs.clan-core.url = "https://git.clan.lol/clan/clan-core/archive/main.tar.gz";
outputs =
{ clan-core, ... }:
let
pkgs = clan-core.inputs.nixpkgs.legacyPackages.${system};
system = "x86_64-linux";
in
# Usage see: https://docs.clan.lol
# nice_flake_interface -> buildInventory() -> Inventory -> buildClanFromInventory() -> nixosConfigurations
# buildClanFromInventory = inventory: evalModules {
# extraAttrs = { inherit inventory; };
# # (attrNames inventory.machines)
# };
# clan =
# clan-core.lib.buildClanFromInventory [
# # Inventory 0 (loads the json file managed by the Python API)
# (builtins.fromJSON (builtins.readFile ./inventory.json))
# # ->
# # {
# # services."backups_1".autoIncludeMachines = true;
# # services."backups_1".module = "borgbackup";
# # ... etc.
# # }
# ]
# ++ (buildInventory {
# clanName = "nice_flake_interface";
# description = "A nice flake interface";
# icon = "assets/icon.png";
# machines = {
# jon = {
# # Just regular nixos/clan configuration ?
# # config = {
# # imports = [
# # ./modules/shared.nix
# # ./machines/jon/configuration.nix
# # ];
# # nixpkgs.hostPlatform = system;
# # # Set this for clan commands use ssh i.e. `clan machines update`
# # # If you change the hostname, you need to update this line to root@<new-hostname>
# # # This only works however if you have avahi running on your admin machine else use IP
# # clan.networking.targetHost = pkgs.lib.mkDefault "root@jon";
# # # ssh root@flash-installer.local lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT
# # disko.devices.disk.main = {
# # device = "/dev/disk/by-id/__CHANGE_ME__";
# # };
# # # IMPORTANT! Add your SSH key here
# # # e.g. > cat ~/.ssh/id_ed25519.pub
# # users.users.root.openssh.authorizedKeys.keys = throw ''
# # Don't forget to add your SSH key here!
# # users.users.root.openssh.authorizedKeys.keys = [ "<YOUR SSH_KEY>" ]
# # '';
# # # Zerotier needs one controller to accept new nodes. Once accepted
# # # the controller can be offline and routing still works.
# # clan.networking.zerotier.controller.enable = true;
# # };
# };
# };
# })
# ++ [
# # Low level inventory overrides (comes at the end)
# {
# services."backups_2".autoIncludeMachines = true;
# services."backups_2".module = "borgbackup";
# }
# ];
# # buildClan :: [ Partial<Inventory> ] -> Inventory
# # foldl' (acc: v: lib.recursiveUpdate acc v) {} []
# inventory = [
# # import json
# {...}
# # power user flake
# {...}
# ]
# # With Module system
# # Pros: Easy to understand,
# # Cons: Verbose, hard to maintain
# # buildClan :: { modules = [ { config = Partial<Inventory>; options :: InventoryOptions; } } ]; } -> Inventory
# eval = lib.evalModules {
# modules = [
# {
# # Inventory Schema
# # Python validation
# options = {...}
# }
# {
# config = map lib.mkDefault
# (builtins.fromJSON (builtins.readFile ./inventory.json))
# }
# {
# # User provided
# config = {...}
# }
# # Later overrides.
# {
# lib.mkForce ...
# }
# ];
# }
# nixosConfigurations = lib.evalModules inventory;
# eval.config.inventory
# #
# eval.config.machines.jon#nixosConfig
# eval.config.machines.sara#nixosConfig
#
# {inventory, config, ...}:{
# hostname = config.machines.sara # Invalid
# hostname = inventory.machines.sara.hostname # Valid
# }
/*
# Type
buildInventory :: {
clanName :: string
machines :: {
${name} :: {
config :: {
# NixOS configuration
};
};
};
# ... More mapped inventory options
# i.e. shared config for all machines
} -> Inventory
*/
{
# all machines managed by Clan
inherit (clan) nixosConfigurations clanInternals;
# add the Clan cli tool to the dev shell
devShells.${system}.default = pkgs.mkShell {
packages = [ clan-core.packages.${system}.clan-cli ];
};
};
}

View File

@ -0,0 +1,46 @@
{ ... }:
{
perSystem =
{ pkgs, config, ... }:
{
packages.inventory-schema = pkgs.stdenv.mkDerivation {
name = "inventory-schema";
src = ./src;
buildInputs = [ pkgs.cue ];
installPhase = ''
mkdir -p $out
'';
};
devShells.inventory-schema = pkgs.mkShell { inputsFrom = [ config.packages.inventory-schema ]; };
checks.inventory-schema-checks = pkgs.stdenv.mkDerivation {
name = "inventory-schema-checks";
src = ./src;
buildInputs = [ pkgs.cue ];
buildPhase = ''
echo "Running inventory tests..."
echo "Export cue as json-schema..."
cue export --out openapi root.cue
echo "Validate test/*.json against inventory-schema..."
test_dir="test"
for file in "$test_dir"/*; do
# Check if the item is a file
if [ -f "$file" ]; then
# Print the filename
echo "Running test on: $file"
# Run the cue vet command
cue vet "$file" root.cue -d "#Root"
fi
done
touch $out
'';
};
};
}

View File

@ -0,0 +1,2 @@
module: "clan.lol/inventory"
language: version: "v0.8.2"

View File

@ -0,0 +1,8 @@
package machines
#machine: machines: [string]: {
name: string,
description?: string,
icon?: string
}

24
inventory/src/root.cue Normal file
View File

@ -0,0 +1,24 @@
package inventory
import (
"clan.lol/inventory/services"
"clan.lol/inventory/machines"
)
@jsonschema(schema="http://json-schema.org/schema#")
#Root: {
meta: {
// A name of the clan (primarily shown by the UI)
name: string
// A description of the clan
description?: string
// The icon path
icon?: string
}
// A map of services
services.#service
// A map of machines
machines.#machine
}

View File

@ -0,0 +1,32 @@
package services
#ServiceRole: "server" | "client" | "both"
#service: services: [string]: {
// Required meta fields
meta: {
name: string,
icon?: string
description?: string,
},
// Required module specifies the behavior of the service.
module: string,
// We moved the machine sepcific config to "machines".
// It may be moved back depending on what makes more sense in the future.
machineConfig: {
[string]: {
roles?: [ ...#ServiceRole ],
config?: {
...
}
}
},
// Configuration for the service
config: {
// Schema depends on the module.
// It declares the interface how the service can be configured.
...
}
}

View File

@ -0,0 +1,38 @@
{
"machines": {
"camina_machine": {
"name": "camina"
},
"vyr_machine": {
"name": "vyr"
},
"vi_machine": {
"name": "vi"
}
},
"meta": {
"name": "kenjis clan"
},
"services": {
"backup": {
"meta": {
"name": "My backup"
},
"module": "borbackup-static",
"machineConfig": {
"vyr": {
"roles": ["server"]
},
"vi": {
"roles": ["client"]
},
"camina_machine": {
"roles": ["client"]
}
},
"config": {
"folders": ["/home", "/root", "/var", "/etc"]
}
}
}
}

View File

@ -0,0 +1,45 @@
{
"machines": {
"camina_machine": {
"name": "camina"
},
"vyr": {
"name": "vyr"
},
"vi": {
"name": "vi"
}
},
"meta": {
"name": "kenjis clan"
},
"services": {
"sync_files": {
"meta": {
"name": "My sync"
},
"module": "syncthing-static-peers",
"machineConfig": {
"vyr": {},
"vi": {},
"camina_machine": {}
},
"config": {
"folders": {
"test": {
"path": "~/data/docs",
"devices": ["camina", "vyr", "vi"]
},
"videos": {
"path": "~/data/videos",
"devices": ["camina", "vyr", "ezra"]
},
"playlist": {
"path": "~/data/playlist",
"devices": ["camina", "vyr", "ezra"]
}
}
}
}
}
}

View File

@ -0,0 +1,36 @@
{
"machines": {
"camina_machine": {
"name": "camina"
},
"vyr_machine": {
"name": "vyr"
},
"vi_machine": {
"name": "vi"
}
},
"meta": {
"name": "kenjis clan"
},
"services": {
"backup": {
"meta": {
"name": "My backup"
},
"module": "borbackup-static",
"machineConfig": {
"vyr_machine": {
"roles": ["server"]
},
"vi_machine": {
"roles": ["peer"]
},
"camina_machine": {
"roles": ["peer"]
}
},
"config": {}
}
}
}

View File

@ -7,16 +7,58 @@
directory, # The directory containing the machines subdirectory
specialArgs ? { }, # Extra arguments to pass to nixosSystem i.e. useful to make self available
machines ? { }, # allows to include machine-specific modules i.e. machines.${name} = { ... }
clanName, # Needs to be (globally) unique, as this determines the folder name where the flake gets downloaded to.
# DEPRECATED: use meta.name instead
clanName ? null, # Needs to be (globally) unique, as this determines the folder name where the flake gets downloaded to.
# DEPRECATED: use meta.icon instead
clanIcon ? null, # A path to an icon to be used for the clan, should be the same for all machines
meta ? { }, # A set containing clan meta: name :: string, icon :: string, description :: string
pkgsForSystem ? (_system: null), # 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.
}:
let
deprecationWarnings = [
(lib.warnIf (
clanName != null
) "clanName is deprecated, please use meta.name instead. ${clanName}" null)
(lib.warnIf (clanIcon != null) "clanIcon is deprecated, please use meta.icon instead" null)
];
machinesDirs = lib.optionalAttrs (builtins.pathExists "${directory}/machines") (
builtins.readDir (directory + /machines)
);
mergedMeta =
let
metaFromFile =
if (builtins.pathExists "${directory}/clan/meta.json") then
let
settings = builtins.fromJSON (builtins.readFile "${directory}/clan/meta.json");
in
settings
else
{ };
legacyMeta = lib.filterAttrs (_: v: v != null) {
name = clanName;
icon = clanIcon;
};
optionsMeta = lib.filterAttrs (_: v: v != null) meta;
warnings =
builtins.map (
name:
if
metaFromFile.${name} or null != optionsMeta.${name} or null && optionsMeta.${name} or null != null
then
lib.warn "meta.${name} is set in different places. (exlicit option meta.${name} overrides ${directory}/clan/meta.json)" null
else
null
) (builtins.attrNames metaFromFile)
++ [ (if (res.name or null == null) then (throw "meta.name should be set") else null) ];
res = metaFromFile // legacyMeta // optionsMeta;
in
# Print out warnings before returning the merged result
builtins.deepSeq warnings res;
machineSettings =
machineName:
# CLAN_MACHINE_SETTINGS_FILE allows to override the settings file temporarily
@ -58,11 +100,15 @@ let
(machines.${name} or { })
(
{
# Settings
clan.core.clanDir = directory;
# Inherited from clan wide settings
clan.core.clanName = meta.name or clanName;
clan.core.clanIcon = meta.icon or clanIcon;
# Machine specific settings
clan.core.machineName = name;
networking.hostName = lib.mkDefault name;
clanCore.clanName = clanName;
clanCore.clanIcon = clanIcon;
clanCore.clanDir = directory;
clanCore.machineName = name;
nixpkgs.hostPlatform = lib.mkDefault system;
# speeds up nix commands by using the nixpkgs from the host system (especially useful in VMs)
@ -127,10 +173,15 @@ let
) supportedSystems
);
in
{
builtins.deepSeq deprecationWarnings {
inherit nixosConfigurations;
clanInternals = {
# Evaluated clan meta
# Merged /clan/meta.json with overrides from buildClan
meta = mergedMeta;
# machine specifics
machines = configsPerSystem;
machinesFunc = configsFuncPerSystem;
all-machines-json = lib.mapAttrs (

View File

@ -83,20 +83,20 @@ rec {
in
# either type
# TODO: if all nested optiosn are excluded, the parent sould be excluded too
# TODO: if all nested options are excluded, the parent should be excluded too
if
option.type.name or null == "either"
option.type.name or null == "either" || option.type.name or null == "coercedTo"
# return jsonschema property definition for either
then
let
optionsList' = [
{
type = option.type.nestedTypes.left;
type = option.type.nestedTypes.left or option.type.nestedTypes.coercedType;
_type = "option";
loc = option.loc;
}
{
type = option.type.nestedTypes.right;
type = option.type.nestedTypes.right or option.type.nestedTypes.finalType;
_type = "option";
loc = option.loc;
}
@ -157,12 +157,21 @@ rec {
# TODO: Add support for intMatching in jsonschema
# parse port type aka. "unsignedInt16"
else if option.type.name == "unsignedInt16" then
else if
option.type.name == "unsignedInt16"
|| option.type.name == "unsignedInt"
|| option.type.name == "pkcs11"
|| option.type.name == "intBetween"
then
default // example // description // { type = "integer"; }
# parse string
# TODO: parse more precise string types
else if
option.type.name == "str"
|| option.type.name == "singleLineStr"
|| option.type.name == "passwdEntry str"
|| option.type.name == "passwdEntry path"
# return jsonschema property definition for string
then
default // example // description // { type = "string"; }

View File

@ -1,7 +1,7 @@
{ lib, ... }:
{
imports = [ ./state.nix ];
options.clanCore.backups = {
options.clan.core.backups = {
providers = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule (

View File

@ -2,37 +2,43 @@
{
imports = [
(lib.mkRemovedOptionModule [
"clanCore"
"clan"
"core"
"secretsPrefix"
] "secretsPrefix was only used by the sops module and the code is now integrated in there")
(lib.mkRenamedOptionModule
[
"clanCore"
"clan"
"core"
"secretStore"
]
[
"clanCore"
"clan"
"core"
"facts"
"secretStore"
]
)
(lib.mkRemovedOptionModule [
"clanCore"
"clan"
"core"
"secretsDirectory"
] "clancore.secretsDirectory was removed. Use clanCore.facts.secretPathFunction instead")
] "clan.core.secretsDirectory was removed. Use clan.core.facts.secretPathFunction instead")
(lib.mkRenamedOptionModule
[
"clanCore"
"clan"
"core"
"secretsUploadDirectory"
]
[
"clanCore"
"clan"
"core"
"facts"
"secretUploadDirectory"
]
)
];
options.clanCore.secrets = lib.mkOption {
options.clan.core.secrets = lib.mkOption {
visible = false;
default = { };
type = lib.types.attrsOf (
@ -97,14 +103,14 @@
description = ''
path to a secret which is generated by the generator
'';
default = config.clanCore.facts.secretPathFunction secret;
defaultText = lib.literalExpression "config.clanCore.facts.secretPathFunction secret";
default = config.clan.core.facts.secretPathFunction secret;
defaultText = lib.literalExpression "config.clan.core.facts.secretPathFunction secret";
};
}
// lib.optionalAttrs (config.clanCore.facts.secretStore == "sops") {
// lib.optionalAttrs (config.clan.core.facts.secretStore == "sops") {
groups = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = config.clanCore.sops.defaultGroups;
default = config.clan.core.sops.defaultGroups;
description = ''
Groups to decrypt the secret for. By default we always use the user's key.
'';
@ -134,12 +140,12 @@
path to a fact which is generated by the generator
'';
default =
config.clanCore.clanDir
+ "/machines/${config.clanCore.machineName}/facts/${fact.config._module.args.name}";
defaultText = lib.literalExpression "\${config.clanCore.clanDir}/machines/\${config.clanCore.machineName}/facts/\${fact.config._module.args.name}";
config.clan.core.clanDir
+ "/machines/${config.clan.core.machineName}/facts/${fact.config._module.args.name}";
defaultText = lib.literalExpression "\${config.clan.core.clanDir}/machines/\${config.clan.core.machineName}/facts/\${fact.config._module.args.name}";
};
value = lib.mkOption {
defaultText = lib.literalExpression "\${config.clanCore.clanDir}/\${fact.config.path}";
defaultText = lib.literalExpression "\${config.clan.core.clanDir}/\${fact.config.path}";
type = lib.types.nullOr lib.types.str;
default =
if builtins.pathExists fact.config.path then lib.strings.fileContents fact.config.path else null;
@ -152,16 +158,16 @@
})
);
};
config = lib.mkIf (config.clanCore.secrets != { }) {
clanCore.facts.services = lib.mapAttrs' (
config = lib.mkIf (config.clan.core.secrets != { }) {
clan.core.facts.services = lib.mapAttrs' (
name: service:
lib.warn "clanCore.secrets.${name} is deprecated, use clanCore.facts.services.${name} instead" (
lib.warn "clan.core.secrets.${name} is deprecated, use clan.core.facts.services.${name} instead" (
lib.nameValuePair name ({
secret = service.secrets;
public = service.facts;
generator = service.generator;
})
)
) config.clanCore.secrets;
) config.clan.core.secrets;
};
}

View File

@ -5,7 +5,7 @@
...
}:
{
options.clanCore.facts = {
options.clan.core.facts = {
secretStore = lib.mkOption {
type = lib.types.enum [
"sops"
@ -115,6 +115,7 @@
type = lib.types.str;
readOnly = true;
internal = true;
defaultText = "read only script";
default = ''
set -eu -o pipefail
@ -122,13 +123,23 @@
# prepare sandbox user
mkdir -p /etc
cp ${
pkgs.runCommand "fake-etc" { } ''
export PATH="${pkgs.coreutils}/bin"
mkdir -p $out
cp /etc/* $out/
''
}/* /etc/
cat > /etc/group <<EOF
root:x:0:
nixbld:!:$(id -g):
nogroup:x:65534:
EOF
cat > /etc/passwd <<EOF
root:x:0:0:Nix build user:/build:/noshell
nixbld:x:$(id -u):$(id -g):Nix build user:/build:/noshell
nobody:x:65534:65534:Nobody:/:/noshell
EOF
cat > /etc/hosts <<EOF
127.0.0.1 localhost
::1 localhost
EOF
${config.script}
'';
@ -155,13 +166,13 @@
description = ''
path to a secret which is generated by the generator
'';
default = config.clanCore.facts.secretPathFunction secret;
default = config.clan.core.facts.secretPathFunction secret;
};
}
// lib.optionalAttrs (config.clanCore.facts.secretModule == "clan_cli.facts.secret_modules.sops") {
// lib.optionalAttrs (config.clan.core.facts.secretModule == "clan_cli.facts.secret_modules.sops") {
groups = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = config.clanCore.sops.defaultGroups;
default = config.clan.core.sops.defaultGroups;
description = ''
Groups to decrypt the secret for. By default we always use the user's key.
'';
@ -190,12 +201,12 @@
description = ''
path to a fact which is generated by the generator
'';
defaultText = lib.literalExpression "\${config.clanCore.clanDir}/machines/\${config.clanCore.machineName}/facts/\${fact.config.name}";
defaultText = lib.literalExpression "\${config.clan.core.clanDir}/machines/\${config.clan.core.machineName}/facts/\${fact.config.name}";
default =
config.clanCore.clanDir + "/machines/${config.clanCore.machineName}/facts/${fact.config.name}";
config.clan.core.clanDir + "/machines/${config.clan.core.machineName}/facts/${fact.config.name}";
};
value = lib.mkOption {
defaultText = lib.literalExpression "\${config.clanCore.clanDir}/\${fact.config.path}";
defaultText = lib.literalExpression "\${config.clan.core.clanDir}/\${fact.config.path}";
type = lib.types.nullOr lib.types.str;
default =
if builtins.pathExists fact.config.path then lib.strings.fileContents fact.config.path else null;
@ -218,5 +229,15 @@
./public/in_repo.nix
./public/vm.nix
# (lib.mkRenamedOptionModule
# [
# "clanCore"
# ]
# [
# "clan"
# "core"
# ]
# )
];
}

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