Compare commits
428 Commits
pinned-cla
...
feat/termi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7859c87af8 | ||
|
|
b6190b2760 | ||
|
|
d389c4dc5d | ||
|
|
91cf2a54bb | ||
|
|
322068dad1 | ||
|
|
39995eef39 | ||
|
|
01eff2c6b9 | ||
|
|
491dd8134a | ||
|
|
7e4e083014 | ||
|
|
f561102ca8 | ||
|
|
6d6a0521ff | ||
|
|
bf993af56f | ||
|
|
7503784699 | ||
|
|
1c62c287b7 | ||
|
|
a32b3db8e5 | ||
|
|
04d0087239 | ||
|
|
6777baca96 | ||
|
|
4b44892b47 | ||
|
|
339696da1f | ||
|
|
1644dc66e7 | ||
|
|
4aaa985703 | ||
|
|
8a40d46e96 | ||
|
|
c7515ab5e9 | ||
|
|
447a4ecc3e | ||
|
|
df12613ad8 | ||
|
|
fe39c37c07 | ||
|
|
6b8c0ba57a | ||
|
|
5f10f5712e | ||
|
|
2bf33ea295 | ||
|
|
e5ba0489c4 | ||
|
|
98b0f97d45 | ||
|
|
57cd50ae35 | ||
|
|
176b1f94bc | ||
|
|
d4e5a5ef8b | ||
|
|
0ca7600439 | ||
|
|
aa1bbd1180 | ||
|
|
3d6fcd522a | ||
|
|
9b714aa048 | ||
|
|
1b13296444 | ||
|
|
cff5d61f26 | ||
|
|
7bcb0afae9 | ||
|
|
e53ce07dc8 | ||
|
|
768b94fc75 | ||
|
|
6b1d4adb81 | ||
|
|
dc108cc27d | ||
|
|
dcb9358e51 | ||
|
|
104c05e206 | ||
|
|
e5807bfa7e | ||
|
|
0a22218026 | ||
|
|
843e1b24be | ||
|
|
8f98aa854f | ||
|
|
8576016b32 | ||
|
|
0e9124d322 | ||
|
|
2510b2bb77 | ||
|
|
9f298ecb86 | ||
|
|
df0b8cfd45 | ||
|
|
afbb6549a6 | ||
|
|
15ec2067a6 | ||
|
|
b628b12b3e | ||
|
|
74ceb95eb7 | ||
|
|
f8cf9fa172 | ||
|
|
5bc6126873 | ||
|
|
f9779322d0 | ||
|
|
04ca72f5b5 | ||
|
|
5be449740e | ||
|
|
5dc3d27fb4 | ||
|
|
c45c94e045 | ||
|
|
66f35ae637 | ||
|
|
1c0b383183 | ||
|
|
89edfda887 | ||
|
|
ce00c63721 | ||
|
|
80229c5e77 | ||
|
|
39b81a17c3 | ||
|
|
5b80204107 | ||
|
|
55b032094f | ||
|
|
73ab00ac7c | ||
|
|
25e3d27bf2 | ||
|
|
d9e4c93509 | ||
|
|
15f0ea616c | ||
|
|
3285efa55d | ||
|
|
a3078f4e13 | ||
|
|
513d085f59 | ||
|
|
4eac7ad86d | ||
|
|
bfe158c9fa | ||
|
|
188e6d5d16 | ||
|
|
b1054e2ad2 | ||
|
|
db666ce2ce | ||
|
|
1c2ee49047 | ||
|
|
53dcc4e332 | ||
|
|
a9ed972834 | ||
|
|
c34b693a64 | ||
|
|
6dab14c9d4 | ||
|
|
0c099f16bb | ||
|
|
38159d85f7 | ||
|
|
228cdfd0e9 | ||
|
|
bbeef3d76a | ||
|
|
d8cb43ae8d | ||
|
|
d50eac6525 | ||
|
|
3b29c0e006 | ||
|
|
e5f38db60f | ||
|
|
c624163581 | ||
|
|
40e34d9307 | ||
|
|
6863ce136f | ||
|
|
bd92170bed | ||
|
|
d842a13789 | ||
|
|
42de68966b | ||
|
|
68183634bb | ||
|
|
3457542871 | ||
|
|
f6544d1cda | ||
|
|
131c7ea263 | ||
|
|
6b3509c3b1 | ||
|
|
ec19ef1ec5 | ||
|
|
00a439999b | ||
|
|
7e63be2976 | ||
|
|
c059eb37ea | ||
|
|
dc8675fcb6 | ||
|
|
545f498881 | ||
|
|
c55bffa5a5 | ||
|
|
16112e259c | ||
|
|
877107650f | ||
|
|
6da64f6f27 | ||
|
|
cdaf0e8c2b | ||
|
|
2f370a6d33 | ||
|
|
027ae49449 | ||
|
|
6989899338 | ||
|
|
b05c7469ce | ||
|
|
c5540941a6 | ||
|
|
12a5a0d792 | ||
|
|
792826f0cb | ||
|
|
68854f36ff | ||
|
|
463eaff47c | ||
|
|
30e74c408c | ||
|
|
af8dd22369 | ||
|
|
4f4c44c7d4 | ||
|
|
55d1a94947 | ||
|
|
33f3f01e56 | ||
|
|
d15d135e23 | ||
|
|
af69a0d5c3 | ||
|
|
3bdf296205 | ||
|
|
f5e9f305d0 | ||
|
|
050804a917 | ||
|
|
56cc7977f3 | ||
|
|
5195a049a1 | ||
|
|
52ea2ea352 | ||
|
|
7f3459d178 | ||
|
|
494ea192e7 | ||
|
|
6c42baca23 | ||
|
|
f18b219d0c | ||
|
|
72073494a1 | ||
|
|
fb19b7c9de | ||
|
|
88a3f0a6a7 | ||
|
|
ccf8e99a98 | ||
|
|
a22180f980 | ||
|
|
131afefe3a | ||
|
|
d880634d22 | ||
|
|
dc4aae643a | ||
|
|
1df5dfe6d3 | ||
|
|
0f6e5499f6 | ||
|
|
7df15c67d3 | ||
|
|
b10682c7f7 | ||
|
|
43d9fdc77e | ||
|
|
9f27e21bd4 | ||
|
|
2129790bda | ||
|
|
bd70f4cff2 | ||
|
|
fb5839f929 | ||
|
|
76e4ecb6d5 | ||
|
|
dc2abb1352 | ||
|
|
93b23a38dd | ||
|
|
bdddcd05cc | ||
|
|
1f33f7aad4 | ||
|
|
5dbfca0364 | ||
|
|
6525b591e2 | ||
|
|
79e615b5b1 | ||
|
|
9405e40d00 | ||
|
|
cdd9b8a3e4 | ||
|
|
e4ffae84a7 | ||
|
|
df611dd3db | ||
|
|
96feb5bd26 | ||
|
|
989fdbca49 | ||
|
|
88f7b3410e | ||
|
|
ef29e62d9b | ||
|
|
a9f746c1d3 | ||
|
|
b36d641e71 | ||
|
|
04146eeac9 | ||
|
|
3051763cbf | ||
|
|
df5010084f | ||
|
|
e9278ceaba | ||
|
|
0261a954de | ||
|
|
ad5bbdbee0 | ||
|
|
7f62a7993a | ||
|
|
04e842a2a5 | ||
|
|
3986200c74 | ||
|
|
b27d6bb29b | ||
|
|
ed72abcc5c | ||
|
|
64a146400f | ||
|
|
2d665e876e | ||
|
|
fb746b874c | ||
|
|
00eac81c2f | ||
|
|
0b404b9637 | ||
|
|
6a6dd8ad2a | ||
|
|
2e2335a922 | ||
|
|
d5d7cba6a5 | ||
|
|
a5d561b996 | ||
|
|
6b08527929 | ||
|
|
211ca59441 | ||
|
|
29811cd0dc | ||
|
|
e4a6cbc7e3 | ||
|
|
1bcf5a82a6 | ||
|
|
1adcada568 | ||
|
|
80606274ed | ||
|
|
fa270cf74c | ||
|
|
9221231e89 | ||
|
|
74f9ee4326 | ||
|
|
7d6ddc5e59 | ||
|
|
868db1e6f3 | ||
|
|
f210b2f9a6 | ||
|
|
9a642e465f | ||
|
|
0c1a48c9d4 | ||
|
|
56f3fd0a45 | ||
|
|
21f87f169a | ||
|
|
829cdcb826 | ||
|
|
3dc41f7d5f | ||
|
|
f68b372268 | ||
|
|
35bceac822 | ||
|
|
2892bbe93e | ||
|
|
c43d8fa958 | ||
|
|
8220c32142 | ||
|
|
13fa74b8cd | ||
|
|
d765f1078b | ||
|
|
37180ff2af | ||
|
|
766c11f900 | ||
|
|
3841b8ea8c | ||
|
|
bd5c33041d | ||
|
|
d36b6f08fe | ||
|
|
dc424c6970 | ||
|
|
7f63920933 | ||
|
|
a484f2a7fc | ||
|
|
ed3f8f85c8 | ||
|
|
9e8dc584eb | ||
|
|
146f183256 | ||
|
|
cc20e0bf35 | ||
|
|
876027ea02 | ||
|
|
34349ab4c1 | ||
|
|
a2bc237d79 | ||
|
|
3b5f1f2c5c | ||
|
|
2561e3e4d1 | ||
|
|
180e84d9e9 | ||
|
|
cc1f78058b | ||
|
|
6159456024 | ||
|
|
00ee0d807a | ||
|
|
78475e5a82 | ||
|
|
c26cc9503c | ||
|
|
c50cf54e33 | ||
|
|
3eb8af34fc | ||
|
|
172d571804 | ||
|
|
e337b9997c | ||
|
|
f436d91711 | ||
|
|
9a2a72132d | ||
|
|
358ce9e179 | ||
|
|
e4ba4621d0 | ||
|
|
25aa561cb5 | ||
|
|
9742f7516a | ||
|
|
8d7c938138 | ||
|
|
d7bf049058 | ||
|
|
f91e0a99d2 | ||
|
|
4ea40fe8a3 | ||
|
|
c82189d927 | ||
|
|
03ce651de6 | ||
|
|
710258094b | ||
|
|
ebb9da663a | ||
|
|
b383e672dd | ||
|
|
6053d9631f | ||
|
|
1ff5d64a78 | ||
|
|
d397c8ad39 | ||
|
|
974c3f9b09 | ||
|
|
90b0e811a4 | ||
|
|
ec6a86f8ef | ||
|
|
9edc3fb881 | ||
|
|
d5c77cda5b | ||
|
|
d019b3b57d | ||
|
|
2b699e6e81 | ||
|
|
0e1831d0f4 | ||
|
|
e1f0590eac | ||
|
|
90232977e2 | ||
|
|
5b1b74e06f | ||
|
|
800313c2a0 | ||
|
|
0326476d4b | ||
|
|
c08af894b9 | ||
|
|
5e7b34a4c7 | ||
|
|
3dbad7a55b | ||
|
|
2f073470df | ||
|
|
97a229a438 | ||
|
|
8162933711 | ||
|
|
7e92308b70 | ||
|
|
f8540de48e | ||
|
|
742fbd111f | ||
|
|
8b5cfb48c1 | ||
|
|
b5b26a6d13 | ||
|
|
2e4d6b0b2e | ||
|
|
bf88aed318 | ||
|
|
a97ed62e2a | ||
|
|
67406ef6cd | ||
|
|
bbb4a9b5fb | ||
|
|
56ffd896dc | ||
|
|
693f404f4c | ||
|
|
043e7fbb16 | ||
|
|
3520ca5ef3 | ||
|
|
289c70d884 | ||
|
|
603810da5e | ||
|
|
d0989cd0f5 | ||
|
|
973d7706bd | ||
|
|
f722aafc18 | ||
|
|
d825a3348b | ||
|
|
a569a7bc7c | ||
|
|
8b957a128f | ||
|
|
259ac96bc3 | ||
|
|
c77a3b11a8 | ||
|
|
0e50e47f16 | ||
|
|
6194c2a625 | ||
|
|
59e1512cfc | ||
|
|
8e96a8931e | ||
|
|
b14c27c7bb | ||
|
|
8a3aacc00c | ||
|
|
5ac4cc8586 | ||
|
|
84e9835ed2 | ||
|
|
a62b828120 | ||
|
|
5d10b7582a | ||
|
|
27f44a3662 | ||
|
|
f20f8b365a | ||
|
|
78cea7f7c9 | ||
|
|
d9075a5d79 | ||
|
|
09c9c184ab | ||
|
|
daffc95c96 | ||
|
|
a12ba8e56f | ||
|
|
58fafac958 | ||
|
|
0f6e084640 | ||
|
|
e941f2adde | ||
|
|
a3b0c0472a | ||
|
|
e0c407a8a3 | ||
|
|
ce1256304c | ||
|
|
84c0c7e678 | ||
|
|
952859529d | ||
|
|
2e149c7a0e | ||
|
|
6edd804731 | ||
|
|
cfa966d58c | ||
|
|
9f805b9e46 | ||
|
|
120dac6dbc | ||
|
|
16b6df18a5 | ||
|
|
eb50278d1e | ||
|
|
bfc7a74a66 | ||
|
|
b97177363a | ||
|
|
217563740e | ||
|
|
b116df770c | ||
|
|
e836492a80 | ||
|
|
3db8b00898 | ||
|
|
cbaa765154 | ||
|
|
c506692d96 | ||
|
|
04108ff656 | ||
|
|
028a401931 | ||
|
|
aead181fb7 | ||
|
|
f512f0a949 | ||
|
|
77d266bdef | ||
|
|
d73ff02749 | ||
|
|
afae472e63 | ||
|
|
0989bbca36 | ||
|
|
e6f53ac243 | ||
|
|
c80cb601e0 | ||
|
|
f1a53a1255 | ||
|
|
d197f0f6e7 | ||
|
|
f8a647d181 | ||
|
|
21aa95b139 | ||
|
|
968efb97d4 | ||
|
|
ee1095a87e | ||
|
|
573e79322e | ||
|
|
a123e05557 | ||
|
|
aac6066e20 | ||
|
|
14969c5822 | ||
|
|
8fbd465a2e | ||
|
|
005f11b00d | ||
|
|
36bc493a43 | ||
|
|
79271cb41b | ||
|
|
fb11710bdb | ||
|
|
ee8ee2a659 | ||
|
|
70b152b548 | ||
|
|
ce774539b7 | ||
|
|
6670f2fd50 | ||
|
|
a834f210a0 | ||
|
|
7f0a430ec0 | ||
|
|
f5700ef742 | ||
|
|
58b0e21040 | ||
|
|
caaae17dca | ||
|
|
98ae22bd1b | ||
|
|
ef4806f71c | ||
|
|
1de7b8cefd | ||
|
|
5dff187a32 | ||
|
|
5b2a4cc696 | ||
|
|
7eac2ce436 | ||
|
|
36b72ec436 | ||
|
|
a06bd43a1a | ||
|
|
552ea582d6 | ||
|
|
2eaebbd1db | ||
|
|
acfc604435 | ||
|
|
2bee4a8167 | ||
|
|
0ab296a385 | ||
|
|
c9812e7682 | ||
|
|
3c157c4a31 | ||
|
|
ca17b64237 | ||
|
|
5206366ddf | ||
|
|
17e5f63149 | ||
|
|
ccb1f08345 | ||
|
|
a87ab490a3 | ||
|
|
5d26caa15a | ||
|
|
d109090bcf | ||
|
|
4ea4876644 | ||
|
|
8433248c56 | ||
|
|
3bdfa7e405 | ||
|
|
3bddb26b48 | ||
|
|
ef4b5cc9d5 | ||
|
|
bea10f7bc8 | ||
|
|
e8608ac830 | ||
|
|
2ecedb6535 | ||
|
|
a6f17f18a2 | ||
|
|
96fb6c39f4 | ||
|
|
6e26d31ac6 | ||
|
|
77ec1e9e48 | ||
|
|
ea8b1aa34c | ||
|
|
bbed94d6de | ||
|
|
23a5c845b0 |
@@ -1,9 +1,6 @@
|
||||
name: checks
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
checks-impure:
|
||||
runs-on: nix
|
||||
|
||||
@@ -14,16 +14,40 @@ jobs:
|
||||
- name: Update clan-core for checks
|
||||
run: nix run .#update-clan-core-for-checks
|
||||
- name: Create pull request
|
||||
env:
|
||||
CI_BOT_TOKEN: ${{ secrets.CI_BOT_TOKEN }}
|
||||
run: |
|
||||
git commit -am ""
|
||||
git push origin HEAD:update-clan-core-for-checks
|
||||
curl -X POST \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
export GIT_AUTHOR_NAME=clan-bot GIT_AUTHOR_EMAIL=clan-bot@clan.lol GIT_COMMITTER_NAME=clan-bot GIT_COMMITTER_EMAIL=clan-bot@clan.lol
|
||||
git commit -am "Update pinned clan-core for checks"
|
||||
git push origin +HEAD:update-clan-core-for-checks
|
||||
set -x
|
||||
resp=$(nix run --inputs-from . nixpkgs#curl -- -X POST \
|
||||
-H "Authorization: token $CI_BOT_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"head": "update-clan-core-branch",
|
||||
"head": "update-clan-core-for-checks",
|
||||
"base": "main",
|
||||
"title": "Automated Update: Clan Core",
|
||||
"body": "This PR updates the pinned clan-core for checks."
|
||||
"title": "Update Clan Core for Checks",
|
||||
"body": "This PR updates the pinned clan-core flake input that is used for checks."
|
||||
}' \
|
||||
"${GITEA_SERVER_URL}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/pulls"
|
||||
"https://git.clan.lol/api/v1/repos/clan/clan-core/pulls")
|
||||
pr_number=$(echo "$resp" | jq -r '.number')
|
||||
|
||||
# Merge when succeed
|
||||
while true; do
|
||||
resp=$(nix run --inputs-from . nixpkgs#curl -- -X POST \
|
||||
-H "Authorization: token $CI_BOT_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"Do": "merge",
|
||||
"merge_when_checks_succeed": true,
|
||||
"delete_branch_after_merge": true
|
||||
}' \
|
||||
"https://git.clan.lol/api/v1/repos/clan/clan-core/pulls/$pr_number/merge")
|
||||
msg=$(echo $resp | jq -r '.message')
|
||||
if [[ "$msg" != "Please try again later" ]]; then
|
||||
break
|
||||
fi
|
||||
echo "Retrying in 2 seconds..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
30
.gitignore
vendored
30
.gitignore
vendored
@@ -1,24 +1,24 @@
|
||||
.direnv
|
||||
**/.nixos-test-history
|
||||
***/.hypothesis
|
||||
.nixos-test-history
|
||||
.hypothesis
|
||||
out.log
|
||||
.coverage.*
|
||||
**/qubeclan
|
||||
qubeclan
|
||||
pkgs/repro-hook
|
||||
**/testdir
|
||||
testdir
|
||||
democlan
|
||||
example_clan
|
||||
**/result
|
||||
/pkgs/clan-cli/clan_cli/nixpkgs
|
||||
result*
|
||||
/pkgs/clan-cli/clan_lib/nixpkgs
|
||||
/pkgs/clan-cli/clan_cli/webui/assets
|
||||
nixos.qcow2
|
||||
**/*.glade~
|
||||
*.glade~
|
||||
/docs/out
|
||||
/pkgs/clan-cli/clan_cli/select
|
||||
**/.local.env
|
||||
/pkgs/clan-cli/clan_lib/select
|
||||
.local.env
|
||||
|
||||
# MacOS stuff
|
||||
**/.DS_store
|
||||
# macOS stuff
|
||||
.DS_Store
|
||||
|
||||
# dream2nix
|
||||
.dream2nix
|
||||
@@ -46,3 +46,11 @@ dist
|
||||
|
||||
# TODO: remove after bug in select is fixed
|
||||
select
|
||||
|
||||
# Generated files
|
||||
pkgs/clan-app/ui/api/API.json
|
||||
pkgs/clan-app/ui/api/API.ts
|
||||
pkgs/clan-app/ui/api/Inventory.ts
|
||||
pkgs/clan-app/ui/api/modules_schemas.json
|
||||
pkgs/clan-app/ui/api/schema.json
|
||||
pkgs/clan-app/ui/.fonts
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Contributing to Clan
|
||||
|
||||
<!-- Local file: docs/CONTRIBUTING.md -->
|
||||
Go to the Contributing guide at https://docs.clan.lol/manual/contribute/
|
||||
Go to the Contributing guide at https://docs.clan.lol/guides/contributing/CONTRIBUTING
|
||||
@@ -24,7 +24,7 @@ If you're new to Clan and eager to dive in, start with our quickstart guide and
|
||||
|
||||
In the Clan ecosystem, security is paramount. Learn how to handle secrets effectively:
|
||||
|
||||
- **Secrets Management**: Securely manage secrets by consulting [secrets](https://docs.clan.lol/getting-started/secrets/)<!-- [secrets.md](docs/site/getting-started/secrets.md) -->.
|
||||
- **Secrets Management**: Securely manage secrets by consulting [secrets](https://docs.clan.lol/guides/getting-started/secrets/)<!-- [secrets.md](docs/site/guides/getting-started/secrets.md) -->.
|
||||
|
||||
### Contributing to Clan
|
||||
|
||||
|
||||
64
checks/admin/default.nix
Normal file
64
checks/admin/default.nix
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
pkgs,
|
||||
self,
|
||||
clanLib,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII6zj7ubTg6z/aDwRNwvM/WlQdUocMprQ8E92NWxl6t+ test@test";
|
||||
in
|
||||
|
||||
clanLib.test.makeTestClan {
|
||||
inherit pkgs self;
|
||||
nixosTest = (
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
name = "admin";
|
||||
|
||||
clan = {
|
||||
directory = ./.;
|
||||
modules."@clan/admin" = ../../clanServices/admin/default.nix;
|
||||
inventory = {
|
||||
|
||||
machines.client = { };
|
||||
machines.server = { };
|
||||
|
||||
instances = {
|
||||
ssh-test-one = {
|
||||
module.name = "@clan/admin";
|
||||
roles.default.machines."server".settings = {
|
||||
allowedKeys.testkey = public-key;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nodes = {
|
||||
client.environment.etc.private-test-key.source = ./private-test-key;
|
||||
|
||||
server = {
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings.UsePAM = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
machines = [client, server]
|
||||
for m in machines:
|
||||
m.systemctl("start network-online.target")
|
||||
|
||||
for m in machines:
|
||||
m.wait_for_unit("network-online.target")
|
||||
|
||||
client.succeed(f"ssh -F /dev/null -i /etc/private-test-key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes root@server true &>/dev/null")
|
||||
'';
|
||||
}
|
||||
);
|
||||
}
|
||||
8
checks/admin/private-test-key
Normal file
8
checks/admin/private-test-key
Normal file
@@ -0,0 +1,8 @@
|
||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACCOs4+7m04Os/2g8ETcLzP1pUHVKHDKa0PBPdjVsZerfgAAAJDXdRkm13UZ
|
||||
JgAAAAtzc2gtZWQyNTUxOQAAACCOs4+7m04Os/2g8ETcLzP1pUHVKHDKa0PBPdjVsZerfg
|
||||
AAAECIgb2FQcgBKMniA+6zm2cwGre60ATu3Sg1GivgAqVJlI6zj7ubTg6z/aDwRNwvM/Wl
|
||||
QdUocMprQ8E92NWxl6t+AAAAC3BpbnBveEBraXdpAQI=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
|
||||
6
checks/admin/sops/machines/server/key.json
Executable file
6
checks/admin/sops/machines/server/key.json
Executable file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"publickey": "age1q4e7nsw5z6mqeqk5u5kug8lwhpq3f276s0t0npwfffwdkfh58gkqxknhjg",
|
||||
"type": "age"
|
||||
}
|
||||
]
|
||||
15
checks/admin/sops/secrets/server-age.key/secret
Normal file
15
checks/admin/sops/secrets/server-age.key/secret
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:ET/FggP6t7L60krfVRvtMjv++xr3zqRsJ58AfnPS1zjTovV5tE9RgnboGY1ieS7fCs4VOL2S6ELtwV1+BTLDQX9s0c5A9cKqjnc=,iv:6EQ6DOqxUdHcOziTxf8kl0sp1Pggu720s5BJ8zA9Je0=,tag:hQMPWaWb4igqDYjwNehlqQ==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRWjhuZkgwNEZTL3JXZHFE\nTC9jSXJGcVd2bnkvOE1qV0d6TzNobFZobndvCmF1UmhVUWtKeVVwS29NY21ONkRn\nZU5sM01kTU9rQVNENi9paUFWbERoWnMKLS0tIEdjZzgwQjFtWlVtRGZwdW9GY0FK\nSER1TTFNVGxFa0ZrclR4MitWVERiSGMK9DNLzlJZelcpP0klwSDMggTAy5ZVOmsZ\niuu8dXMSdIeTd7l8rpZZN27BaKUm8yEDpUmot5Vq9rbZl6SO3ncX+A==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-05-07T11:45:41Z",
|
||||
"mac": "ENC[AES256_GCM,data:m8eTnPtMzrooEah43mvjwHxQIwR/aq+A1wYyG/rQ75COq/TQepfMiDSrCJKW8x+OKmN/3HZs1b9k659jNNMF+RtMag0+/ovTmr7PQux3IkzWl+R2kU3Y7WDOMweBKY3mTMu6reICE1YVME8vJwhDDbA5JCXJv64rkTz2tfGt4CQ=,iv:/vrwJyEVsfm1cUK//TesY24Makt8YI8mwx5GIhn4038=,tag:H2tS9ohvWJ4TWB6LghcZNg==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
1
checks/admin/sops/secrets/server-age.key/users/admin
Symbolic link
1
checks/admin/sops/secrets/server-age.key/users/admin
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../users/admin
|
||||
4
checks/admin/sops/users/admin/key.json
Normal file
4
checks/admin/sops/users/admin/key.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"type": "age"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICVVQjCEuryZii1LmJyjx9DX44eJh3qwTTEWlahYONsz nixbld@kiwi
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/machines/server
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:yH7IQixe4nudnK4QOsr7VYoJ1YrVLP0Ufvgu7TNWSJnc55khKZHvQiDIlxzCIrAyMgUYwPNmrrZn9PZhgjAQZm7/o6SmP91Efb0yWM55o861El6v59yw0fseo3z6xAisjlg3KwTd5KMrRhzT0HzrjLn89SYRVh7DAWK+Cs7HVGvKVJ1E6AWiJmFPXIB7YaqJ7P4jZW9u7bEMCZabsRRqgS8dWXVXw9VS5ll4bNYQY4x5p2eg6e81zdeY2Y9Gbi5ty1Whqpzko2Pvggu6K4zUDXikM4lWggvIXzfrJA7HNE3xzXw94J45woj1y5FVOzn1Ve5kCc8PjVGaJ32poGkZiiD07kd5PxZuyVexREJpgz29lyB6nRJJeau4gpSG1VHOyNdwwBsBBm+zn6v2rlVzJPTlqmCV1+5UKf8JZKziIDFfi/78kSdtaeX+miJJvyDRkqNpQ7htEI0TAS8yQrkjWEIyaPAWQ2Usa8g1UrEftTlGUi/aMC2ob0qTLQQbhNhlSV/dImzI/qRMqSy2RWeS,iv:EuprKOFKzNLZrGlPtU2mEjmtNPNOcuVDbuvrtYyrerc=,tag:ny/q1AMHIQ8OgUNEE0Cc8w==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1q4e7nsw5z6mqeqk5u5kug8lwhpq3f276s0t0npwfffwdkfh58gkqxknhjg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLODFxUjREa2tOYW9xaHYw\nQlhWZ282UVhiOGRndk0xYnlCQWRYR01qS2hJCllySUZyblJmTkgyZXd5bjVINDBo\nbEhIWmxycVdOVW0xTUxkalF5Y1k2bXcKLS0tIGRRS1VqOG5sanh2dXR5a2FGeXRs\nK3ZUdERCdEkvMmt3ZndPZEM3QUxJZzAKutOr9jHPCL86zEdMWJ6YZmplcr4tDAcN\nncQfC5rddYDW+0y/crwepKTa2FZjQheOY7jobZanU19ai521hqDSVw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxc3NxNGhRYmU3eFNodDZ4\ndnNTeHFnNXBKbUxmNHBjRlFpNG0zdVNpS2d3CjhrOUlSQU5BZVlSdWR3dnNyODZO\nRFBKZWpwWHlOUW03OGlVZlRQUmMrMzQKLS0tIEd6ei9LU3ZFTzlWTUk1c3huS1RQ\nbG1vQzI4ODJkeFcyRnJaQWp1Wk9zSkUKXefMOk/ZT4P6DItfnM82RoOvX4SBn7Fn\nlAoMnSzaRCunDwq7ha05G45gcI2Wjv3urjt0tmdmrmTnFtBSSt23TQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-05-07T11:45:47Z",
|
||||
"mac": "ENC[AES256_GCM,data:ORCANHbEX13O+zBVLOYyPxYIr1RS3NybTBb23ES7RbiGhSl2t/TXcfPWU5Smuqee0tfcrxL0u1FELZta4IysySW54JlD2907E9OUJWlQ6seOxADla4TMukW2pwhSsUJ9XfjEwC07zYB0alHzO3pY+LG3OAWzyhAlWzHlB5+WqIA=,iv:As+CjAJxKht0PJs3S2WWzho7UBqaUUltBIrYvlzBAbM=,tag:PSyUKaPZZNCxqd6XLPJSCw==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/users/admin
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/machines/server
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:5Fa0TQN/Whj311JZuVWXnp+2KJaNZPb/TOnP23T+KktulabcBA9go+/F+8wJbsEH2mf6UDq656p6C+kLIvfBFl2O/WwSOhsl23as9TLbgB6gBq73GjyV81VFsnLYNLHKMq+8nfJHM/WekA==,iv:n5vz3q5N6DplLWibdiCcYDdiN7q1VggzPoIYy9r2ZJw=,tag:FoGXrrJfjHZCUVTS2RESmw==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1q4e7nsw5z6mqeqk5u5kug8lwhpq3f276s0t0npwfffwdkfh58gkqxknhjg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBheXZvUW9YbjBFMi9mZnVk\ncGFPQzFOZkNPMU1HckhtSGtDWExpWVNYRlV3CjdDaDlSd2wzVnhKZGU0aFY0UnZY\nQStPSkxuSmlyOU9aeUdRaEJ2UTRRSm8KLS0tIFd3SG9YdEU5T2tzNk16b2s1SUNj\nWkh2cng5eWd3ZmxVZDhSR2Y1QnFySDgKGb/t+8NqiSGgmFOJc1NmDYZ+PXlANy8V\nuFwUTeqWAv7pOiGC8oessfyTPaJ7gWjz+XfKV5JVVikK2l3J4eAGxg==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWM0daWmxCTjAyQStwQ2lM\nNkcyZW9hRmpDelRJR0VVTWhNTGFuZWhCc1RJCm81ZXowZjBhWGpIQTBhQnZLSmQy\nVUNNYjI0bVpqQ21YZS95TW53OUx1YUkKLS0tIDRUUE1zczBDeFJTOTQyVXVkMkYy\ncVVTN3J6TWtwcXVpM0M5c0gxUXpmV2cKwlWrbGLtkO2+PXKoMoHTV5aJpnfVy3RP\n6i8DDpLPGYfVUtWxHx+L+NmMxmw1AvmKSbdB4Y7aSbBW2mea3j1YCg==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-05-07T11:45:50Z",
|
||||
"mac": "ENC[AES256_GCM,data:rwdbGOg8l8fWT2GYFx+PgV3oPxt5+NCHJf3PhG3V2lrRMPRisyf1nKwDsYavTuhv+bZC/qo4LrGylcXsHWdkCe/xBX+/jYLMf6nJZPk8BPzfUpiDnEKwRl05qfRfkIDusnQrlBrE+tqtcool65js7hYIzSi92O/hxbzzfsCUpqk=,iv:lUTNJkr6Zh3MQm/h7Ven4N6xVn4VeTXOEKzxd0HSsCk=,tag:Bwbi4HD9vzso6306y7EZOg==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/users/admin
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:sPh+BuT2we+d/GaMv4zPWc3rPhlMsJQC,iv:VwcHUOMaNiao+R8RBtUINffEUhutktKD6KEWLkFxyp4=,tag:SNVKLjjDv+u5XTVczs2/Uw==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJVWNYRGEwVWxDSmE4bTNL\nRlZPeGZabFZZNGFsMEwzV1ZmT1pqNVk4STMwCkg5UER0Vjk3K1RMazVVYjF3SDc2\ndDZHa3VtYjRiWUJET25weXprc0JNUjAKLS0tIDdVb2xNdWxCcjhpSGtGWDV0d2ti\nZENkZGNpSTNzMVVTZVN0ZktLc2VackEKdexhI37pwcnbZbcy30k9Uo5Z7z3NLqlx\nspxJ87SzEwdStTMhiH1iYf62vcyAOTa4HwfXu97MGVPFNw13/VfgCw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-05-07T11:45:50Z",
|
||||
"mac": "ENC[AES256_GCM,data:tZRh8qj7JUnhXCfqCHJKWEFQ8XLtmo/p0C+eFIK+34enxfB5lG5Lq83wBXLa0D/nqrr58z1rLO+UVDOI5LH1jFxARBZZnUKrVJNTDHa5pUnlnVOFEOoc+R0h2E5Xw9OHaq7aDUh4fT9+gNDpguKggI5fS9KqRnmZ4VrpNccjnkw=,iv:2yI25fcWMog91EMD7bYQy3GS30a7gZHnif93MaE3sZo=,tag:tYqa6zssiU3BCFU5xmDYZQ==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/users/admin
|
||||
@@ -1,6 +1,6 @@
|
||||
{ fetchgit }:
|
||||
fetchgit {
|
||||
url = "https://git.clan.lol/clan/clan-core.git";
|
||||
rev = "1e8b9def2a021877342491ca1f4c45533a580759";
|
||||
sha256 = "0f12vwr1abwa1iwjbb5z5xx8jlh80d9njwdm6iaw1z1h2m76xgzc";
|
||||
rev = "4b44892b476b32b1ca7d2f637da41562b8ed5456";
|
||||
sha256 = "15k7dp3m9dcvx75sm900xp70vss2pnx0ywjnpmqyqlmwpvzn663p";
|
||||
}
|
||||
|
||||
@@ -34,27 +34,33 @@ in
|
||||
inherit self;
|
||||
inherit (self) clanLib;
|
||||
};
|
||||
nixosTests = lib.optionalAttrs (pkgs.stdenv.isLinux) {
|
||||
# Deltachat is currently marked as broken
|
||||
# deltachat = import ./deltachat nixosTestArgs;
|
||||
nixosTests =
|
||||
lib.optionalAttrs (pkgs.stdenv.isLinux) {
|
||||
# Deltachat is currently marked as broken
|
||||
# deltachat = import ./deltachat nixosTestArgs;
|
||||
|
||||
# Base Tests
|
||||
secrets = self.clanLib.test.baseTest ./secrets nixosTestArgs;
|
||||
borgbackup = self.clanLib.test.baseTest ./borgbackup nixosTestArgs;
|
||||
wayland-proxy-virtwl = self.clanLib.test.baseTest ./wayland-proxy-virtwl nixosTestArgs;
|
||||
# Base Tests
|
||||
secrets = self.clanLib.test.baseTest ./secrets nixosTestArgs;
|
||||
borgbackup = self.clanLib.test.baseTest ./borgbackup nixosTestArgs;
|
||||
wayland-proxy-virtwl = self.clanLib.test.baseTest ./wayland-proxy-virtwl nixosTestArgs;
|
||||
|
||||
# Container Tests
|
||||
container = self.clanLib.test.containerTest ./container nixosTestArgs;
|
||||
zt-tcp-relay = self.clanLib.test.containerTest ./zt-tcp-relay nixosTestArgs;
|
||||
matrix-synapse = self.clanLib.test.containerTest ./matrix-synapse nixosTestArgs;
|
||||
postgresql = self.clanLib.test.containerTest ./postgresql nixosTestArgs;
|
||||
# Container Tests
|
||||
container = self.clanLib.test.containerTest ./container nixosTestArgs;
|
||||
zt-tcp-relay = self.clanLib.test.containerTest ./zt-tcp-relay nixosTestArgs;
|
||||
matrix-synapse = self.clanLib.test.containerTest ./matrix-synapse nixosTestArgs;
|
||||
postgresql = self.clanLib.test.containerTest ./postgresql nixosTestArgs;
|
||||
|
||||
# Clan Tests
|
||||
mumble = import ./mumble nixosTestArgs;
|
||||
dummy-inventory-test = import ./dummy-inventory-test nixosTestArgs;
|
||||
data-mesher = import ./data-mesher nixosTestArgs;
|
||||
syncthing = import ./syncthing nixosTestArgs;
|
||||
};
|
||||
# Clan Tests
|
||||
dummy-inventory-test = import ./dummy-inventory-test nixosTestArgs;
|
||||
admin = import ./admin nixosTestArgs;
|
||||
data-mesher = import ./data-mesher nixosTestArgs;
|
||||
syncthing = import ./syncthing nixosTestArgs;
|
||||
}
|
||||
// lib.optionalAttrs (pkgs.stdenv.hostPlatform.system == "aarch64-linux") {
|
||||
# for some reason this hangs in an odd place in CI, but it works on my machine ...
|
||||
# on aarch64-linux it works though
|
||||
mumble = import ./mumble nixosTestArgs;
|
||||
};
|
||||
|
||||
packagesToBuild = lib.removeAttrs self'.packages [
|
||||
# exclude the check that checks that nothing depends on the repo root
|
||||
|
||||
@@ -47,6 +47,20 @@ clanLib.test.makeTestClan {
|
||||
nodes.peer2 = common;
|
||||
|
||||
testScript = ''
|
||||
import time
|
||||
import re
|
||||
|
||||
|
||||
def machine_has_text(machine: Machine, regex: str) -> bool:
|
||||
variants = machine.get_screen_text_variants()
|
||||
# for debugging
|
||||
# machine.screenshot(f"/tmp/{machine.name}.png")
|
||||
for text in variants:
|
||||
print(f"Expecting '{regex}' in '{text}'")
|
||||
if re.search(regex, text) is not None:
|
||||
return True
|
||||
return False
|
||||
|
||||
start_all()
|
||||
|
||||
with subtest("Waiting for x"):
|
||||
@@ -63,41 +77,53 @@ clanLib.test.makeTestClan {
|
||||
peer2.execute("mumble >&2 &")
|
||||
|
||||
with subtest("Wait for Mumble"):
|
||||
peer1.wait_for_window(r"^Mumble$")
|
||||
peer2.wait_for_window(r"^Mumble$")
|
||||
peer1.wait_for_window(r"Mumble")
|
||||
peer2.wait_for_window(r"Mumble")
|
||||
|
||||
with subtest("Wait for certificate creation"):
|
||||
peer1.wait_for_window(r"^Mumble$")
|
||||
peer1.sleep(3) # mumble is slow to register handlers
|
||||
peer1.send_chars("\n")
|
||||
peer1.send_chars("\n")
|
||||
peer2.wait_for_window(r"^Mumble$")
|
||||
peer2.sleep(3) # mumble is slow to register handlers
|
||||
peer2.send_chars("\n")
|
||||
peer2.send_chars("\n")
|
||||
peer1.wait_for_window(r"Mumble")
|
||||
peer2.wait_for_window(r"Mumble")
|
||||
|
||||
with subtest("Wait for server connect"):
|
||||
peer1.wait_for_window(r"^Mumble Server Connect$")
|
||||
peer2.wait_for_window(r"^Mumble Server Connect$")
|
||||
for i in range(20):
|
||||
time.sleep(1)
|
||||
peer1.send_chars("\n")
|
||||
peer1.send_chars("\n")
|
||||
peer2.send_chars("\n")
|
||||
peer2.send_chars("\n")
|
||||
if machine_has_text(peer1, r"Mumble Server Connect") and \
|
||||
machine_has_text(peer2, r"Mumble Server Connect"):
|
||||
break
|
||||
else:
|
||||
raise Exception("Timeout waiting for certificate creation")
|
||||
|
||||
with subtest("Check validity of server certificates"):
|
||||
peer1.execute("killall .mumble-wrapped")
|
||||
peer1.sleep(1)
|
||||
peer1.execute("mumble mumble://peer2 >&2 &")
|
||||
peer1.wait_for_window(r"^Mumble$")
|
||||
peer1.sleep(3) # mumble is slow to register handlers
|
||||
peer1.send_chars("\n")
|
||||
peer1.send_chars("\n")
|
||||
peer1.wait_for_text("Connected.")
|
||||
peer1.wait_for_window(r"Mumble")
|
||||
|
||||
for i in range(20):
|
||||
time.sleep(1)
|
||||
peer1.send_chars("\n")
|
||||
peer1.send_chars("\n")
|
||||
if machine_has_text(peer1, "Connected."):
|
||||
break
|
||||
else:
|
||||
raise Exception("Timeout waiting for certificate creation")
|
||||
|
||||
peer2.execute("killall .mumble-wrapped")
|
||||
peer2.sleep(1)
|
||||
peer2.execute("mumble mumble://peer1 >&2 &")
|
||||
peer2.wait_for_window(r"^Mumble$")
|
||||
peer2.sleep(3) # mumble is slow to register handlers
|
||||
peer2.send_chars("\n")
|
||||
peer2.send_chars("\n")
|
||||
peer2.wait_for_text("Connected.")
|
||||
peer2.wait_for_window(r"Mumble")
|
||||
|
||||
for i in range(20):
|
||||
time.sleep(1)
|
||||
peer2.send_chars("\n")
|
||||
peer2.send_chars("\n")
|
||||
if machine_has_text(peer2, "Connected."):
|
||||
break
|
||||
else:
|
||||
raise Exception("Timeout waiting for certificate creation")
|
||||
'';
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
description = "Convenient Administration for the Clan App"
|
||||
categories = ["Utility"]
|
||||
features = [ "inventory" ]
|
||||
features = [ "inventory", "deprecated" ]
|
||||
---
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# Dont import this file
|
||||
# It is only here for backwards compatibility.
|
||||
# Dont author new modules with this file.
|
||||
{
|
||||
imports = [ ./roles/default.nix ];
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{ lib, config, ... }:
|
||||
{
|
||||
|
||||
options.clan.admin = {
|
||||
allowedKeys = lib.mkOption {
|
||||
default = { };
|
||||
|
||||
@@ -4,7 +4,7 @@ description = "Statically configure borgbackup with sane defaults."
|
||||
!!! Danger "Deprecated"
|
||||
Use [borgbackup](borgbackup.md) instead.
|
||||
|
||||
Don't use borgbackup-static through [inventory](../../manual/inventory.md).
|
||||
Don't use borgbackup-static through [inventory](../../guides/inventory.md).
|
||||
|
||||
This module implements the `borgbackup` backend and implements sane defaults
|
||||
for backup management through `borgbackup` for members of the clan.
|
||||
|
||||
@@ -12,13 +12,16 @@ let
|
||||
# currently only supports zerotier
|
||||
defaultBootstrapNodes = builtins.foldl' (
|
||||
urls: name:
|
||||
if
|
||||
builtins.pathExists "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value"
|
||||
then
|
||||
let
|
||||
|
||||
ipPath = "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value";
|
||||
|
||||
in
|
||||
if builtins.pathExists ipPath then
|
||||
let
|
||||
ip = builtins.readFile "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value";
|
||||
ip = builtins.readFile ipPath;
|
||||
in
|
||||
urls ++ "${ip}:${cfg.network.port}"
|
||||
urls ++ [ "[${ip}]:${builtins.toString cfg.network.port}" ]
|
||||
else
|
||||
urls
|
||||
) [ ] (dmLib.machines config).bootstrap;
|
||||
@@ -87,7 +90,8 @@ in
|
||||
push_pull_interval = "30s";
|
||||
|
||||
interface = cfg.network.interface;
|
||||
bootstrap_nodes = cfg.bootstrapNodes or defaultBootstrapNodes;
|
||||
|
||||
bootstrap_nodes = if cfg.bootstrapNodes == null then defaultBootstrapNodes else cfg.bootstrapNodes;
|
||||
};
|
||||
|
||||
http.port = 7331;
|
||||
|
||||
@@ -8,8 +8,8 @@ in
|
||||
{
|
||||
# only import available files, as this allows to filter the files for tests.
|
||||
flake.clanModules = filterAttrs (_name: pathExists) {
|
||||
admin = ./admin;
|
||||
auto-upgrade = ./auto-upgrade;
|
||||
admin = ./admin;
|
||||
borgbackup = ./borgbackup;
|
||||
borgbackup-static = ./borgbackup-static;
|
||||
deltachat = ./deltachat;
|
||||
|
||||
@@ -10,7 +10,7 @@ After the system was installed/deployed the following command can be used to dis
|
||||
clan vars get [machine_name] root-password/root-password
|
||||
```
|
||||
|
||||
See also: [Vars](../../manual/vars-backend.md)
|
||||
See also: [Vars](../../guides/vars-backend.md)
|
||||
|
||||
To regenerate the password run:
|
||||
```
|
||||
|
||||
@@ -16,7 +16,7 @@ After the system was installed/deployed the following command can be used to dis
|
||||
clan vars get [machine_name] root-password/root-password
|
||||
```
|
||||
|
||||
See also: [Vars](../../manual/vars-backend.md)
|
||||
See also: [Vars](../../guides/vars-backend.md)
|
||||
|
||||
To regenerate the password run:
|
||||
```
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
description = "Configures Wifi networks to join"
|
||||
features = [ "inventory", "experimental" ]
|
||||
categories = [ "Network", "System" ]
|
||||
---
|
||||
|
||||
## Experimental wifi module
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./roles/default.nix
|
||||
];
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.clan.wifi;
|
||||
secret_path =
|
||||
network_name: config.clan.core.vars.generators."iwd.${network_name}".files.password.path;
|
||||
ssid_path = network_name: config.clan.core.vars.generators."iwd.${network_name}".files.ssid.path;
|
||||
secret_generator = name: value: {
|
||||
name = "iwd.${name}";
|
||||
value = {
|
||||
prompts.ssid.type = "line";
|
||||
prompts.ssid.persist = true;
|
||||
prompts.password.type = "hidden";
|
||||
prompts.password.persist = true;
|
||||
share = true;
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options.clan.wifi = {
|
||||
networks = lib.mkOption {
|
||||
visible = false;
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule (
|
||||
{ ... }:
|
||||
{
|
||||
options = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Enable this wifi network";
|
||||
};
|
||||
autoConnect = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Automatically try to join this wifi network";
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
default = { };
|
||||
description = "Wifi networks to predefine";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
(lib.mkIf (cfg.networks != { }) {
|
||||
|
||||
clan.core.vars.generators = lib.mapAttrs' secret_generator cfg.networks;
|
||||
|
||||
systemd.services.iwd.partOf = [ "nixos-activation.service" ];
|
||||
|
||||
/*
|
||||
script that generates iwd config files inside /var/lib/iwd/clan and symlinks
|
||||
them to /var/lib/iwd.
|
||||
*/
|
||||
systemd.services.iwd.serviceConfig.ExecStartPre = pkgs.writeShellScript "clan-iwd-setup" ''
|
||||
set -e
|
||||
|
||||
rm -rf /var/lib/iwd/clan
|
||||
mkdir -p /var/lib/iwd/clan
|
||||
|
||||
# remove all existing symlinks in /var/lib/iwd
|
||||
${pkgs.findutils}/bin/find /var/lib/iwd -type l -exec rm {} \;
|
||||
|
||||
${toString (
|
||||
lib.mapAttrsToList (name: network: ''
|
||||
passwd=$(cat "${secret_path name}")
|
||||
ssid=$(cat "${ssid_path name}")
|
||||
echo "
|
||||
[Settings]
|
||||
autoConnect=${if network.autoConnect then "true" else "false"}
|
||||
[Security]
|
||||
Passphrase=$passwd
|
||||
" > "/var/lib/iwd/clan/$ssid.psk"
|
||||
'') cfg.networks
|
||||
)}
|
||||
|
||||
# link all files in /var/lib/iwd/clan to /var/lib/iwd
|
||||
${pkgs.findutils}/bin/find /var/lib/iwd/clan -type f -exec ln -s {} /var/lib/iwd \;
|
||||
'';
|
||||
})
|
||||
{
|
||||
# disable wpa supplicant
|
||||
networking.wireless.enable = false;
|
||||
|
||||
# Set the network manager backend to iwd
|
||||
networking.networkmanager.wifi.backend = "iwd";
|
||||
|
||||
# Use iwd instead of wpa_supplicant. It has a user friendly CLI
|
||||
networking.wireless.iwd = {
|
||||
enable = true;
|
||||
settings = {
|
||||
Network = {
|
||||
EnableIPv6 = true;
|
||||
RoutePriorityOffset = 300;
|
||||
};
|
||||
Settings.autoConnect = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
}
|
||||
39
clanServices/admin/default.nix
Normal file
39
clanServices/admin/default.nix
Normal file
@@ -0,0 +1,39 @@
|
||||
{ ... }:
|
||||
{
|
||||
_class = "clan.service";
|
||||
manifest.name = "clan-core/admin";
|
||||
manifest.description = "Convenient Administration for the Clan App";
|
||||
manifest.categories = [ "Utility" ];
|
||||
|
||||
roles.default = {
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
options.allowedKeys = lib.mkOption {
|
||||
default = { };
|
||||
type = lib.types.attrsOf lib.types.str;
|
||||
description = "The allowed public keys for ssh access to the admin user";
|
||||
example = {
|
||||
"key_1" = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD...";
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
perInstance =
|
||||
{ settings, ... }:
|
||||
{
|
||||
nixosModule =
|
||||
{ ... }:
|
||||
{
|
||||
|
||||
imports = [
|
||||
../../clanModules/sshd
|
||||
../../clanModules/root-password
|
||||
];
|
||||
|
||||
users.users.root.openssh.authorizedKeys.keys = builtins.attrValues settings.allowedKeys;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
6
clanServices/admin/flake-module.nix
Normal file
6
clanServices/admin/flake-module.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
clan.modules = {
|
||||
admin = lib.modules.importApply ./default.nix { };
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./admin/flake-module.nix
|
||||
./hello-world/flake-module.nix
|
||||
./wifi/flake-module.nix
|
||||
];
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
{
|
||||
_class = "clan.service";
|
||||
manifest.name = "clan-core/hello-word";
|
||||
manifest.description = "This is a test";
|
||||
|
||||
roles.peer = {
|
||||
interface =
|
||||
@@ -10,6 +11,8 @@
|
||||
{
|
||||
options.foo = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
# default = "";
|
||||
description = "Some option";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
115
clanServices/wifi/default.nix
Normal file
115
clanServices/wifi/default.nix
Normal file
@@ -0,0 +1,115 @@
|
||||
{ packages }:
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
concatMapAttrsStringSep
|
||||
flip
|
||||
mapAttrs
|
||||
;
|
||||
in
|
||||
{
|
||||
_class = "clan.service";
|
||||
manifest.name = "wifi";
|
||||
|
||||
roles.default = {
|
||||
interface = {
|
||||
options.networks = lib.mkOption {
|
||||
visible = false;
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule (
|
||||
{ ... }:
|
||||
{
|
||||
options = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Enable this wifi network";
|
||||
};
|
||||
autoConnect = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
description = "Automatically try to join this wifi network";
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
default = { };
|
||||
description = "Wifi networks to predefine";
|
||||
};
|
||||
};
|
||||
|
||||
perInstance =
|
||||
{ settings, ... }:
|
||||
{
|
||||
nixosModule =
|
||||
{ pkgs, config, ... }:
|
||||
let
|
||||
password_path =
|
||||
network_name: config.clan.core.vars.generators."iwd.${network_name}".files.password.path;
|
||||
|
||||
ssid_path = network_name: config.clan.core.vars.generators."iwd.${network_name}".files.ssid.path;
|
||||
|
||||
secret_generator = name: value: {
|
||||
name = "iwd.${name}";
|
||||
value = {
|
||||
prompts.ssid.type = "line";
|
||||
prompts.ssid.persist = true;
|
||||
prompts.password.type = "hidden";
|
||||
prompts.password.persist = true;
|
||||
share = true;
|
||||
};
|
||||
};
|
||||
in
|
||||
lib.mkIf (settings.networks != { }) {
|
||||
|
||||
clan.core.vars.generators = lib.mapAttrs' secret_generator settings.networks;
|
||||
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
networking.networkmanager.ensureProfiles.environmentFiles = [
|
||||
"/run/secrets/NetworkManager/wifi-secrets"
|
||||
];
|
||||
|
||||
networking.networkmanager.ensureProfiles.profiles = flip mapAttrs settings.networks (
|
||||
name: _network: {
|
||||
connection.id = "$ssid_${name}";
|
||||
connection.type = "wifi";
|
||||
wifi.mode = "infrastructure";
|
||||
wifi.ssid = "$ssid_${name}";
|
||||
wifi-security.psk = "$pw_${name}";
|
||||
wifi-security.key-mgmt = "wpa-psk";
|
||||
}
|
||||
);
|
||||
|
||||
# service to generate the environment file containing all secrets, as
|
||||
# expected by the nixos NetworkManager-ensure-profile service
|
||||
systemd.services.NetworkManager-setup-secrets = {
|
||||
description = "Generate wifi secrets for NetworkManager";
|
||||
requiredBy = [ "NetworkManager-ensure-profiles.service" ];
|
||||
partOf = [ "NetworkManager-ensure-profiles.service" ];
|
||||
before = [ "NetworkManager-ensure-profiles.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = pkgs.writeShellScript "wifi-secrets" ''
|
||||
set -euo pipefail
|
||||
|
||||
env_file=/run/secrets/NetworkManager/wifi-secrets
|
||||
mkdir -p $(dirname "$env_file")
|
||||
: > "$env_file"
|
||||
|
||||
# Generate the secrets file
|
||||
echo "Generating wifi secrets file: $env_file"
|
||||
${flip (concatMapAttrsStringSep "\n") settings.networks (
|
||||
name: _network: ''
|
||||
echo "ssid_${name}=\"$(cat "${ssid_path name}")\"" >> /run/secrets/NetworkManager/wifi-secrets
|
||||
echo "pw_${name}=\"$(cat "${password_path name}")\"" >> /run/secrets/NetworkManager/wifi-secrets
|
||||
''
|
||||
)}
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
36
clanServices/wifi/flake-module.nix
Normal file
36
clanServices/wifi/flake-module.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
self,
|
||||
inputs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix {
|
||||
inherit (self) packages;
|
||||
};
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
wifi = module;
|
||||
};
|
||||
perSystem =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
/**
|
||||
1. Prepare the test vars
|
||||
nix run .#generate-test-vars -- clanServices/hello-world/tests/vm hello-service
|
||||
|
||||
2. To run the test
|
||||
nix build .#checks.x86_64-linux.hello-service
|
||||
*/
|
||||
checks =
|
||||
# Currently we don't support nixos-integration tests on darwin
|
||||
lib.optionalAttrs (pkgs.stdenv.isLinux) {
|
||||
wifi-service = import ./tests/vm/default.nix {
|
||||
inherit module;
|
||||
inherit self inputs pkgs;
|
||||
clanLib = self.clanLib;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
58
clanServices/wifi/tests/eval-tests.nix
Normal file
58
clanServices/wifi/tests/eval-tests.nix
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
module,
|
||||
clanLib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
testFlake = clanLib.buildClan {
|
||||
# Point to the folder of the module
|
||||
# TODO: make this optional in buildClan
|
||||
directory = ./..;
|
||||
|
||||
# Create some test machines
|
||||
machines.jon = {
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
};
|
||||
machines.sara = {
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
};
|
||||
|
||||
# Register the module for the test
|
||||
inventory.modules.wifi = module;
|
||||
|
||||
# Use the module in the test
|
||||
inventory.instances = {
|
||||
"default" = {
|
||||
module.name = "wifi";
|
||||
roles.default.tags.all = { };
|
||||
roles.default.settings.networks.one = { };
|
||||
roles.default.settings.networks.two = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
# NOTE:
|
||||
# If you wonder why 'self-zerotier-redux':
|
||||
# A local module has prefix 'self', otherwise it is the name of the 'input'
|
||||
# The rest is the name of the service as in the instance 'module.name';
|
||||
#
|
||||
# -> ${module.input}-${module.name}
|
||||
# In this case it is 'self-zerotier-redux'
|
||||
# This is usually only used internally, but we can use it to test the evaluation of service module in isolation
|
||||
# evaluatedService =
|
||||
# testFlake.clanInternals.inventoryClass.distributedServices.importedModulesEvaluated.self-zerotier-redux.config;
|
||||
in
|
||||
{
|
||||
test_simple = {
|
||||
inherit testFlake;
|
||||
|
||||
expr =
|
||||
testFlake.clanInternals.inventoryClass.distributedServices.importedModulesEvaluated.self-wifi.config;
|
||||
expected = 1;
|
||||
|
||||
# expr = {
|
||||
# };
|
||||
# expected = {
|
||||
#
|
||||
# };
|
||||
};
|
||||
}
|
||||
43
clanServices/wifi/tests/vm/default.nix
Normal file
43
clanServices/wifi/tests/vm/default.nix
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
pkgs,
|
||||
self,
|
||||
clanLib,
|
||||
module,
|
||||
...
|
||||
}:
|
||||
clanLib.test.makeTestClan {
|
||||
inherit pkgs self;
|
||||
useContainers = false;
|
||||
nixosTest = (
|
||||
{ ... }:
|
||||
{
|
||||
name = "wifi";
|
||||
|
||||
clan = {
|
||||
directory = ./.;
|
||||
modules."@clan/wifi" = module;
|
||||
inventory = {
|
||||
|
||||
machines.test = { };
|
||||
|
||||
instances = {
|
||||
wg-test-one = {
|
||||
module.name = "@clan/wifi";
|
||||
|
||||
roles.default.machines = {
|
||||
test.settings.networks.one = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
test.wait_for_unit("NetworkManager.service")
|
||||
psk = test.succeed("cat /run/NetworkManager/system-connections/one.nmconnection")
|
||||
assert "password-eins" in psk, "Password is incorrect"
|
||||
'';
|
||||
}
|
||||
);
|
||||
}
|
||||
6
clanServices/wifi/tests/vm/sops/machines/test/key.json
Executable file
6
clanServices/wifi/tests/vm/sops/machines/test/key.json
Executable file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"publickey": "age1aex07l3uafv5hdr0h2707jgfsxcu7yhlc7glw3qu26xzn3m9nazsu47jzs",
|
||||
"type": "age"
|
||||
}
|
||||
]
|
||||
15
clanServices/wifi/tests/vm/sops/secrets/test-age.key/secret
Normal file
15
clanServices/wifi/tests/vm/sops/secrets/test-age.key/secret
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:l5kJU4j1D/4TcPT0Ea0c1X3FWRbHCLCnWy22xeEWseBKnd5R8cEPAYflw+xqGNKpDpQOb0K5XCfA5+CFFXyl0oXEnmnIDDCmtqk=,iv:6cF445KqSJiaTfQ+eNqKH4dAFiIaqdSqt1alF80GpFU=,tag:4Fz+MtxiLmV31Nn6NUVAzg==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsOVlvZVdoWDBpNEdRb0U1\nRVRpS0xhaElYVUg1OUJWUlF5a3A1ZWUxeGxJClVjNDNsM2xXWDhsMktYOU1pdUZD\nY3VFeVowbDFmR2dFY2NUc3pEOGFUUU0KLS0tIE9pT0xZMFdwRU5VekNNWmpKQWNh\naTk2eGhGL3QvSlBLOUpJdFJaMnUzVkkKQT3KVYLG3HD9cbLzG46wI5ipxzjLfM8W\nwHezTfnVL9UUztHapdqu2uM2cZjjdGcsacvOCacfxLWzE+7Uk0RMGQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-05-05T10:34:16Z",
|
||||
"mac": "ENC[AES256_GCM,data:VfRQvyeeEAhQzTcG//spQm4VDYKY/aldO46CWx6QhW945H/2PP1OyNehT2PjjHArVy6HzZeLMb1E2tQHEemPvi4F4jjAqeA+SgnwNKEClYcIF021eaPZDeWbxo8MxQcy0QbRH6Aimihyr4GjAb+cYBm43DAgWCG9q9kHKCk7dts=,iv:eyWHtaGAB+/2Vwkq4tYKei60LGSatRM4FSOI0YUddyY=,tag:ElOBNQ5Hf1sTefzYYN3JoA==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
1
clanServices/wifi/tests/vm/sops/secrets/test-age.key/users/admin
Symbolic link
1
clanServices/wifi/tests/vm/sops/secrets/test-age.key/users/admin
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../users/admin
|
||||
4
clanServices/wifi/tests/vm/sops/users/admin/key.json
Normal file
4
clanServices/wifi/tests/vm/sops/users/admin/key.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"type": "age"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../sops/machines/test
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:C0x458T590iWSMBl6w==,iv:K0WawWV9fJbyFg9cD3H0htMAvxSqxVp2spdzNcVUSuI=,tag:Hb1+WGgM12UItrqjx04UdA==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1aex07l3uafv5hdr0h2707jgfsxcu7yhlc7glw3qu26xzn3m9nazsu47jzs",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxOEdHODRlRDFxRVMxSTNG\nazhkaXA3cGhBdUtqNExkZFFrcHlLOFQ1dFZNCndkc0tzZ29sYlB6KzBBZXpWN1hT\nRUl6c0dUY3NXNUVSd1Ixdk5UdkY5cE0KLS0tIDZCeldabUtieUtjUDJsV1BvMEhV\nNmQwcW5pZmx2cjFWWlRJMmY5b1JjQmsKqlFegGpY3zqHXa/qlSKEIQQ4nY/NPwL+\n3NzE2Voon6YLhrYNJAv8YndM5GMiIWQQim3suqdcq5KIRQshhO1x8g==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0NUFKdGIrM2NOWUx6M0Fl\naUp0K3Y5cEVON1haMkpiQ0kydXVvcWQ1WVVJCnl4bTN5Nk5kdjJ6ejB0NkE2aFJJ\nZlJjQzk4MjB1TmlNT0d6VmVScWVCcHMKLS0tIE1mWi9LMkNwc0pGZ3grTWdCTENC\nb1ZOYk41YStYYWJad2hHN2t5ODNQcjgKKP82jzHVDp53eRXg7yX6JgrWtJwcGbWj\nKCacNw6rRpdLOJDRea2uW3kHEVJz1L+T7EALRK9o59DxJfiQvjC/yw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-05-05T10:35:08Z",
|
||||
"mac": "ENC[AES256_GCM,data:XseZIImMQW4D9YhLmDbMkQiJqX+hQNEMAo8kTUgFE0AQy+72A6IT6kI5C7NnlvRAQmhc2KxtbooFLlYW2OR3cb7M0xCEZPYv76l/j6HXhYpBxuWbJsSz0htkm09OYFfYIpg4AEHXOt3TBJyzK9BWD5RX0Jwgp5x8ZxYxZKP1Zks=,iv:/5ZQ+Bp3mzcfe/OsHn4nToC412fNpiatvrdB/JBhIhM=,tag:I4duVl5DcTGABhBg2nTLnQ==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../sops/users/admin
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../sops/machines/test
|
||||
19
clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/secret
Normal file
19
clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/secret
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:YisL0uMSKSU=,iv:TWLcznbWfuIPrtYzIqhE+iqa+6jSLatSV51nxapwPow=,tag:fThlc6jY12C/cOFGXbStlg==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1aex07l3uafv5hdr0h2707jgfsxcu7yhlc7glw3qu26xzn3m9nazsu47jzs",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBudldzU1YrczMxK2RmZHlG\nTTdDZkVCbGhWek43TmRUTTc2NzA1VFN6VmhJCnpEencxSnZVOG83QVY2R1pRek0v\naHNuMzBCWVNGTGNrME8xd0hGaEx1SmcKLS0tIHRRN1BJZE5SZWFXYTlNSEVvekxI\nYlRoWHJ1UFBoSWxJQmd5ZWVIQVNjT0EKhO1ax3q+cIF2YyXJCGg00Zwl4A+ae9gF\n0Ta3aZy6QnHrzOcMGA2HYiefoVvPDlU5zkxjwvxtOZt6TmulumpzBw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJYUV3VXByVWFRaVNWQ0pt\ncG81RWFVbFh5SWFKS09xZlV0UGNaZWtDd1U4CmNYaUk3djRhYlBrSnllekk5RGtz\nUU95N1loS0dwbkRvaCt4NW55Rk12V1UKLS0tIDl6QjIxRC9BNmJBYi9BdGhybFcy\nTzVLdG9WcnkwbDZoaWJUTzM1b1dmbmsKzdOOKpZAAJwFc525IZ69RbmAMk79Pt6W\nzGs4qf0xBocYzF0G3kmt8ki8Nvvh5IWvpkIb+NTaQZAPhKNcSmBlzA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-05-05T10:35:08Z",
|
||||
"mac": "ENC[AES256_GCM,data:rv26UZhuyEouasJF1mY71df+7izOCw7dCqG/KjuUogtzt102NAawu4q7jF7j3Xi09cZKTmGllZD6L+R/8cpQ4l6R1JlBI6nbjKPFc4UNMNizW5U4KKHq0ApG9CVWiCDOdlH4Fiqa6vkZQw2dHyTAg5eHYiHtg7wuoiWlF4XnkP8=,iv:/yq+JlMCc1EQkj05Y1D6V4f64Whh+US9YEKOSb08xmI=,tag:jMYqXiDChLYnv3P1+bi3Bw==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
1
clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/users/admin
Symbolic link
1
clanServices/wifi/tests/vm/vars/shared/iwd.one/ssid/users/admin
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../../sops/users/admin
|
||||
@@ -1 +0,0 @@
|
||||
see [architecture-decision-record](https://github.com/joelparkerhenderson/architecture-decision-record)
|
||||
@@ -1,4 +1,4 @@
|
||||
{ ... }:
|
||||
{ inputs, ... }:
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
@@ -39,6 +39,10 @@
|
||||
shellHook = ''
|
||||
echo -e "${ansiEscapes.green}switch to another dev-shell using: select-shell${ansiEscapes.reset}"
|
||||
export PRJ_ROOT=$(git rev-parse --show-toplevel)
|
||||
|
||||
# vendoring / needed for impure tests
|
||||
ln -sfT ${self'.packages.clan-cli.nixpkgs} "$PRJ_ROOT/pkgs/clan-cli/clan_lib/nixpkgs"
|
||||
ln -sfT ${inputs.nix-select} "$PRJ_ROOT/pkgs/clan-cli/clan_lib/select"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
104
docs/mkdocs.yml
104
docs/mkdocs.yml
@@ -22,7 +22,11 @@ markdown_extensions:
|
||||
emoji_generator: !!python/name:material.extensions.emoji.to_svg
|
||||
- pymdownx.tasklist:
|
||||
custom_checkbox: true
|
||||
- pymdownx.superfences
|
||||
- pymdownx.superfences:
|
||||
custom_fences:
|
||||
- name: mermaid
|
||||
class: mermaid
|
||||
format: !!python/name:pymdownx.superfences.fence_code_format
|
||||
- pymdownx.tabbed:
|
||||
alternate_style: true
|
||||
- pymdownx.details
|
||||
@@ -42,43 +46,51 @@ exclude_docs: |
|
||||
|
||||
nav:
|
||||
- Home: index.md
|
||||
- Getting Started:
|
||||
- Setup Clan: getting-started/index.md
|
||||
- Create Installer: getting-started/installer.md
|
||||
- Add Machines: getting-started/configure.md
|
||||
- Secrets & Facts: getting-started/secrets.md
|
||||
- Deploy Machine: getting-started/deploy.md
|
||||
- Continuous Integration: getting-started/check.md
|
||||
- Guides:
|
||||
- Disk Encryption: getting-started/disk-encryption.md
|
||||
- Mesh VPN: getting-started/mesh-vpn.md
|
||||
- Backup & Restore: getting-started/backups.md
|
||||
- Vars Backend: manual/vars-backend.md
|
||||
- Facts Backend: manual/secrets.md
|
||||
- Autoincludes: manual/adding-machines.md
|
||||
- Getting Started:
|
||||
- Creating Your First Clan: guides/getting-started/index.md
|
||||
- Create Installer: guides/getting-started/installer.md
|
||||
- Add Machines: guides/getting-started/add-machines.md
|
||||
- Secrets & Facts: guides/getting-started/secrets.md
|
||||
- Deploy Machine: guides/getting-started/deploy.md
|
||||
- Continuous Integration: guides/getting-started/check.md
|
||||
- clanServices: guides/clanServices.md
|
||||
- Disk Encryption: guides/disk-encryption.md
|
||||
- Mesh VPN: guides/mesh-vpn.md
|
||||
- Backup & Restore: guides/backups.md
|
||||
- Vars Backend: guides/vars-backend.md
|
||||
- Facts Backend: guides/secrets.md
|
||||
- Adding more machines: guides/more-machines.md
|
||||
- Inventory:
|
||||
- Inventory: manual/inventory.md
|
||||
- Services: manual/distributed-services.md
|
||||
- Secure Boot: manual/secure-boot.md
|
||||
- Flake-parts: manual/flake-parts.md
|
||||
- Inventory: guides/inventory.md
|
||||
- Secure Boot: guides/secure-boot.md
|
||||
- Flake-parts: guides/flake-parts.md
|
||||
- Authoring:
|
||||
- clan.service: authoring/clanServices/index.md
|
||||
- Disk Templates: authoring/templates/disk/disko-templates.md
|
||||
- clanModules: authoring/legacyModules/index.md
|
||||
- clanService: guides/authoring/clanServices/index.md
|
||||
- Disk Template: guides/authoring/templates/disk/disko-templates.md
|
||||
- clanModule: guides/authoring/clanModules/index.md
|
||||
- Contributing:
|
||||
- Contribute: contributing/contribute.md
|
||||
- Debugging: contributing/debugging.md
|
||||
- Testing: contributing/testing.md
|
||||
- Repo Layout: manual/repo-layout.md
|
||||
- Migrate existing Flakes: manual/migration-guide.md
|
||||
- Contribute: guides/contributing/CONTRIBUTING.md
|
||||
- Debugging: guides/contributing/debugging.md
|
||||
- Testing: guides/contributing/testing.md
|
||||
- Migrations:
|
||||
- Migrate existing Flakes: guides/migrations/migration-guide.md
|
||||
- Migrate inventory Services: guides/migrations/migrate-inventory-services.md
|
||||
- Facts Vars Migration: guides/migrations/migration-facts-vars.md
|
||||
- macOS: guides/macos.md
|
||||
- Reference:
|
||||
- Overview: reference/index.md
|
||||
- Clan Services:
|
||||
- Overview: reference/clanServices/index.md
|
||||
- reference/clanServices/admin.md
|
||||
- reference/clanServices/hello-world.md
|
||||
- reference/clanServices/wifi.md
|
||||
- Clan Modules:
|
||||
- Overview:
|
||||
- reference/clanModules/index.md
|
||||
- reference/clanModules/frontmatter/index.md
|
||||
# This is the module overview and should stay at the top
|
||||
- Overview: reference/clanModules/index.md
|
||||
- reference/clanModules/frontmatter/index.md
|
||||
# TODO: display the docs of the clan.service modules
|
||||
- reference/clanModules/admin.md
|
||||
# This is the module overview and should stay at the top
|
||||
- reference/clanModules/borgbackup-static.md
|
||||
- reference/clanModules/data-mesher.md
|
||||
- reference/clanModules/borgbackup.md
|
||||
@@ -119,7 +131,7 @@ nav:
|
||||
- reference/clanModules/zerotier.md
|
||||
- reference/clanModules/zt-tcp-relay.md
|
||||
- CLI:
|
||||
- reference/cli/index.md
|
||||
- Overview: reference/cli/index.md
|
||||
|
||||
- reference/cli/backups.md
|
||||
- reference/cli/facts.md
|
||||
@@ -133,20 +145,30 @@ nav:
|
||||
- reference/cli/state.md
|
||||
- reference/cli/vars.md
|
||||
- reference/cli/vms.md
|
||||
- Clan Core:
|
||||
- reference/clan-core/index.md
|
||||
- NixOS Modules:
|
||||
- clan.core:
|
||||
- Overview: reference/clan.core/index.md
|
||||
|
||||
- reference/clan-core/backups.md
|
||||
- reference/clan-core/deployment.md
|
||||
- reference/clan-core/facts.md
|
||||
- reference/clan-core/networking.md
|
||||
- reference/clan-core/settings.md
|
||||
- reference/clan-core/sops.md
|
||||
- reference/clan-core/state.md
|
||||
- reference/clan-core/vars.md
|
||||
- reference/clan.core/backups.md
|
||||
- reference/clan.core/deployment.md
|
||||
- reference/clan.core/facts.md
|
||||
- reference/clan.core/networking.md
|
||||
- reference/clan.core/settings.md
|
||||
- reference/clan.core/sops.md
|
||||
- reference/clan.core/state.md
|
||||
- reference/clan.core/vars.md
|
||||
- Nix API:
|
||||
- buildClan: reference/nix-api/buildclan.md
|
||||
- Inventory: reference/nix-api/inventory.md
|
||||
- Glossary: reference/glossary.md
|
||||
- Decisions:
|
||||
- Architecture Decisions: decisions/README.md
|
||||
- 01-clanModules: decisions/01-ClanModules.md
|
||||
- 02-clan-api: decisions/02-clan-api.md
|
||||
- 03-adr-numbering-process: decisions/03-adr-numbering-process.md
|
||||
- 04-fetching-nix-from-python: decisions/04-fetching-nix-from-python.md
|
||||
- 05-deployment-parameters: decisions/05-deployment-parameters.md
|
||||
- Template: decisions/_template.md
|
||||
|
||||
docs_dir: site
|
||||
site_dir: out
|
||||
|
||||
@@ -45,7 +45,7 @@ pkgs.stdenv.mkDerivation {
|
||||
ln -snf ${fira-code}/share/fonts/truetype/FiraCode-VF.ttf ./site/static/
|
||||
|
||||
# Copy icons into place
|
||||
cp -af ../pkgs/webview-ui/app/icons ./site/static/
|
||||
cp -af ../pkgs/clan-app/ui/icons ./site/static/
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
|
||||
@@ -36,6 +36,9 @@
|
||||
# Options available when imported via ` inventory.${moduleName}....${rolesName} `
|
||||
clanModulesViaRoles = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModulesViaRoles);
|
||||
|
||||
# clan service options
|
||||
clanModulesViaService = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModulesViaService);
|
||||
|
||||
# Simply evaluated options (JSON)
|
||||
renderOptions =
|
||||
pkgs.runCommand "render-options"
|
||||
@@ -85,6 +88,7 @@
|
||||
export CLAN_CORE_DOCS=${jsonDocs.clanCore}/share/doc/nixos/options.json
|
||||
# A file that contains the links to all clanModule docs
|
||||
export CLAN_MODULES_VIA_ROLES=${clanModulesViaRoles}
|
||||
export CLAN_MODULES_VIA_SERVICE=${clanModulesViaService}
|
||||
export CLAN_MODULES_VIA_NIX=${clanModulesViaNix}
|
||||
# Frontmatter format for clanModules
|
||||
export CLAN_MODULES_FRONTMATTER_DOCS=${clanModulesFrontmatter}/share/doc/nixos/options.json
|
||||
@@ -100,7 +104,12 @@
|
||||
in
|
||||
{
|
||||
legacyPackages = {
|
||||
inherit jsonDocs clanModulesViaNix clanModulesViaRoles;
|
||||
inherit
|
||||
jsonDocs
|
||||
clanModulesViaNix
|
||||
clanModulesViaRoles
|
||||
clanModulesViaService
|
||||
;
|
||||
};
|
||||
devShells.docs = pkgs.callPackage ./shell.nix {
|
||||
inherit (self'.packages) docs clan-cli-docs inventory-api-docs;
|
||||
|
||||
@@ -36,6 +36,33 @@
|
||||
) rolesOptions
|
||||
) modulesRolesOptions;
|
||||
|
||||
# Test with:
|
||||
# nix build .\#legacyPackages.x86_64-linux.clanModulesViaService
|
||||
clanModulesViaService = lib.mapAttrs (
|
||||
_moduleName: moduleValue:
|
||||
let
|
||||
evaluatedService = clan-core.clanLib.inventory.evalClanService {
|
||||
modules = [ moduleValue ];
|
||||
prefix = [ ];
|
||||
};
|
||||
in
|
||||
{
|
||||
roles = lib.mapAttrs (
|
||||
_roleName: role:
|
||||
|
||||
(nixosOptionsDoc {
|
||||
transformOptions =
|
||||
opt: if lib.strings.hasPrefix "_" opt.name then opt // { visible = false; } else opt;
|
||||
options = (lib.evalModules { modules = [ role.interface ]; }).options;
|
||||
warningsAreErrors = true;
|
||||
}).optionsJSON
|
||||
) evaluatedService.config.roles;
|
||||
|
||||
manifest = evaluatedService.config.manifest;
|
||||
|
||||
}
|
||||
) clan-core.clan.modules;
|
||||
|
||||
clanCore =
|
||||
(nixosOptionsDoc {
|
||||
options =
|
||||
|
||||
@@ -29,8 +29,13 @@ from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from clan_cli.errors import ClanError
|
||||
from clan_lib.api.modules import Frontmatter, extract_frontmatter, get_roles
|
||||
from clan_lib.api.modules import (
|
||||
CategoryInfo,
|
||||
Frontmatter,
|
||||
extract_frontmatter,
|
||||
get_roles,
|
||||
)
|
||||
from clan_lib.errors import ClanError
|
||||
|
||||
# Get environment variables
|
||||
CLAN_CORE_PATH = Path(os.environ["CLAN_CORE_PATH"])
|
||||
@@ -44,6 +49,7 @@ CLAN_MODULES_VIA_NIX = os.environ.get("CLAN_MODULES_VIA_NIX")
|
||||
# Some modules can be imported via inventory
|
||||
CLAN_MODULES_VIA_ROLES = os.environ.get("CLAN_MODULES_VIA_ROLES")
|
||||
|
||||
CLAN_MODULES_VIA_SERVICE = os.environ.get("CLAN_MODULES_VIA_SERVICE")
|
||||
|
||||
OUT = os.environ.get("out")
|
||||
|
||||
@@ -58,7 +64,8 @@ def replace_store_path(text: str) -> tuple[str, str]:
|
||||
res = "https://git.clan.lol/clan/clan-core/src/branch/main/" + str(
|
||||
Path(*Path(text).parts[4:])
|
||||
)
|
||||
name = Path(res).name
|
||||
# name = Path(res).name
|
||||
name = str(Path(*Path(text).parts[4:]))
|
||||
return (res, name)
|
||||
|
||||
|
||||
@@ -149,8 +156,12 @@ def render_option(
|
||||
decls = option.get("declarations", [])
|
||||
if decls:
|
||||
source_path, name = replace_store_path(decls[0])
|
||||
|
||||
name = name.split(",")[0]
|
||||
source_path = source_path.split(",")[0]
|
||||
|
||||
res += f"""
|
||||
:simple-git: [{name}]({source_path})
|
||||
:simple-git: Declared in: [{name}]({source_path})
|
||||
"""
|
||||
res += "\n\n"
|
||||
|
||||
@@ -195,7 +206,12 @@ Some modules are considered 'low-level' or 'expert modules' and are not availabl
|
||||
"""
|
||||
|
||||
|
||||
clan_core_descr = """`clan.core` is always included in each machine `config`.
|
||||
clan_core_descr = """
|
||||
`clan.core` is always present in a clan machine
|
||||
|
||||
* It is a module of class **`nixos`**
|
||||
* Provides a set of common options for every machine (in addition to the NixOS options)
|
||||
|
||||
Your can customize your machines behavior with the configuration [options](#module-options) provided below.
|
||||
"""
|
||||
|
||||
@@ -221,7 +237,8 @@ def produce_clan_modules_frontmatter_docs() -> None:
|
||||
# header
|
||||
output = """# Frontmatter
|
||||
|
||||
Every clan module has a `frontmatter` section within its readme. It provides machine readable metadata about the module.
|
||||
Every clan module has a `frontmatter` section within its readme. It provides
|
||||
machine readable metadata about the module.
|
||||
|
||||
!!! example
|
||||
|
||||
@@ -246,7 +263,8 @@ Every clan module has a `frontmatter` section within its readme. It provides mac
|
||||
|
||||
output += """## Overview
|
||||
|
||||
This provides an overview of the available attributes of the `frontmatter` within the `README.md` of a clan module.
|
||||
This provides an overview of the available attributes of the `frontmatter`
|
||||
within the `README.md` of a clan module.
|
||||
|
||||
"""
|
||||
# for option_name, info in options.items():
|
||||
@@ -279,16 +297,28 @@ def produce_clan_core_docs() -> None:
|
||||
core_outputs: dict[str, str] = {}
|
||||
with CLAN_CORE_DOCS.open() as f:
|
||||
options: dict[str, dict[str, Any]] = json.load(f)
|
||||
module_name = "clan-core"
|
||||
module_name = "clan.core"
|
||||
|
||||
transform = {n.replace("clan.core.", ""): v for n, v in options.items()}
|
||||
split = split_options_by_root(transform)
|
||||
|
||||
# Prepopulate the index file header
|
||||
indexfile = f"{module_name}/index.md"
|
||||
core_outputs[indexfile] = (
|
||||
module_header(module_name) + clan_core_descr + options_head
|
||||
)
|
||||
core_outputs[indexfile] = module_header(module_name) + clan_core_descr
|
||||
|
||||
core_outputs[indexfile] += """!!! info "Submodules"\n"""
|
||||
|
||||
for submodule_name, split_options in split.items():
|
||||
root = options_to_tree(split_options, debug=True)
|
||||
module = root.suboptions[0]
|
||||
module_type = module.info.get("type")
|
||||
if module_type is not None and "submodule" not in module_type:
|
||||
continue
|
||||
core_outputs[indexfile] += (
|
||||
f" - [{submodule_name}](./{submodule_name}.md)\n"
|
||||
)
|
||||
|
||||
core_outputs[indexfile] += options_head
|
||||
|
||||
for submodule_name, split_options in split.items():
|
||||
outfile = f"{module_name}/{submodule_name}.md"
|
||||
@@ -304,7 +334,6 @@ def produce_clan_core_docs() -> None:
|
||||
print("type", module.info.get("type"))
|
||||
|
||||
module_type = module.info.get("type")
|
||||
|
||||
if module_type is not None and "submodule" not in module_type:
|
||||
outfile = indexfile
|
||||
init_level = 2
|
||||
@@ -331,7 +360,7 @@ def produce_clan_core_docs() -> None:
|
||||
|
||||
def render_roles(roles: list[str] | None, module_name: str) -> str:
|
||||
if roles:
|
||||
roles_list = "\n".join([f" - `{r}`" for r in roles])
|
||||
roles_list = "\n".join([f"- `{r}`" for r in roles])
|
||||
return (
|
||||
f"""
|
||||
### Roles
|
||||
@@ -341,17 +370,19 @@ This module can be used via predefined roles
|
||||
{roles_list}
|
||||
"""
|
||||
"""
|
||||
Every role has its own configuration options. Which are each listed below.
|
||||
Every role has its own configuration options, which are each listed below.
|
||||
|
||||
For more information, see the [inventory guide](../../manual/inventory.md).
|
||||
For more information, see the [inventory guide](../../guides/inventory.md).
|
||||
|
||||
??? Example
|
||||
For example the `admin` module adds the following options globally to all machines where it is used.
|
||||
|
||||
`clan.admin.allowedkeys`
|
||||
|
||||
This means there are two equivalent ways to set the `allowedkeys` option. Either via a nixos module or via the inventory interface.
|
||||
**But it is recommended to keep together `imports` and `config` to preserve locality of the module configuration.**
|
||||
This means there are two equivalent ways to set the `allowedkeys` option.
|
||||
Either via a nixos module or via the inventory interface.
|
||||
**But it is recommended to keep together `imports` and `config` to preserve
|
||||
locality of the module configuration.**
|
||||
|
||||
=== "Inventory"
|
||||
|
||||
@@ -383,20 +414,24 @@ For more information, see the [inventory guide](../../manual/inventory.md).
|
||||
return ""
|
||||
|
||||
|
||||
clan_modules_descr = """Clan modules are [NixOS modules](https://wiki.nixos.org/wiki/NixOS_modules) which have been enhanced with additional features provided by Clan, with certain option types restricted to enable configuration through a graphical interface.
|
||||
clan_modules_descr = """
|
||||
Clan modules are [NixOS modules](https://wiki.nixos.org/wiki/NixOS_modules)
|
||||
which have been enhanced with additional features provided by Clan, with
|
||||
certain option types restricted to enable configuration through a graphical
|
||||
interface.
|
||||
|
||||
!!! note "🔹"
|
||||
Modules with this indicator support the [inventory](../../manual/inventory.md) feature.
|
||||
Modules with this indicator support the [inventory](../../guides/inventory.md) feature.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def render_categories(categories: list[str], frontmatter: Frontmatter) -> str:
|
||||
cat_info = frontmatter.categories_info
|
||||
def render_categories(
|
||||
categories: list[str], categories_info: dict[str, CategoryInfo]
|
||||
) -> str:
|
||||
res = """<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;">"""
|
||||
for cat in categories:
|
||||
color = cat_info[cat]["color"]
|
||||
# description = cat_info[cat]["description"]
|
||||
color = categories_info[cat]["color"]
|
||||
res += f"""
|
||||
<div style="background-color: {color}; color: white; padding: 10px; border-radius: 20px; text-align: center;">
|
||||
{cat}
|
||||
@@ -406,6 +441,83 @@ def render_categories(categories: list[str], frontmatter: Frontmatter) -> str:
|
||||
return res
|
||||
|
||||
|
||||
def produce_clan_service_docs() -> None:
|
||||
if not CLAN_MODULES_VIA_SERVICE:
|
||||
msg = f"Environment variables are not set correctly: $CLAN_MODULES_VIA_SERVICE={CLAN_MODULES_VIA_SERVICE}"
|
||||
raise ClanError(msg)
|
||||
|
||||
if not CLAN_CORE_PATH:
|
||||
msg = f"Environment variables are not set correctly: $CLAN_CORE_PATH={CLAN_CORE_PATH}"
|
||||
raise ClanError(msg)
|
||||
|
||||
if not OUT:
|
||||
msg = f"Environment variables are not set correctly: $out={OUT}"
|
||||
raise ClanError(msg)
|
||||
|
||||
indexfile = Path(OUT) / "clanServices/index.md"
|
||||
indexfile.parent.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
index = "# Clan Services\n\n"
|
||||
index += """
|
||||
**`clanServices`** are modular building blocks that simplify the configuration and orchestration of multi-host services.
|
||||
|
||||
Each `clanService`:
|
||||
|
||||
* Is a module of class **`clan.service`**
|
||||
* Can define **roles** (e.g., `client`, `server`)
|
||||
* Uses **`inventory.instances`** to configure where and how it is deployed
|
||||
* Replaces the legacy `clanModules` and `inventory.services` system altogether
|
||||
|
||||
!!! Note
|
||||
`clanServices` are part of Clan's next-generation service model and are intended to replace `clanModules`.
|
||||
|
||||
See [Migration Guide](../../guides/migrations/migrate-inventory-services.md) for help on migrating.
|
||||
|
||||
Learn how to use `clanServices` in practice in the [Using clanServices guide](../../guides/clanServices.md).
|
||||
"""
|
||||
|
||||
with indexfile.open("w") as of:
|
||||
of.write(index)
|
||||
|
||||
with Path(CLAN_MODULES_VIA_SERVICE).open() as f3:
|
||||
service_links: dict[str, dict[str, dict[str, Any]]] = json.load(f3)
|
||||
|
||||
for module_name, module_info in service_links.items():
|
||||
output = f"# {module_name}\n\n"
|
||||
# output += f"`clan.modules.{module_name}`\n"
|
||||
output += f"*{module_info['manifest']['description']}*\n"
|
||||
|
||||
fm = Frontmatter("")
|
||||
# output += "## Categories\n\n"
|
||||
output += render_categories(
|
||||
module_info["manifest"]["categories"], fm.categories_info
|
||||
)
|
||||
output += "\n---\n\n## Roles\n"
|
||||
|
||||
output += f"The {module_name} module has the following roles:\n\n"
|
||||
|
||||
for role_name, _ in module_info["roles"].items():
|
||||
output += f"- {role_name}\n"
|
||||
|
||||
for role_name, role_filename in module_info["roles"].items():
|
||||
output += print_options(
|
||||
role_filename,
|
||||
f"## Options for the `{role_name}` role",
|
||||
"This role has no configuration",
|
||||
replace_prefix=f"clan.{module_name}",
|
||||
)
|
||||
|
||||
outfile = Path(OUT) / f"clanServices/{module_name}.md"
|
||||
outfile.parent.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
with outfile.open("w") as of:
|
||||
of.write(output)
|
||||
|
||||
|
||||
def produce_clan_modules_docs() -> None:
|
||||
if not CLAN_MODULES_VIA_NIX:
|
||||
msg = f"Environment variables are not set correctly: $CLAN_MODULES_VIA_NIX={CLAN_MODULES_VIA_NIX}"
|
||||
@@ -456,11 +568,27 @@ def produce_clan_modules_docs() -> None:
|
||||
|
||||
# 2. Description from README.md
|
||||
if frontmatter.description:
|
||||
output += f"**{frontmatter.description}**\n\n"
|
||||
output += f"*{frontmatter.description}*\n\n"
|
||||
|
||||
# 2. Deprecation note if the module is deprecated
|
||||
if "deprecated" in frontmatter.features:
|
||||
output += f"""
|
||||
!!! Warning "Deprecated"
|
||||
The `{module_name}` module is deprecated.*
|
||||
|
||||
Use [clanServices/{module_name}](../clanServices/{module_name}.md) instead
|
||||
"""
|
||||
else:
|
||||
output += f"""
|
||||
!!! Warning "Will be deprecated"
|
||||
The `{module_name}` module might eventually be migrated to 'clanServices'*
|
||||
|
||||
See: [clanServices](../../guides/clanServices.md)
|
||||
"""
|
||||
|
||||
# 3. Categories from README.md
|
||||
output += "## Categories\n\n"
|
||||
output += render_categories(frontmatter.categories, frontmatter)
|
||||
output += render_categories(frontmatter.categories, frontmatter.categories_info)
|
||||
output += "\n---\n\n"
|
||||
|
||||
# 3. README.md content
|
||||
@@ -593,7 +721,7 @@ Each attribute is documented below
|
||||
};
|
||||
```
|
||||
|
||||
- **flake-parts**: Each attribute can be defined via `clan.<attribute name>`. See our [flake-parts](../../manual/flake-parts.md) guide.
|
||||
- **flake-parts**: Each attribute can be defined via `clan.<attribute name>`. See our [flake-parts](../../guides/flake-parts.md) guide.
|
||||
|
||||
??? example "flake-parts Example"
|
||||
|
||||
@@ -785,7 +913,7 @@ def options_docs_from_tree(
|
||||
root: Option, init_level: int = 1, prefix: list[str] | None = None
|
||||
) -> str:
|
||||
"""
|
||||
Render the options from the tree structure.
|
||||
eender the options from the tree structure.
|
||||
|
||||
Args:
|
||||
root (Option): The root option node.
|
||||
@@ -829,5 +957,6 @@ if __name__ == "__main__": #
|
||||
produce_inventory_docs()
|
||||
|
||||
produce_clan_modules_docs()
|
||||
produce_clan_service_docs()
|
||||
|
||||
produce_clan_modules_frontmatter_docs()
|
||||
|
||||
@@ -17,6 +17,9 @@ pkgs.mkShell {
|
||||
self'.devShells.default
|
||||
];
|
||||
shellHook = ''
|
||||
git_root=$(git rev-parse --show-toplevel)
|
||||
cd ''${git_root}/docs
|
||||
|
||||
mkdir -p ./site/reference/cli
|
||||
cp -af ${module-docs}/* ./site/reference/
|
||||
cp -af ${clan-cli-docs}/* ./site/reference/cli/
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../CONTRIBUTING.md
|
||||
@@ -1,6 +1,8 @@
|
||||
# Clan service modules
|
||||
|
||||
Status: Accepted
|
||||
## Status
|
||||
|
||||
Accepted
|
||||
|
||||
## Context
|
||||
|
||||
@@ -65,9 +67,9 @@ Problems with the current way of writing clanModules:
|
||||
1. No way to retrieve the config of a single service instance, together with its name.
|
||||
2. Directly exporting a single, anonymous nixosModule without any intermediary attribute layers doesn't leave room for exporting other inventory resources such as potentially `vars` or `homeManagerConfig`.
|
||||
3. Can't access multiple config instances individually.
|
||||
Example:
|
||||
```nix
|
||||
inventory = {
|
||||
Example:
|
||||
```nix
|
||||
inventory = {
|
||||
services = {
|
||||
network.c-base = {
|
||||
instanceConfig.ips = {
|
||||
@@ -81,7 +83,7 @@ Problems with the current way of writing clanModules:
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
```
|
||||
This doesn't work because all instance configs are applied to the same namespace. So this results in a conflict currently.
|
||||
Resolving this problem means that new inventory modules cannot be plain nixos modules anymore. If they are configured via `instances` / `instanceConfig` they cannot be configured without using the inventory. (There might be ways to inject instanceConfig but that requires knowledge of inventory internals)
|
||||
|
||||
@@ -256,7 +258,6 @@ The following thoughts went into this:
|
||||
|
||||
We want to implement the system as described. Once we have sufficient data on real world use-cases and modules we might revisit this document along with the updated implementation.
|
||||
|
||||
|
||||
## Real world example
|
||||
|
||||
The following module demonstrates the idea in the example of *borgbackup*.
|
||||
@@ -407,7 +408,7 @@ The following module demonstrates the idea in the example of *borgbackup*.
|
||||
''
|
||||
) (lib.attrValues config.clan.core.state)}
|
||||
|
||||
if [[ ''${#preCommandErrors[@]} -gt 0 ]]; then
|
||||
if [[ ''${preCommandErrors[@]} -gt 0 ]]; then
|
||||
echo "pre-backup commands failed for the following services:"
|
||||
for state in "''${!preCommandErrors[@]}"; do
|
||||
echo " $state"
|
||||
@@ -22,11 +22,9 @@ This leads to the conclusion that we should do `library` centric development.
|
||||
With the current `clan` python code being a library that can be imported to create various tools ontop of it.
|
||||
All **CLI** or **UI** related parts should be moved out of the main library.
|
||||
|
||||
*Note: The next person who wants implement any new frontend should do this first. Currently it looks like the TUI is the next one.*
|
||||
|
||||
Imagine roughly the following architecture:
|
||||
|
||||
```mermaid
|
||||
``` mermaid
|
||||
graph TD
|
||||
%% Define styles
|
||||
classDef frontend fill:#f9f,stroke:#333,stroke-width:2px;
|
||||
@@ -75,7 +73,7 @@ Integration tests and smaller unit-tests should both be utilized to ensure the s
|
||||
|
||||
Note: Library function don't have to be json-serializable in general.
|
||||
|
||||
Persistence includes but is not limited to: creating git commits, writing to inventory.json, reading and writing vars and to/from disk in general.
|
||||
Persistence includes but is not limited to: creating git commits, writing to inventory.json, reading and writing vars, and interacting with persisted data in general.
|
||||
|
||||
## Benefits / Drawbacks
|
||||
|
||||
97
docs/site/decisions/04-fetching-nix-from-python.md
Normal file
97
docs/site/decisions/04-fetching-nix-from-python.md
Normal file
@@ -0,0 +1,97 @@
|
||||
## Status
|
||||
|
||||
accepted
|
||||
|
||||
## Context
|
||||
|
||||
In our clan-cli we need to get a lot of values from nix into the python runtime. This is used to determine the hostname, the target ips address, scripts to generate vars, file locations and many more.
|
||||
|
||||
Currently we use two different accessing methods:
|
||||
|
||||
### Method 1: deployment.json
|
||||
|
||||
A json file that serializes some predefined values into a JSON file as build-time artifact.
|
||||
|
||||
Downsides:
|
||||
|
||||
* no access to flake level values
|
||||
* all or nothing:
|
||||
* values are either cached via deployment.json or not. So we can only put cheap values into there,
|
||||
* in the past var generation script were added here, which added a huge build time overhead for every time we wanted to do any action
|
||||
* duplicated nix code
|
||||
* values need duplicated nix code, once to define them at the correct place in the module system (clan.core.vars.generators) and code to accumulate them again for the deployment.json (system.clan.deployment.data)
|
||||
* This duality adds unnecessary dependencies to the nixos module system.
|
||||
|
||||
Benefits:
|
||||
|
||||
* Utilize `nix build` for caching the file.
|
||||
* Caching mechanism is very simple.
|
||||
|
||||
|
||||
### Method 2: Direct access:
|
||||
|
||||
Directly calling the evaluator / build sandbox via `nix build` and `nix eval`within the Python code
|
||||
|
||||
|
||||
Downsides:
|
||||
|
||||
* Access is not cached: Static overhead (see below: \~1.5s) is present every time, if we invoke `nix commands`
|
||||
* The static overhead depends obviously which value we need to retrieve, since the `evalModules` overhead depends, whether we evaluate some attribute inside a machine or a flake attribute
|
||||
* Accessing more and more attributes with this method increases the static overhead, which leads to a linear decrease in performance.
|
||||
* Boilerplate for interacting with the CLI and Error handling code is repeated every time.
|
||||
|
||||
Benefits:
|
||||
|
||||
* Simple and native interaction with the `nix commands`is rather intuitive
|
||||
* Custom error handling for each attribute is easy
|
||||
|
||||
This sytem could be enhanced with custom nix expressions, which could be used in places where we don't want to put values into deployment.json or want to fetch flake level values. This also has some downsides:
|
||||
|
||||
* technical debt
|
||||
* we have to maintain custom nix expressions inside python code, embedding code is error prone and the language linters won't help you here, so errors are common and harder to debug.
|
||||
* we need custom error reporting code in case something goes wrong, either the value doesn't exist or there is an reported build error
|
||||
* no caching/custom caching logic
|
||||
* currently there is no infrastructure to cache those extra values, so we would need to store them somewhere, we could either enhance one of the many classes we have or don't cache them at all
|
||||
* even if we implement caching for extra nix expressions, there can be no sharing between extra nix expressions. for example we have 2 nix expressions, one fetches paths and values for all generators and the second one fetches only the values, we still need to execute both of them in both contexts although the second one could be skipped if the first one is already cached
|
||||
|
||||
### Method 3: nix select
|
||||
|
||||
Move all code that extracts nix values into a common class:
|
||||
|
||||
Downsides:
|
||||
* added complexity for maintaining our own DSL
|
||||
|
||||
Benefits:
|
||||
* we can implement an API (select DSL) to get those values from nix without writing complex nix expressions.
|
||||
* we can implement caching of those values beyond the runtime of the CLI
|
||||
* we can use precaching at different endpoints to eliminate most of multiple nix evaluations (except in cases where we have to break the cache or we don't know if we need the value in the value later and getting it is expensive).
|
||||
|
||||
|
||||
|
||||
## Decision
|
||||
|
||||
Use Method 3 (nix select) for extracting values out of nix.
|
||||
|
||||
This adds the Flake class in flake.py with a select method, which takes a selector string and returns a python dict.
|
||||
|
||||
Example:
|
||||
```python
|
||||
from clan_lib.flake import Flake
|
||||
flake = Flake("github:lassulus/superconfig")
|
||||
flake.select("nixosConfigurations.*.config.networking.hostName)
|
||||
```
|
||||
returns:
|
||||
```
|
||||
{
|
||||
"ignavia": "ignavia",
|
||||
"mors": "mors",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Consequences
|
||||
|
||||
* Faster execution due to caching most things beyond a single execution, if no cache break happens execution is basically instant, because we don't need to run nix again.
|
||||
* Better error reporting, since all nix values go through one chokepoint, we can parse error messages in that chokepoint and report them in a more user friendly way, for example if a value is missing at the expected location inside the module system.
|
||||
* less embedded nix code inside python code
|
||||
* more portable CLI, since we need to import less modules into the module system and most things can be extracted by the python code directly
|
||||
36
docs/site/decisions/05-deployment-parameters.md
Normal file
36
docs/site/decisions/05-deployment-parameters.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# deployment parameters: evalHost, buildHost, targetHost
|
||||
|
||||
## Status
|
||||
|
||||
accepted
|
||||
|
||||
## Context
|
||||
|
||||
Currently different operations (install, update) have different modes. Install always evals locally and pushes the derivation to a remote system. update has a configurable buildHost and targetHost.
|
||||
Confusingly install always evals locally and update always evals on the targetHost, so hosts have different semantics in different operations contexts.
|
||||
|
||||
## Decision
|
||||
|
||||
Add evalHost to make this clear and configurable for the user. This would leave us with:
|
||||
|
||||
- evalHost
|
||||
- buildHost
|
||||
- targetHost
|
||||
|
||||
for the update and install operation.
|
||||
|
||||
`evalHost` would be the machine that evaluates the nixos configuration. if evalHost is not localhost, we upload the non secret vars and the nix archived flake (this is usually the same operation) to the evalMachine.
|
||||
|
||||
`buildHost` would be what is used by the machine to build, it would correspond to `--build-host` on the nixos-rebuild command or `--builders` for nix build.
|
||||
|
||||
`targetHost` would be the machine where the closure gets copied to and activated (either through install or switch-to-configuration). It corresponds to `--targetHost` for nixos-rebuild or where we usually point `nixos-anywhere` to.
|
||||
|
||||
This hosts could be set either through CLI args (or forms for the GUI) or via the inventory. If both are given, the CLI args would take precedence.
|
||||
|
||||
## Consequences
|
||||
|
||||
We now support every deployment model of every tool out there with a bunch of simple flags. The semantics are more clear and we can write some nice documentation.
|
||||
|
||||
The install code has to be reworked, since nixos-anywhere has problems with evalHost and targetHost being the same machine, So we would need to kexec first and use the kexec image (or installer) as the evalHost afterwards.
|
||||
|
||||
In cases where the evalHost doesn't have access to the targetHost or buildHost, we need to setup temporary entries for the lifetime of the command.
|
||||
16
docs/site/decisions/README.md
Normal file
16
docs/site/decisions/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# Architecture Decision Records
|
||||
|
||||
This section contains the architecture decisions that have been reviewed and generally agreed upon
|
||||
|
||||
## What is an ADR?
|
||||
|
||||
> An architecture decision record (ADR) is a document that captures an important architecture decision made along with its context and consequences.
|
||||
|
||||
!!! Note
|
||||
For further reading about adr's we recommend [architecture-decision-record](https://github.com/joelparkerhenderson/architecture-decision-record)
|
||||
|
||||
## Crafting a new ADR
|
||||
|
||||
1. Use the [template](./_template.md)
|
||||
2. Create the Pull request and gather feedback
|
||||
3. Retreive your adr-number (see: [numbering](./03-adr-numbering-process.md))
|
||||
@@ -1,63 +0,0 @@
|
||||
---
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@ This site will guide you through authoring your first module. Explaining which c
|
||||
|
||||
|
||||
!!! Tip
|
||||
External ClanModules can be ad-hoc loaded via [`clan.inventory.modules`](../../reference/nix-api/inventory.md#inventory.modules)
|
||||
External ClanModules can be ad-hoc loaded via [`clan.inventory.modules`](../../../reference/nix-api/inventory.md#inventory.modules)
|
||||
|
||||
## Bootstrapping the `clanModule`
|
||||
|
||||
A ClanModule is a specific subset of a [NixOS Module](https://nix.dev/tutorials/module-system/index.html), but it has some constraints and might be used via the [Inventory](../../manual/inventory.md) interface.
|
||||
A ClanModule is a specific subset of a [NixOS Module](https://nix.dev/tutorials/module-system/index.html), but it has some constraints and might be used via the [Inventory](../../../guides/inventory.md) interface.
|
||||
In fact a `ClanModule` can be thought of as a layer of abstraction on-top of NixOS and/or other ClanModules. It may configure sane defaults and provide an ergonomic interface that is easy to use and can also be used via a UI that is under development currently.
|
||||
|
||||
Because ClanModules should be configurable via `json`/`API` all of its interface (`options`) must be serializable.
|
||||
@@ -48,7 +48,7 @@ clanModules/borgbackup
|
||||
=== "User module"
|
||||
|
||||
If the module should be ad-hoc loaded.
|
||||
It can be made available in any project via the [`clan.inventory.modules`](../../reference/nix-api/inventory.md#inventory.modules) attribute.
|
||||
It can be made available in any project via the [`clan.inventory.modules`](../../../reference/nix-api/inventory.md#inventory.modules) attribute.
|
||||
|
||||
```nix title="flake.nix"
|
||||
# ...
|
||||
@@ -89,7 +89,7 @@ description = "Module A"
|
||||
This is the example module that does xyz.
|
||||
```
|
||||
|
||||
See the [Full Frontmatter reference](../../reference/clanModules/frontmatter/index.md) further details and all supported attributes.
|
||||
See the [Full Frontmatter reference](../../../reference/clanModules/frontmatter/index.md) further details and all supported attributes.
|
||||
|
||||
## Roles
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Authoring a 'clan.service' module
|
||||
|
||||
!!! Tip
|
||||
This is the successor format to the older [clanModules](../legacyModules/index.md)
|
||||
This is the successor format to the older [clanModules](../clanModules/index.md)
|
||||
|
||||
While some features might still be missing we recommend to adapt this format early and give feedback.
|
||||
|
||||
129
docs/site/guides/clanServices.md
Normal file
129
docs/site/guides/clanServices.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# Using `clanServices`
|
||||
|
||||
Clan’s `clanServices` system is a composable way to define and deploy services across machines. It replaces the legacy `clanModules` approach and introduces better structure, flexibility, and reuse.
|
||||
|
||||
This guide shows how to **instantiate** a `clanService`, explains how service definitions are structured in your inventory, and how to pick or create services from modules exposed by flakes.
|
||||
|
||||
The term **Multi-host-modules** was introduced previously in the [nixus repository](https://github.com/infinisil/nixus) and represents a similar concept.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
A `clanService` is used in:
|
||||
|
||||
```nix
|
||||
inventory.instances.<instance_name>
|
||||
```
|
||||
|
||||
Each instance includes a reference to a **module specification** — this is how Clan knows which service module to use and where it came from.
|
||||
You can reference services from any flake input, allowing you to compose services from multiple flake sources.
|
||||
|
||||
These operate on a strict *role-based membership model*, meaning machines are added by assigning them specific *roles*.
|
||||
|
||||
---
|
||||
|
||||
## Basic Example
|
||||
|
||||
Example of instantiating a `borgbackup` service using `clan-core`:
|
||||
|
||||
```nix
|
||||
inventory.instances = {
|
||||
# Arbitrary unique name for this 'borgbackup' instance
|
||||
borgbackup-example = {
|
||||
module = {
|
||||
name = "borgbackup"; # <-- Name of the module
|
||||
input = "clan-core"; # <-- The flake input where the service is defined
|
||||
};
|
||||
# Participation of the machines is defined via roles
|
||||
# Right side needs to be an attribute set. Its purpose will become clear later
|
||||
roles.client.machines."machine-a" = {};
|
||||
roles.server.machines."backup-host" = {};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
If you used `clan-core` as an input attribute for your flake:
|
||||
|
||||
```nix
|
||||
# ↓ module.input = "clan-core"
|
||||
inputs.clan-core.url = "git+https://git.clan.lol/clan/clan-core"
|
||||
```
|
||||
|
||||
## Configuration Example
|
||||
|
||||
Each role might expose configurable options
|
||||
|
||||
See clan's [clanServices reference](../reference/clanServices/index.md) for available options
|
||||
|
||||
```nix
|
||||
inventory.instances = {
|
||||
borgbackup-example = {
|
||||
module = {
|
||||
name = "borgbackup";
|
||||
input = "clan-core";
|
||||
};
|
||||
roles.client.machines."machine-a" = {
|
||||
# 'client' -Settings of 'machine-a'
|
||||
settings = {
|
||||
backupFolders = [
|
||||
/home
|
||||
/var
|
||||
];
|
||||
};
|
||||
# ---------------------------
|
||||
};
|
||||
roles.server.machines."backup-host" = {};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Tags
|
||||
|
||||
Multiple members can be defined using tags as follows
|
||||
|
||||
```nix
|
||||
inventory.instances = {
|
||||
borgbackup-example = {
|
||||
module = {
|
||||
name = "borgbackup";
|
||||
input = "clan-core";
|
||||
};
|
||||
#
|
||||
# The 'all' -tag targets all machines
|
||||
roles.client.tags."all" = {};
|
||||
# ---------------------------
|
||||
roles.server.machines."backup-host" = {};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Picking a clanService
|
||||
|
||||
You can use services exposed by Clan’s core module library, `clan-core`.
|
||||
|
||||
🔗 See: [List of Available Services in clan-core](../reference/clanServices/index.md)
|
||||
|
||||
## Defining Your Own Service
|
||||
|
||||
You can also author your own `clanService` modules.
|
||||
|
||||
🔗 Learn how to write your own service: [Authoring a clanService](../guides/authoring/clanServices/index.md)
|
||||
|
||||
You might expose your service module from your flake — this makes it easy for other people to also use your module in their clan.
|
||||
|
||||
---
|
||||
|
||||
## 💡 Tips for Working with clanServices
|
||||
|
||||
* You can add multiple inputs to your flake (`clan-core`, `your-org-modules`, etc.) to mix and match services.
|
||||
* Each service instance is isolated by its key in `inventory.instances`, allowing you to deploy multiple versions or roles of the same service type.
|
||||
* Roles can target different machines or be scoped dynamically.
|
||||
|
||||
---
|
||||
|
||||
## What’s Next?
|
||||
|
||||
* [Author your own clanService →](../guides/authoring/clanServices/index.md)
|
||||
* [Migrate from clanModules →](../guides/migrations/migrate-inventory-services.md)
|
||||
<!-- TODO: * [Understand the architecture →](../explanation/clan-architecture.md) -->
|
||||
1
docs/site/guides/contributing/CONTRIBUTING.md
Symbolic link
1
docs/site/guides/contributing/CONTRIBUTING.md
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../CONTRIBUTING.md
|
||||
@@ -112,7 +112,7 @@ You can execute every test separately by following the tree path `nix run .#chec
|
||||
|
||||
## Test Locally in Devshell with Breakpoints
|
||||
|
||||
To test the cli locally in a development environment and set breakpoints for debugging, follow these steps:
|
||||
To test the CLI locally in a development environment and set breakpoints for debugging, follow these steps:
|
||||
|
||||
1. Run the following command to execute your tests and allow for debugging with breakpoints:
|
||||
```bash
|
||||
@@ -77,9 +77,9 @@ Locate the definition (see above) and add print statements, like, for example `p
|
||||
|
||||
#### Interactive Shell
|
||||
|
||||
- Execute the vm test outside the nix Sandbox via the following command:
|
||||
- Execute the vm test outside the nix Sandbox via the following command:
|
||||
`nix run .#checks.x86_64-linux.{test-attr-name}.driver -- --interactive`
|
||||
- Then run the commands in the machines manually, like for example:
|
||||
- Then run the commands in the machines manually, like for example:
|
||||
```python3
|
||||
start_all()
|
||||
machine1.succeed("echo hello")
|
||||
@@ -87,7 +87,7 @@ Locate the definition (see above) and add print statements, like, for example `p
|
||||
|
||||
#### Breakpoints
|
||||
|
||||
To get an interactive shell at a specific line in the VM test script, add a `breakpoint()` call before the line to debug, then run the test outside of the sandbox via:
|
||||
To get an interactive shell at a specific line in the VM test script, add a `breakpoint()` call before the line to debug, then run the test outside of the sandbox via:
|
||||
`nix run .#checks.x86_64-linux.{test-attr-name}.driver`
|
||||
|
||||
|
||||
@@ -113,9 +113,9 @@ rg self.clanLib.test.containerTest
|
||||
|
||||
## Python tests via pytest
|
||||
|
||||
Since the clan cli is written in python, the `pytest` framework is used to define unit tests and integration tests via python
|
||||
Since the Clan CLI is written in python, the `pytest` framework is used to define unit tests and integration tests via python
|
||||
|
||||
Due to superior efficiency,
|
||||
Due to superior efficiency,
|
||||
|
||||
### When to use python tests
|
||||
|
||||
@@ -141,7 +141,7 @@ rg "import pytest"
|
||||
If any python test fails in the CI pipeline, an error message like this can be found at the end of the log:
|
||||
```
|
||||
...
|
||||
FAILED tests/test_machines_cli.py::test_machine_delete - clan_cli.errors.ClanError: Template 'new-machine' not in 'inputs.clan-core
|
||||
FAILED tests/test_machines_cli.py::test_machine_delete - clan_lib.errors.ClanError: Template 'new-machine' not in 'inputs.clan-core
|
||||
...
|
||||
```
|
||||
|
||||
@@ -244,7 +244,7 @@ Find the attribute via ripgrep:
|
||||
$ rg "lib-values-eval ="
|
||||
lib/values/flake-module.nix
|
||||
21: lib-values-eval = pkgs.runCommand "tests" { nativeBuildInputs = [ pkgs.nix-unit ]; } ''
|
||||
grmpf@grmpf-nix ~/p/c/clan-core (test-docs)>
|
||||
grmpf@grmpf-nix ~/p/c/clan-core (test-docs)>
|
||||
```
|
||||
|
||||
In this case the test is defined in the file `lib/values/flake-module.nix` line 21
|
||||
@@ -296,9 +296,9 @@ Example:
|
||||
$ nix repl
|
||||
Nix 2.25.5
|
||||
Type :? for help.
|
||||
nix-repl> tests = import ./lib/values/test.nix {}
|
||||
nix-repl> tests = import ./lib/values/test.nix {}
|
||||
|
||||
nix-repl> tests
|
||||
nix-repl> tests
|
||||
{
|
||||
test_attrsOf_attrsOf_submodule = { ... };
|
||||
test_attrsOf_submodule = { ... };
|
||||
@@ -309,7 +309,7 @@ nix-repl> tests
|
||||
test_submodule_with_merging = { ... };
|
||||
}
|
||||
|
||||
nix-repl> tests.test_default.expr
|
||||
nix-repl> tests.test_default.expr
|
||||
{
|
||||
foo = { ... };
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Clan supports integration with [flake.parts](https://flake.parts/) a tool which allows composing nixos modules in a modular way.
|
||||
Clan supports integration with [flake-parts](https://flake.parts/), a framework for constructing your `flake.nix` using modules.
|
||||
|
||||
Here's how to set up Clan using `nix flakes` and `flake-parts`.
|
||||
To construct your Clan using flake-parts, follow these steps:
|
||||
|
||||
## 1. Update Your Flake Inputs
|
||||
|
||||
@@ -10,7 +10,7 @@ To begin, you'll need to add `flake-parts` as a new dependency in your flake's i
|
||||
```nix
|
||||
# flake.nix
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable";
|
||||
|
||||
# New flake-parts input
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
@@ -18,77 +18,76 @@ inputs = {
|
||||
|
||||
clan-core = {
|
||||
url = "git+https://git.clan.lol/clan/clan-core";
|
||||
inputs.nixpkgs.follows = "nixpkgs"; # Needed if your configuration uses nixpkgs unstable.
|
||||
inputs.nixpkgs.follows = "nixpkgs"; # Necessary if you are using a stable NixOS channel
|
||||
# New
|
||||
inputs.flake-parts.follows = "flake-parts";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Import Clan-Core Flake Module
|
||||
## 2. Import the Clan flake-parts Module
|
||||
|
||||
After updating your flake inputs, the next step is to import the `clan-core` flake module. This will make the [clan options](../reference/nix-api/buildclan.md) available within `mkFlake`.
|
||||
After updating your flake inputs, the next step is to import the Clan flake-parts module. This will make the [Clan options](../reference/nix-api/buildclan.md) available within `mkFlake`.
|
||||
|
||||
```nix
|
||||
{
|
||||
outputs =
|
||||
inputs@{ flake-parts, ... }:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } (
|
||||
{
|
||||
#
|
||||
imports = [
|
||||
inputs.clan-core.flakeModules.default
|
||||
];
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Configure Clan Settings and Define Machines
|
||||
|
||||
Configure your clan settings and define machine configurations.
|
||||
|
||||
Below is a guide on how to structure this in your flake.nix:
|
||||
Next you'll need to configure Clan wide settings and define machines, here's an example of how `flake.nix` should look:
|
||||
|
||||
```nix
|
||||
{
|
||||
outputs = inputs@{ flake-parts, clan-core, ... }:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } ({self, pkgs, ...}: {
|
||||
# We define our own systems below. you can still use this to add system specific outputs to your flake.
|
||||
# See: https://flake.parts/getting-started
|
||||
systems = [];
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
];
|
||||
|
||||
# import clan-core modules
|
||||
# Import the Clan flake-parts module
|
||||
imports = [
|
||||
clan-core.flakeModules.default
|
||||
];
|
||||
# Define your clan
|
||||
|
||||
# Define your Clan
|
||||
# See: https://docs.clan.lol/reference/nix-api/buildclan/
|
||||
clan = {
|
||||
# Clan wide settings. (Required)
|
||||
meta.name = ""; # Ensure to choose a unique name.
|
||||
# Clan wide settings
|
||||
meta.name = ""; # This is required and must be unique
|
||||
|
||||
machines = {
|
||||
jon = {
|
||||
imports = [
|
||||
./machines/jon/configuration.nix
|
||||
./modules/disko.nix
|
||||
./modules/firefox.nix
|
||||
# ... more modules
|
||||
];
|
||||
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
|
||||
# Set this for clan commands use ssh i.e. `clan machines update`
|
||||
clan.core.networking.targetHost = pkgs.lib.mkDefault "root@jon";
|
||||
# Set this for Clan commands to work remotely over SSH like `clan machines update`
|
||||
clan.core.networking.targetHost = "root@jon";
|
||||
|
||||
# remote> lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT
|
||||
disko.devices.disk.main = {
|
||||
device = "/dev/disk/by-id/nvme-eui.e8238fa6bf530001001b448b4aec2929";
|
||||
};
|
||||
|
||||
# There needs to be exactly one controller per clan
|
||||
clan.core.networking.zerotier.controller.enable = true;
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
For detailed information about configuring `flake-parts` and the available options within Clan,
|
||||
@@ -1,20 +1,20 @@
|
||||
|
||||
Managing machine configurations can be done in the following ways:
|
||||
|
||||
- writing `nix` expressions in a `flake.nix` file,
|
||||
- placing `autoincluded` files into your machine directory,
|
||||
- writing Nix expressions in a `flake.nix` file
|
||||
- placing `autoincluded` files into your machine directory
|
||||
|
||||
Clan currently offers the following methods to configure machines:
|
||||
|
||||
!!! Success "Recommended for nix people"
|
||||
!!! Success "Recommended for advanced Nix users"
|
||||
|
||||
- flake.nix (i.e. via `buildClan`)
|
||||
- `machine` argument
|
||||
- `inventory` argument
|
||||
|
||||
- machines/`machine_name`/configuration.nix (`autoincluded` if it exists)
|
||||
- machines/`machine_name`/configuration.nix (automatically included if it exists)
|
||||
|
||||
See the complete [list](../manual/adding-machines.md#automatic-registration) of auto-loaded files.
|
||||
See the complete [list](../../guides/more-machines.md#automatic-registration) of auto-loaded files.
|
||||
|
||||
???+ Note "Used by CLI & UI"
|
||||
|
||||
@@ -40,7 +40,7 @@ In the `flake.nix` file:
|
||||
|
||||
=== "**template using flake-parts**"
|
||||
|
||||
!!! info "See [Clan with flake-parts](../manual/flake-parts.md) for help migrating to flake-parts."
|
||||
!!! info "See [Clan with flake-parts](../../guides/flake-parts.md) for help migrating to flake-parts."
|
||||
|
||||
```nix title="flake.nix" hl_lines="3"
|
||||
clan = {
|
||||
@@ -106,7 +106,7 @@ Adding or configuring a new machine requires two simple steps:
|
||||
clan.core.networking.targetHost = "root@__IP__";
|
||||
|
||||
|
||||
# Replace this __CHANGE_ME__ with the result of the lsblk command from step 1.
|
||||
# Replace this __CHANGE_ME__ with the result of the lsblk command from step 1.
|
||||
disko.devices.disk.main.device = "/dev/disk/by-id/__CHANGE_ME__";
|
||||
|
||||
# IMPORTANT! Add your SSH key here
|
||||
@@ -124,7 +124,7 @@ Adding or configuring a new machine requires two simple steps:
|
||||
!!! Info "Replace `__YOUR_SSH_KEY__` with your personal key, like `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILoMI0NC5eT9pHlQExrvR5ASV3iW9+BXwhfchq0smXUJ jon@jon-desktop`"
|
||||
|
||||
|
||||
You can also create additional machines using the cli:
|
||||
You can also create additional machines using the CLI:
|
||||
|
||||
```
|
||||
$ clan machines create <machinename>
|
||||
@@ -8,7 +8,7 @@ Now that you have created a new machine, we will walk through how to install it.
|
||||
=== "**Physical Hardware**"
|
||||
|
||||
- [x] **Two Computers**: You need one computer that you're getting ready (we'll call this the Target Computer) and another one to set it up from (we'll call this the Setup Computer). Make sure both can talk to each other over the network using SSH.
|
||||
- [x] **Machine configuration**: See our basic [configuration guide](./configure.md)
|
||||
- [x] **Machine configuration**: See our basic [adding and configuring machine guide](./add-machines.md)
|
||||
- [x] **Initialized secrets**: See [secrets](secrets.md) for how to initialize your secrets.
|
||||
- [x] **USB Flash Drive**: See [Clan Installer](installer.md)
|
||||
|
||||
@@ -21,7 +21,7 @@ Now that you have created a new machine, we will walk through how to install it.
|
||||
=== "**Cloud VMs**"
|
||||
|
||||
- [x] **Two Computers**: You need one computer that you're getting ready (we'll call this the Target Computer) and another one to set it up from (we'll call this the Setup Computer). Make sure both can talk to each other over the network using SSH.
|
||||
- [x] **Machine configuration**: See our basic [configuration guide](./configure.md)
|
||||
- [x] **Machine configuration**: See our basic [adding and configuring machine guide](./add-machines.md)
|
||||
- [x] **Initialized secrets**: See [secrets](secrets.md) for how to initialize your secrets.
|
||||
|
||||
!!! Steps
|
||||
@@ -171,7 +171,7 @@ clan machines update
|
||||
|
||||
If the machine does not have enough resources to run the NixOS evaluation or build itself,
|
||||
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.
|
||||
During an update, the CLI will SSH into the build host and run `nixos-rebuild` from there.
|
||||
|
||||
|
||||
```{.nix hl_lines="5" .no-copy}
|
||||
@@ -1,41 +1,41 @@
|
||||
# :material-clock-fast: Getting Started
|
||||
|
||||
Ready to create your own clan and manage a fleet of machines? Follow these simple steps to get started.
|
||||
Ready to create your own Clan and manage a fleet of machines? Follow these simple steps to get started.
|
||||
|
||||
By the end of this guide, you'll have a fresh NixOS configuration ready to push to one or more machines. You'll create a new git repository and a flake, and all you need is at least one machine to push to. This is the easiest way to begin, and we recommend you to copy your existing configuration into this new setup!
|
||||
By the end of this guide, you'll have a fresh NixOS configuration ready to push to one or more machines. You'll create a new Git repository and a flake, and all you need is at least one machine to push to. This is the easiest way to begin, and we recommend you to copy your existing configuration into this new setup!
|
||||
|
||||
|
||||
### Prerequisites
|
||||
|
||||
=== "**Linux**"
|
||||
|
||||
Clan depends on nix installed on your system. Run the following command to install nix.
|
||||
Clan requires Nix to be installed on your system. Run the following command to install Nix:
|
||||
|
||||
```bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
|
||||
```
|
||||
|
||||
If you already have installed Nix, make sure you have the `nix-command` and `flakes` configuration enabled in your ~/.config/nix/nix.conf.
|
||||
The determinate installer already comes with this configuration by default.
|
||||
|
||||
```bash
|
||||
# /etc/nix/nix.conf or ~/.config/nix/nix.conf
|
||||
experimental-features = nix-command flakes
|
||||
```
|
||||
If you have previously installed Nix, make sure `experimental-features = nix-command flakes` is present in `~/.config/nix/nix.conf` or `/etc/nix/nix.conf`. If this is not the case, please add it to `~/.config/nix/nix.conf`.
|
||||
|
||||
=== "**NixOS**"
|
||||
|
||||
If you run NixOS the `nix` binary is already installed.
|
||||
|
||||
You will also need to enable the `flakes` and `nix-commands` experimental features in your configuration.nix:
|
||||
You will also need to enable the `nix-command` and `flakes` experimental features in your `configuration.nix`:
|
||||
|
||||
```nix
|
||||
{ nix.settings.experimental-features = [ "nix-command" "flakes" ]; }
|
||||
```
|
||||
|
||||
=== "**Other**"
|
||||
=== "**macOS**"
|
||||
|
||||
Clan doesn't offer dedicated support for other operating systems yet.
|
||||
Clan requires Nix to be installed on your system. Run the following command to install Nix:
|
||||
|
||||
```bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
|
||||
```
|
||||
|
||||
If you have previously installed Nix, make sure `experimental-features = nix-command flakes` is present in `~/.config/nix/nix.conf` or `/etc/nix/nix.conf`. If this is not the case, please add it to `~/.config/nix/nix.conf`.
|
||||
|
||||
### Step 1: Add Clan CLI to Your Shell
|
||||
|
||||
@@ -45,7 +45,7 @@ Add the Clan CLI into your development workflow:
|
||||
nix shell git+https://git.clan.lol/clan/clan-core#clan-cli --refresh
|
||||
```
|
||||
|
||||
You can find reference documentation for the `clan` cli program [here](../reference/cli/index.md).
|
||||
You can find reference documentation for the `clan` CLI program [here](../../reference/cli/index.md).
|
||||
|
||||
Alternatively you can check out the help pages directly:
|
||||
```terminalSession
|
||||
@@ -54,9 +54,9 @@ clan --help
|
||||
|
||||
### Step 2: Initialize Your Project
|
||||
|
||||
If you want to migrate an existing project, follow this [guide](https://docs.clan.lol/manual/migration-guide/).
|
||||
If you want to migrate an existing project, follow this [guide](../migrations/migration-guide.md).
|
||||
|
||||
Set the foundation of your Clan project by initializing it as follows:
|
||||
Set the foundation of your Clan project by initializing it by running:
|
||||
|
||||
```bash
|
||||
clan flakes create my-clan
|
||||
@@ -92,20 +92,23 @@ This should yield the following:
|
||||
5 directories, 9 files
|
||||
```
|
||||
|
||||
??? info "Recommended way of sourcing the `clan` cli tool"
|
||||
The default template also adds the `clan` cli tool to the development shell.
|
||||
Meaning you can get the exact version you need directly from the folder
|
||||
??? info "Recommended way of sourcing the `clan` CLI tool"
|
||||
|
||||
The default template adds the `clan` CLI tool to the development shell.
|
||||
This means that you can access the `clan` CLI tool directly from the folder
|
||||
you are in right now.
|
||||
|
||||
In the `my-clan` directory run the following command:
|
||||
In the `my-clan` directory, run the following command:
|
||||
|
||||
```
|
||||
nix develop
|
||||
```
|
||||
That way you will have the tool available in the shell environment.
|
||||
We also recommend setting up [direnv](https://direnv.net/) for your shell, for a more convenient
|
||||
experience.
|
||||
|
||||
|
||||
|
||||
This will ensure the `clan` CLI tool is available in your shell environment.
|
||||
|
||||
To automatically add the `clan` CLI tool to your environment without having to
|
||||
run `nix develop` every time, we recommend setting up [direnv](https://direnv.net/).
|
||||
|
||||
|
||||
```bash
|
||||
clan machines list
|
||||
@@ -118,5 +121,5 @@ sara
|
||||
|
||||
!!! success
|
||||
|
||||
You just successfully bootstrapped your first clan directory.
|
||||
You just successfully bootstrapped your first Clan.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
To install Clan on physical machines, you need to use our custom installer image. This is necessary for proper installation and operation.
|
||||
|
||||
!!! note "Using a Cloud VM?"
|
||||
If you're using a cloud provider's virtual machine (VM), you can skip this section and go directly to the [Configure Machines](configure.md) step. In this scenario, we automatically use [nixos-anywhere](https://github.com/nix-community/nixos-anywhere) to replace the kernel during runtime.
|
||||
If you're using a cloud provider's virtual machine (VM), you can skip this section and go directly to the [Add Machines](add-machines.md) step. In this scenario, we automatically use [nixos-anywhere](https://github.com/nix-community/nixos-anywhere) to replace the kernel during runtime.
|
||||
|
||||
??? info "Why nixos-anywhere Doesn't Work on Physical Hardware?"
|
||||
nixos-anywhere relies on [kexec](https://wiki.archlinux.org/title/Kexec) to replace the running kernel with our custom one. This method often has compatibility issues with real hardware, especially systems with dedicated graphics cards like laptops and servers, leading to crashes and black screens.
|
||||
@@ -151,7 +151,7 @@ sudo umount /dev/sdb1
|
||||
|
||||
|
||||
### Step 3: Boot From USB Stick
|
||||
- To use, boot from the Clan USB drive with **secure boot turned off**. For step by step instructions go to [Disabling Secure Boot](../manual/secure-boot.md)
|
||||
- To use, boot from the Clan USB drive with **secure boot turned off**. For step by step instructions go to [Disabling Secure Boot](../../guides/secure-boot.md)
|
||||
|
||||
|
||||
## (Optional) Connect to Wifi Manually
|
||||
@@ -3,7 +3,7 @@ Clan enables encryption of secrets (such as passwords & keys) ensuring security
|
||||
|
||||
By default, Clan uses the [sops](https://github.com/getsops/sops) format
|
||||
and integrates with [sops-nix](https://github.com/Mic92/sops-nix) on NixOS machines.
|
||||
Clan can also be configured to be used with other secret store [backends](https://docs.clan.lol/reference/clan-core/vars/#clan.core.vars.settings.secretStore).
|
||||
Clan can also be configured to be used with other secret store [backends](../../reference/clan.core/vars.md#clan.core.vars.settings.secretStore).
|
||||
|
||||
This guide will walk you through:
|
||||
|
||||
@@ -19,7 +19,7 @@ See also: [Inventory API Documentation](../reference/nix-api/inventory.md)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [x] [Add machines](./adding-machines.md) to your clan.
|
||||
- [x] [Add multiple machines](./more-machines.md) to your Clan.
|
||||
|
||||
## Services
|
||||
|
||||
@@ -29,7 +29,7 @@ See each [modules documentation](../reference/clanModules/index.md) for its avai
|
||||
|
||||
### Adding services to machines
|
||||
|
||||
A service can be added to one or multiple machines via `Roles`. clan's `Role` interface provide sane defaults for a module this allows the module author to reduce the configuration overhead to a minimum.
|
||||
A service can be added to one or multiple machines via `Roles`. Clan's `Role` interface provide sane defaults for a module this allows the module author to reduce the configuration overhead to a minimum.
|
||||
|
||||
Each service can still be customized and configured according to the modules options.
|
||||
|
||||
84
docs/site/guides/macos.md
Normal file
84
docs/site/guides/macos.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# Managing macOS Machines with Clan
|
||||
|
||||
This guide explains how to manage macOS machines using Clan.
|
||||
|
||||
## Supported Features
|
||||
|
||||
Currently, Clan supports the following features for macOS:
|
||||
|
||||
- `clan machines update` for existing [nix-darwin](https://github.com/nix-darwin/nix-darwin) installations
|
||||
- Support for [vars](../guides/vars-backend.md)
|
||||
|
||||
## Step 1: Add Your Machine to Your Clan Flake
|
||||
|
||||
In this example, we'll name the machine `yourmachine`. Replace this with your preferred machine name.
|
||||
|
||||
=== "**If using core.lib.buildClan**"
|
||||
|
||||
```nix
|
||||
buildClan {
|
||||
inventory = {
|
||||
machines.yourmachine.machineClass = "darwin";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
=== "**If using flake-parts**"
|
||||
|
||||
```nix
|
||||
{
|
||||
clan = {
|
||||
inventory = {
|
||||
machines.yourmachine.machineClass = "darwin";
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Step 2: Add a `configuration.nix` for Your Machine
|
||||
|
||||
Create the file `./machines/yourmachine/configuration.nix` with the following content (replace `yourmachine` with your chosen machine name):
|
||||
|
||||
```nix
|
||||
{
|
||||
clan.core.networking.targetHost = "root@ip_or_hostname";
|
||||
nixpkgs.hostPlatform = "aarch64-darwin"; # Use "x86_64-darwin" for Intel-based Macs
|
||||
}
|
||||
```
|
||||
|
||||
After creating the file, run `git add` to ensure Nix recognizes it.
|
||||
|
||||
## Step 3: Generate Vars (If Needed)
|
||||
|
||||
If your machine uses vars, generate them with:
|
||||
|
||||
```
|
||||
clan vars generate yourmachine
|
||||
```
|
||||
|
||||
Replace `yourmachine` with your chosen machine name.
|
||||
|
||||
## Step 4: Install Nix
|
||||
|
||||
Install Nix on your macOS machine using one of the methods described in the [nix-darwin prerequisites](https://github.com/nix-darwin/nix-darwin?tab=readme-ov-file#prerequisites).
|
||||
|
||||
|
||||
## Step 5: Install nix-darwin
|
||||
|
||||
Upload your Clan flake to the macOS machine. Then, from within your flake directory, run:
|
||||
|
||||
```sh
|
||||
sudo nix run nix-darwin/master#darwin-rebuild -- switch --flake .#yourmachine
|
||||
```
|
||||
|
||||
Replace `yourmachine` with your chosen machine name.
|
||||
|
||||
## Step 6: Manage Your Machine with Clan
|
||||
|
||||
Once all the steps above are complete, you can start managing your machine with:
|
||||
|
||||
```
|
||||
clan machines update yourmachine
|
||||
```
|
||||
|
||||
This command can be run from any computer that can reach this machine via SSH.
|
||||
147
docs/site/guides/migrations/migrate-inventory-services.md
Normal file
147
docs/site/guides/migrations/migrate-inventory-services.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# Migrating from using `clanModules` to `clanServices`
|
||||
|
||||
**Audience**: This is a guide for **people using `clanModules`**.
|
||||
If you are a **module author** and need to migrate your modules please consult our **new** [clanServices authoring guide](../authoring/clanServices/index.md)
|
||||
|
||||
## What's Changing?
|
||||
|
||||
Clan is transitioning from the legacy `clanModules` system to the `clanServices` system. This guide will help you migrate your service definitions from the old format (`inventory.services`) to the new format (`inventory.instances`).
|
||||
|
||||
| Feature | `clanModules` (Old) | `clanServices` (New) |
|
||||
| ---------------- | -------------------------- | ----------------------- |
|
||||
| Module Class | `"nixos"` | `"clan.service"` |
|
||||
| Inventory Key | `services` | `instances` |
|
||||
| Module Source | Static | Composable via flakes |
|
||||
| Custom Settings | Loosely structured | Strongly typed per-role |
|
||||
| Migration Status | Deprecated (to be removed) | ✅ Preferred |
|
||||
|
||||
---
|
||||
|
||||
## Before: Old `services` Definition
|
||||
|
||||
```nix
|
||||
services = {
|
||||
admin = {
|
||||
simple = {
|
||||
roles.default.tags = [ "all" ];
|
||||
|
||||
roles.default.config = {
|
||||
allowedKeys = {
|
||||
"key-1" = "ssh-ed25519 AAAA...0J jon@jon-os";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ After: New `instances` Definition with `clanServices`
|
||||
|
||||
```nix
|
||||
instances = {
|
||||
# The instance_name is arbitrary but must be unique
|
||||
# We recommend to incorporate the module name in some kind to keep it clear
|
||||
admin-simple = {
|
||||
module = {
|
||||
name = "admin";
|
||||
input = "clan-core";
|
||||
};
|
||||
|
||||
roles.default.tags."all" = {};
|
||||
|
||||
# Move settings either into the desired role
|
||||
# In that case they effect all 'client-machines'
|
||||
roles.default.settings = {
|
||||
allowedKeys = {
|
||||
"key-1" = "ssh-ed25519 AAAA...0J jon@jon-os";
|
||||
};
|
||||
};
|
||||
# ----------------------------
|
||||
# OR move settings into the machine
|
||||
# then they affect only that single 'machine'
|
||||
roles.default.machines."jon".settings = {
|
||||
allowedKeys = {
|
||||
"key-1" = "ssh-ed25519 AAAA...0J jon@jon-os";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Steps to Migrate
|
||||
|
||||
|
||||
|
||||
### 1. Move `services` entries to `instances`
|
||||
|
||||
Check if a service that you use has been migrated [In our reference](../../reference/clanServices/index.md)
|
||||
|
||||
In your inventory, move it from:
|
||||
|
||||
```nix
|
||||
services = { ... };
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```nix
|
||||
instances = { ... };
|
||||
```
|
||||
|
||||
Each nested service-instance-pair becomes a flat key, like `borgbackup.simple → borgbackup-simple`.
|
||||
|
||||
---
|
||||
|
||||
### 2. Add `module.name` and `module.input`
|
||||
|
||||
Each instance must declare the module name and flake input it comes from:
|
||||
|
||||
```nix
|
||||
module = {
|
||||
name = "borgbackup";
|
||||
input = "clan-core"; # The name of your flake input
|
||||
};
|
||||
```
|
||||
|
||||
If you used `clan-core` as an input:
|
||||
|
||||
```nix
|
||||
inputs.clan-core.url = "github:clan/clan-core";
|
||||
```
|
||||
|
||||
Then refer to it as `input = "clan-core"`.
|
||||
|
||||
---
|
||||
|
||||
### 3. Move role and machine config under `roles`
|
||||
|
||||
In the new system:
|
||||
|
||||
* Use `roles.<role>.machines.<hostname>.settings` for machine-specific config.
|
||||
* Use `roles.<role>.settings` for role-wide config.
|
||||
* Remove: `.config` as a top-level attribute is removed.
|
||||
|
||||
Example:
|
||||
|
||||
```nix
|
||||
roles.default.machines."test-inventory-machine".settings = {
|
||||
packages = [ "hello" ];
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
!!! Warning
|
||||
* Old `clanModules` (`class = "nixos"`) are deprecated and will be removed in the near future.
|
||||
* `inventory.services` is no longer recommended; use `inventory.instances` instead.
|
||||
* Module authors should begin exporting service modules under the `clan.modules` attribute of their flake.
|
||||
|
||||
## Further reference
|
||||
|
||||
* [Authoring a 'clan.service' module](../authoring/clanServices/index.md)
|
||||
* [ClanServices](../clanServices.md)
|
||||
* [Inventory Reference](../../reference/nix-api/inventory.md)
|
||||
127
docs/site/guides/migrations/migration-facts-vars.md
Normal file
127
docs/site/guides/migrations/migration-facts-vars.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# Migrate modules from `facts` to `vars`.
|
||||
|
||||
For a high level overview about `vars` see our [blog post](https://clan.lol/blog/vars/).
|
||||
|
||||
This guide will help you migrate your modules that still use our [`facts`](../../guides/secrets.md) backend
|
||||
to the [`vars`](../../guides/vars-backend.md) backend.
|
||||
|
||||
The `vars` [module](../../reference/clan.core/vars.md) and the clan [command](../../reference/cli/vars.md) work in tandem, they should ideally be kept in sync.
|
||||
|
||||
## Keep Existing Values
|
||||
|
||||
In order to keep existing values and move them from `facts` to `vars`
|
||||
we will need to set the corresponding option in the vars module:
|
||||
|
||||
```
|
||||
migrateFact = "fact-name"
|
||||
```
|
||||
|
||||
This will now check on `vars` generation if there is an existing `fact` with the
|
||||
name already present and if that is the case will migrate it to `vars`.
|
||||
|
||||
Let us look at the mapping a little closer.
|
||||
Suppose we have the following fact: `facts.services.vaultwarden.secret.admin`.
|
||||
This would read as follows: The `vaultwarden` `fact` service has the `admin` secret.
|
||||
In order to migrate this fact we would need to have the following `vars` configuration:
|
||||
|
||||
```nix
|
||||
vars.generators.vaultwarden = {
|
||||
migrateFact = "vaultwarden";
|
||||
files.admin = {};
|
||||
};
|
||||
```
|
||||
|
||||
And this would read as follows: The vaultwarden `vars` module generates the admin file.
|
||||
|
||||
|
||||
## Prompts
|
||||
|
||||
Because prompts can be a necessity for certain systems `vars` have a shorthand for defining them.
|
||||
A prompt is a request for user input. Let us look how user input used to be handled in facts:
|
||||
|
||||
```nix
|
||||
facts.services.forgejo-api = {
|
||||
secret.token = {};
|
||||
generator.prompt = "Please insert your forgejo api token";
|
||||
generator.script = "cp $prompt_value > $secret/token";
|
||||
};
|
||||
```
|
||||
To have analogous functionality in `vars`:
|
||||
```nix
|
||||
vars.generators.forgejo-api = {
|
||||
prompts.token = {
|
||||
description = "Please insert your forgejo api token"
|
||||
persist = true;
|
||||
};
|
||||
};
|
||||
```
|
||||
This does not only simplify prompting, it also now allows us to define multiple prompts in one generator.
|
||||
A more analogous way to the `fact` method is available, in case the module author needs more flexibility with the prompt input:
|
||||
|
||||
```nix
|
||||
vars.generators.forgejo-api = {
|
||||
files.token = {};
|
||||
prompts.token.description = "Please insert your forgejo api token";
|
||||
script = "cp $prompts/<name> $out/<name>";
|
||||
};
|
||||
```
|
||||
|
||||
## Migration of a complete module
|
||||
|
||||
Let us look closer at how we would migrate an existing generator for syncthing.
|
||||
This is the `fact` module of syncthing:
|
||||
|
||||
```nix
|
||||
facts.services.syncthing = {
|
||||
secret.key = {};
|
||||
secret.cert = {};
|
||||
public.id = {};
|
||||
|
||||
generator.path = [
|
||||
pkgs.coreutils
|
||||
pkgs.gnugrep
|
||||
pkgs.syncthing
|
||||
];
|
||||
|
||||
generator.script = ''
|
||||
syncthing generate --config "$out"
|
||||
mv "$out"/key.pem "$secret"/key
|
||||
mv "$out"/cert.pem "$secret"/cert
|
||||
cat "$out"/config.xml | grep -oP '(?<=<device id=")[^"]+' | uniq > "$public"/id
|
||||
'';
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
This would be the corresponding `vars` module, which also will migrate existing facts.
|
||||
```nix
|
||||
vars.generators.syncthing = {
|
||||
migrateFact = "syncthing";
|
||||
|
||||
files.key = {};
|
||||
files.cert = {};
|
||||
files.id.secret = false;
|
||||
|
||||
runtimeInputs = [
|
||||
pkgs.coreutils
|
||||
pkgs.gnugrep
|
||||
pkgs.syncthing
|
||||
];
|
||||
|
||||
script = ''
|
||||
syncthing generate --config "$out"
|
||||
mv "$out"/key.pem "$out"/key
|
||||
mv "$out"/cert.pem "$out"/cert
|
||||
cat "$out"/config.xml | grep -oP '(?<=<device id=")[^"]+' | uniq > "$out"/id
|
||||
'';
|
||||
};
|
||||
```
|
||||
Most of the usage patterns stay the same, but `vars` have a more ergonomic interface.
|
||||
There are not two different ways to define files anymore (public/secret).
|
||||
Now files are defined under the `files` attribute and are secret by default.
|
||||
|
||||
|
||||
## Happy Migration
|
||||
|
||||
We hope this gives you a clear path to start and finish your migration from `facts` to `vars`.
|
||||
Please do not hesitate reaching out if something is still unclear - either through [matrix](https://matrix.to/#/#clan:clan.lol) or through our git [forge](https://git.clan.lol/clan/clan-core).
|
||||
@@ -1,10 +1,10 @@
|
||||
# Migrate existing NixOS configurations
|
||||
|
||||
This guide will help you migrate your existing Nix configurations into Clan.
|
||||
This guide will help you migrate your existing NixOS configurations into Clan.
|
||||
|
||||
!!! Warning
|
||||
Migrating instead of starting new can be trickier and might lead to bugs or
|
||||
unexpected issues. We recommend following the [Getting Started](../getting-started/index.md) guide first. Once you have a working setup, you can easily transfer your Nix configurations over.
|
||||
unexpected issues. We recommend following the [Getting Started](../getting-started/index.md) guide first. Once you have a working setup, you can easily transfer your NixOS configurations over.
|
||||
|
||||
## Back up your existing configuration!
|
||||
Before you start, it is strongly recommended to back up your existing
|
||||
@@ -31,12 +31,12 @@ have have two hosts: **berlin** and **cologne**.
|
||||
|
||||
berlin = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [./machines/berlin/configuration.nix];
|
||||
modules = [ ./machines/berlin/configuration.nix ];
|
||||
};
|
||||
|
||||
cologne = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [./machines/cologne/configuration.nix];
|
||||
modules = [ ./machines/cologne/configuration.nix ];
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -53,7 +53,7 @@ inputs.clan-core = {
|
||||
url = "git+https://git.clan.lol/clan/clan-core";
|
||||
# Don't do this if your machines are on nixpkgs stable.
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Update Outputs
|
||||
@@ -77,36 +77,36 @@ For the provide flake example, your flake should now look like this:
|
||||
```nix
|
||||
{
|
||||
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
|
||||
|
||||
inputs.clan-core = {
|
||||
url = "git+https://git.clan.lol/clan/clan-core";
|
||||
url = "git+https://git.clan.lol/clan/clan-core";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, clan-core, ... }:
|
||||
let
|
||||
clan = clan-core.lib.buildClan {
|
||||
self = self; # this needs to point at the repository root
|
||||
specialArgs = {};
|
||||
meta.name = throw "Change me to something unique";
|
||||
self = self; # this needs to point at the repository root
|
||||
specialArgs = {};
|
||||
meta.name = throw "Change me to something unique";
|
||||
|
||||
machines = {
|
||||
berlin = {
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
imports = [ ./machines/berlin/configuration.nix ];
|
||||
};
|
||||
cologne = {
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
imports = [ ./machines/cologne/configuration.nix ];
|
||||
};
|
||||
machines = {
|
||||
berlin = {
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
imports = [ ./machines/berlin/configuration.nix ];
|
||||
};
|
||||
cologne = {
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
imports = [ ./machines/cologne/configuration.nix ];
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
nixosConfigurations = clan.nixosConfigurations;
|
||||
|
||||
|
||||
inherit (clan) clanInternals;
|
||||
|
||||
|
||||
clan = {
|
||||
inherit (clan) templates;
|
||||
};
|
||||
@@ -144,7 +144,7 @@ A minimal example is provided below, add it to your flake outputs.
|
||||
```nix
|
||||
devShells."x86_64-linux".default = nixpkgs.legacyPackages."x86_64-linux".mkShell {
|
||||
packages = [ clan-core.packages."x86_64-linux".clan-cli ];
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
To use the CLI, execute `nix develop` in the directory of your flake. The
|
||||
@@ -178,4 +178,3 @@ Clan needs to know where it can reach your hosts. For each of your hosts, set
|
||||
You are now fully set up. Use the CLI to manage your hosts or proceed to
|
||||
configure further services. At this point you should be able to run commands
|
||||
like `clan machines update berlin` to deploy a host.
|
||||
|
||||
@@ -21,7 +21,7 @@ Every folder `machines/{machineName}` will be registered automatically as a Clan
|
||||
|
||||
## Manual declaration
|
||||
|
||||
Machines can also be added manually under `buildClan`, `clan.*` in flake-parts or via [`inventory`](../manual/inventory.md).
|
||||
Machines can also be added manually under `buildClan`, `clan.*` in flake-parts or via [`inventory`](../guides/inventory.md).
|
||||
|
||||
!!! Note
|
||||
It is possible to use `inventory` and `buildClan` together at the same time.
|
||||
@@ -7,18 +7,18 @@ Defining a linux user's password via the nixos configuration previously required
|
||||
|
||||
In this example, we will guide you through automating that interaction using clan `vars`.
|
||||
|
||||
For a more general explanation of what clan vars are and how it works, see the intro of the [Reference Documentation for vars](https://docs.clan.lol/reference/clan-core/vars/)
|
||||
For a more general explanation of what clan vars are and how it works, see the intro of the [Reference Documentation for vars](../reference/clan.core/vars.md)
|
||||
|
||||
This guide assumes
|
||||
- clan is set up already (see [Getting Started](../getting-started/index.md))
|
||||
- a machine has been added to the clan (see [Adding Machines](./adding-machines.md))
|
||||
- Clan is set up already (see [Getting Started](../guides/getting-started/index.md))
|
||||
- a machine has been added to the clan (see [Adding Machines](./more-machines.md))
|
||||
|
||||
This section will walk you through the following steps:
|
||||
|
||||
1. declare a `generator` in the machine's nixos configuration
|
||||
2. inspect the status via the clan cli
|
||||
2. inspect the status via the Clan CLI
|
||||
3. generate the vars
|
||||
4. observer the changes
|
||||
4. observe the changes
|
||||
5. update the machine
|
||||
6. share the root password between machines
|
||||
7. change the password
|
||||
@@ -147,5 +147,5 @@ Updated var root-password/password-hash
|
||||
|
||||
## Further Reading
|
||||
|
||||
- [Reference Documentation for `clan.core.vars` nixos options](../reference/clan-core/vars.md)
|
||||
- [Reference Documentation for the `clan vars` cli command](../reference/cli/vars.md)
|
||||
- [Reference Documentation for `clan.core.vars` NixOS options](../reference/clan.core/vars.md)
|
||||
- [Reference Documentation for the `clan vars` CLI command](../reference/cli/vars.md)
|
||||
@@ -6,32 +6,7 @@ hide:
|
||||
|
||||
# :material-home: Welcome to **Clan**'s documentation
|
||||
|
||||
[Getting Started](./getting-started/index.md){ .md-button }
|
||||
|
||||
## Tutorials
|
||||
|
||||
**Learning-oriented adventures with a hands-on experience.**
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- :material-clock-fast:{ .lg .middle } __Set up in 15 minutes__
|
||||
|
||||
---
|
||||
|
||||
Create your own clan and get everything
|
||||
running in minutes
|
||||
|
||||
[:octicons-arrow-right-24: Getting started](./getting-started/index.md)
|
||||
|
||||
- :fontawesome-solid-user-group:{ .lg .middle } __Authoring Modules__
|
||||
|
||||
---
|
||||
|
||||
Create ressources that can be reused by the community.
|
||||
|
||||
[:octicons-arrow-right-24: Authoring guides](./authoring/legacyModules/index.md)
|
||||
|
||||
</div>
|
||||
[Getting Started](./guides/getting-started/index.md){ .md-button }
|
||||
|
||||
## :material-book: Guides
|
||||
|
||||
@@ -39,36 +14,42 @@ hide:
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [Autoincludes](./manual/adding-machines.md)
|
||||
- [Adding more machines](./guides/more-machines.md)
|
||||
|
||||
---
|
||||
|
||||
Learn how Clan automatically includes machines and Nix files.
|
||||
|
||||
- [Vars Backend](./manual/vars-backend.md)
|
||||
- [Vars Backend](./guides/vars-backend.md)
|
||||
|
||||
---
|
||||
|
||||
Learn how to manage secrets with facts.
|
||||
Learn how to manage secrets with vars.
|
||||
|
||||
- [Inventory](./manual/inventory.md)
|
||||
- [Inventory](./guides/inventory.md)
|
||||
|
||||
---
|
||||
|
||||
Clan's declaration format for running **services** on one or multiple **machines**.
|
||||
|
||||
- [Flake-parts](./manual/flake-parts.md)
|
||||
- [Flake-parts](./guides/flake-parts.md)
|
||||
|
||||
---
|
||||
|
||||
Use clan with [https://flake.parts/]()
|
||||
Use Clan with [https://flake.parts/]()
|
||||
|
||||
- [Contribute](./contributing/contribute.md)
|
||||
- [Contribute](./guides/contributing/CONTRIBUTING.md)
|
||||
|
||||
---
|
||||
|
||||
Discover how to set up a development environment to contribute to Clan!
|
||||
|
||||
- [macOS machines](./guides/macos.md)
|
||||
|
||||
---
|
||||
|
||||
Manage macOS machines with nix-darwin
|
||||
|
||||
</div>
|
||||
|
||||
## API Reference
|
||||
@@ -77,11 +58,33 @@ hide:
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [Reference Overview](./reference/index.md)
|
||||
- [CLI Reference](./reference/cli/index.md)
|
||||
|
||||
---
|
||||
|
||||
Learn how to interface with Clan programmatically
|
||||
The `clan` CLI command
|
||||
|
||||
- [Service Modules](./reference/clanServices/index.md)
|
||||
|
||||
---
|
||||
|
||||
An overview of available service modules
|
||||
|
||||
- [Core](./reference/clan.core/index.md)
|
||||
|
||||
---
|
||||
|
||||
The clan core nix module.
|
||||
This is imported when using clan and is the basis of the extra functionality
|
||||
that can be provided.
|
||||
|
||||
- [(Legacy) Modules](./reference/clanModules/index.md)
|
||||
|
||||
---
|
||||
|
||||
An overview of available clanModules
|
||||
|
||||
!!! Example "These will be deprecated soon"
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
# Instances
|
||||
|
||||
First of all it might be needed to explain what we mean by the term *distributed service*
|
||||
|
||||
## What is considered a service?
|
||||
|
||||
A **distributed service** is a system where multiple machines work together to provide a certain functionality, abstracting complexity and allowing for declarative configuration and management.
|
||||
|
||||
A VPN service in a closed mesh network is a good example of a distributed service — each machine needs to know the addresses and cryptographic keys of the other machines in advance to establish secure, direct connections, enabling private and encrypted communication without relying on a central server.
|
||||
|
||||
The term **Multi-host-service-abstractions** was introduced previously in the [nixus repository](https://github.com/infinisil/nixus) and represents a similar concept.
|
||||
|
||||
## How to use such a Service in Clan?
|
||||
|
||||
In clan everyone can provide services via modules. Those modules must be [`clan.service` modules](../authoring/clanServices/index.md).
|
||||
|
||||
To use a service you need to create an instance of it via the `clan.inventory.instances` attribute:
|
||||
The source of the module must be specified as a simple string.
|
||||
|
||||
```nix
|
||||
{
|
||||
inventory = {
|
||||
instances = {
|
||||
"my-vpn" = {
|
||||
# service source
|
||||
module.name = "zerotier";
|
||||
# ...
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
After specifying the *service source* for an instance, the next step is to configure the service.
|
||||
Services operate on a strict *role-based membership model*, meaning machines are added by assigning them specific *roles*.
|
||||
|
||||
The following example shows a *zerotier service* which consists of a `controller` and some `peer` machines.
|
||||
|
||||
```nix
|
||||
{
|
||||
inventory = {
|
||||
instances = {
|
||||
"my-vpn" = {
|
||||
# service source
|
||||
module.name = "zerotier";
|
||||
roles.peer.machines = {
|
||||
# Right side needs to be an attribute set. Its purpose will become clear later
|
||||
"my-machine-name" = {};
|
||||
};
|
||||
roles.controller.machines = {
|
||||
"some-server-name" = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
The next step is optional for some services. It might be desired to pass some service specific settings.
|
||||
Either to affect all machines of a given role, or to affect a very specific machine.
|
||||
For example:
|
||||
|
||||
In ZeroTier, the `roles.peer.settings` could specify the allowed IP ranges.
|
||||
|
||||
The `roles.controller.settings` could define a how to manage dynamic IP assignments for devices that are not statically configured.
|
||||
|
||||
```nix
|
||||
{
|
||||
inventory = {
|
||||
instances = {
|
||||
"my-vpn" = {
|
||||
# service source
|
||||
module.name = "zerotier";
|
||||
roles.peer.machines = {
|
||||
# Right side needs to be an attribute set. Its purpose will become clear later
|
||||
"my-machine-name" = {};
|
||||
};
|
||||
roles.peer.settings = {
|
||||
# Allow all ranges
|
||||
ipRanges = [ "all" ];
|
||||
};
|
||||
roles.controller.machines = {
|
||||
"some-server-name" = {
|
||||
settings = {
|
||||
# Enable the dynamic IP controller feature on this machine only
|
||||
dynamicIp.enable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Following all the steps described will result in consistent machine configurations that can be *installed* or *updated* via the [Clan CLI](../reference/cli/index.md)
|
||||
|
||||
### Using `clan.modules` from other people (optional)
|
||||
|
||||
The following example shows how to use remote modules and configure them for use in your clan.
|
||||
|
||||
!!! Note
|
||||
Typically you would just use the `import` builtin. But we wanted to provide a json-compatible interface to allow for external API integrations.
|
||||
|
||||
```nix title="flake.nix"
|
||||
{
|
||||
inputs = {
|
||||
# ...
|
||||
libstd.url = "github:libfoo/libfoo";
|
||||
# ...
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs: flake-parts.lib.mkFlake { inherit inputs; } (
|
||||
{
|
||||
clan = {
|
||||
inventory.instances = {
|
||||
"my-foo" = {
|
||||
# Imports clan.module."mod-A" from inputs.libstd
|
||||
module.input = "libstd";
|
||||
module.name = "mod-A";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
@@ -1,20 +0,0 @@
|
||||
|
||||
This guide will help you navigate the codebase and locate key files:
|
||||
|
||||
```bash
|
||||
$ tree -L 1
|
||||
.
|
||||
├── checks # Contains NixOS and VM tests
|
||||
├── clanModules # Clan modules available for end-user import
|
||||
├── docs # Source files for docs.clan.lol, generated with MkDocs
|
||||
├── flakeModules
|
||||
├── lib # User-exposed Clan Nix functions like buildClan and inventory
|
||||
├── machines
|
||||
├── nixosModules # Internal Clan Nix functions, e.g., clanCore
|
||||
├── pkgs # Clan applications and packaged dependencies
|
||||
├── formatter.nix # Configuration for nix-treefmt, manages `nix fmt`
|
||||
├── scripts
|
||||
├── sops
|
||||
├── templates # Template files for creating a new Clan
|
||||
└── vars
|
||||
```
|
||||
38
docs/site/reference/glossary.md
Normal file
38
docs/site/reference/glossary.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# :material-api: Glossary
|
||||
|
||||
## clan
|
||||
Collection of machines interconnected in a network.
|
||||
|
||||
## clan-app
|
||||
Graphical interface for managing clans. Simpler to use than the `clan-cli`.
|
||||
|
||||
## clan-cli
|
||||
Command-line tool for managing clans.
|
||||
|
||||
## clanModule
|
||||
Module that enables configuration via the inventory.
|
||||
Legacy `clanModules` also support configuration outside the inventory.
|
||||
|
||||
## clanService
|
||||
Service defined and managed through a clan configuration.
|
||||
|
||||
## clanURL
|
||||
Flake URL-like syntax used to link to clans.
|
||||
Required to connect the `url-open` application to the `clan-app`.
|
||||
|
||||
## facts *(deprecated)*
|
||||
System for creating secrets and public files in a declarative way.
|
||||
**Note:** Deprecated, use `vars` instead.
|
||||
|
||||
## inventory
|
||||
JSON-like structure used to configure multiple machines.
|
||||
|
||||
## machine
|
||||
A physical computer or virtual machine.
|
||||
|
||||
## role
|
||||
Specific function assigned to a machine within a service.
|
||||
Allows assignment of sane default configurations in multi-machine services.
|
||||
|
||||
## vars
|
||||
System for creating secrets and public files in a declarative way.
|
||||
@@ -6,7 +6,7 @@ This section of the site provides an overview of available options and commands
|
||||
|
||||
- Learn how to use the [Clan CLI](./cli/index.md)
|
||||
- Explore available services and application [modules](./clanModules/index.md)
|
||||
- Discover [configuration options](./clan-core/index.md) that manage essential features
|
||||
- Discover [configuration options](./clan.core/index.md) that manage essential features
|
||||
- Find descriptions of the [Nix interfaces](./nix-api/buildclan.md) for defining a Clan
|
||||
|
||||
---
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user