Compare commits
1 Commits
monitoring
...
test-updat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71407f88bf |
@@ -1,12 +0,0 @@
|
||||
## Description of the change
|
||||
|
||||
<!-- Brief summary of the change if not already clear from the title -->
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Updated Documentation
|
||||
- [ ] Added tests
|
||||
- [ ] Doesn't affect backwards compatibility - or check the next points
|
||||
- [ ] Add the breaking change and migration details to docs/release-notes.md
|
||||
- !!! Review from another person is required *BEFORE* merge !!!
|
||||
- [ ] Add introduction of major feature to docs/release-notes.md
|
||||
@@ -17,4 +17,4 @@ jobs:
|
||||
|
||||
- name: Build clan-app for x86_64-darwin
|
||||
run: |
|
||||
nix build .#packages.x86_64-darwin.clan-app --log-format bar-with-logs
|
||||
nix build .#packages.x86_64-darwin.clan-app --system x86_64-darwin --log-format bar-with-logs
|
||||
|
||||
@@ -8,6 +8,6 @@ jobs:
|
||||
runs-on: nix
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: nix run --print-build-logs .#deploy-docs
|
||||
- run: nix run .#deploy-docs
|
||||
env:
|
||||
SSH_HOMEPAGE_KEY: ${{ secrets.SSH_HOMEPAGE_KEY }}
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -52,5 +52,3 @@ pkgs/clan-app/ui/.fonts
|
||||
*.gif
|
||||
*.mp4
|
||||
*.mkv
|
||||
|
||||
.jj
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
clanServices/.* @pinpox @kenji
|
||||
|
||||
lib/test/container-test-driver/.* @DavHau @mic92
|
||||
lib/inventory/.* @hsjobeki
|
||||
lib/inventoryClass/.* @hsjobeki
|
||||
|
||||
modules/.* @hsjobeki
|
||||
lib/modules/inventory/.* @hsjobeki
|
||||
lib/modules/inventoryClass/.* @hsjobeki
|
||||
|
||||
pkgs/clan-app/ui/.* @hsjobeki @brianmcgee
|
||||
pkgs/clan-app/clan_app/.* @qubasa @hsjobeki
|
||||
|
||||
4
CONTRIBUTING.md
Normal file
4
CONTRIBUTING.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Contributing to Clan
|
||||
|
||||
<!-- Local file: docs/CONTRIBUTING.md -->
|
||||
Go to the Contributing guide at https://docs.clan.lol/guides/contributing/CONTRIBUTING
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright 2023-2025 Clan contributors
|
||||
Copyright 2023-2024 Clan contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
||||
@@ -30,7 +30,7 @@ In the Clan ecosystem, security is paramount. Learn how to handle secrets effect
|
||||
|
||||
The Clan project thrives on community contributions. We welcome everyone to contribute and collaborate:
|
||||
|
||||
- **Contribution Guidelines**: Make a meaningful impact by following the steps in [contributing](https://docs.clan.lol/guides/contributing/CONTRIBUTING/)<!-- [contributing.md](docs/CONTRIBUTING.md) -->.
|
||||
- **Contribution Guidelines**: Make a meaningful impact by following the steps in [contributing](https://docs.clan.lol/contributing/contributing/)<!-- [contributing.md](docs/CONTRIBUTING.md) -->.
|
||||
|
||||
## Join the revolution
|
||||
|
||||
|
||||
6
checks/clan-core-for-checks.nix
Normal file
6
checks/clan-core-for-checks.nix
Normal file
@@ -0,0 +1,6 @@
|
||||
{ fetchgit }:
|
||||
fetchgit {
|
||||
url = "https://git.clan.lol/clan/clan-core.git";
|
||||
rev = "5d884cecc2585a29b6a3596681839d081b4de192";
|
||||
sha256 = "09is1afmncamavb2q88qac37vmsijxzsy1iz1vr6gsyjq2rixaxc";
|
||||
}
|
||||
@@ -12,6 +12,7 @@ let
|
||||
elem
|
||||
filter
|
||||
filterAttrs
|
||||
flip
|
||||
genAttrs
|
||||
hasPrefix
|
||||
pathExists
|
||||
@@ -19,23 +20,32 @@ let
|
||||
nixosLib = import (self.inputs.nixpkgs + "/nixos/lib") { };
|
||||
in
|
||||
{
|
||||
imports = filter pathExists [
|
||||
./devshell/flake-module.nix
|
||||
./flash/flake-module.nix
|
||||
./installation/flake-module.nix
|
||||
./update/flake-module.nix
|
||||
./morph/flake-module.nix
|
||||
./nixos-documentation/flake-module.nix
|
||||
./dont-depend-on-repo-root.nix
|
||||
# clan core submodule tests
|
||||
../nixosModules/clanCore/machine-id/tests/flake-module.nix
|
||||
../nixosModules/clanCore/postgresql/tests/flake-module.nix
|
||||
../nixosModules/clanCore/state-version/tests/flake-module.nix
|
||||
];
|
||||
imports =
|
||||
let
|
||||
clanCoreModulesDir = ../nixosModules/clanCore;
|
||||
getClanCoreTestModules =
|
||||
let
|
||||
moduleNames = attrNames (builtins.readDir clanCoreModulesDir);
|
||||
testPaths = map (
|
||||
moduleName: clanCoreModulesDir + "/${moduleName}/tests/flake-module.nix"
|
||||
) moduleNames;
|
||||
in
|
||||
filter pathExists testPaths;
|
||||
in
|
||||
getClanCoreTestModules
|
||||
++ filter pathExists [
|
||||
./devshell/flake-module.nix
|
||||
./flash/flake-module.nix
|
||||
./installation/flake-module.nix
|
||||
./update/flake-module.nix
|
||||
./morph/flake-module.nix
|
||||
./nixos-documentation/flake-module.nix
|
||||
./dont-depend-on-repo-root.nix
|
||||
];
|
||||
flake.check = genAttrs [ "x86_64-linux" "aarch64-darwin" ] (
|
||||
system:
|
||||
let
|
||||
checks = filterAttrs (
|
||||
checks = flip filterAttrs self.checks.${system} (
|
||||
name: _check:
|
||||
!(hasPrefix "nixos-test-" name)
|
||||
&& !(hasPrefix "nixos-" name)
|
||||
@@ -47,7 +57,7 @@ in
|
||||
"clan-core-for-checks"
|
||||
"clan-deps"
|
||||
])
|
||||
) self.checks.${system};
|
||||
);
|
||||
in
|
||||
inputs.nixpkgs.legacyPackages.${system}.runCommand "fast-flake-checks-${system}"
|
||||
{ passthru.checks = checks; }
|
||||
@@ -86,13 +96,11 @@ in
|
||||
|
||||
# Container Tests
|
||||
nixos-test-container = self.clanLib.test.containerTest ./container nixosTestArgs;
|
||||
nixos-systemd-abstraction = self.clanLib.test.containerTest ./systemd-abstraction nixosTestArgs;
|
||||
nixos-llm-test = self.clanLib.test.containerTest ./llm nixosTestArgs;
|
||||
nixos-test-user-firewall-iptables = self.clanLib.test.containerTest ./user-firewall/iptables.nix nixosTestArgs;
|
||||
nixos-test-user-firewall-nftables = self.clanLib.test.containerTest ./user-firewall/nftables.nix nixosTestArgs;
|
||||
nixos-test-extra-python-packages = self.clanLib.test.containerTest ./test-extra-python-packages nixosTestArgs;
|
||||
|
||||
service-dummy-test = import ./service-dummy-test nixosTestArgs;
|
||||
wireguard = import ./wireguard nixosTestArgs;
|
||||
service-dummy-test-from-flake = import ./service-dummy-test-from-flake nixosTestArgs;
|
||||
};
|
||||
|
||||
@@ -113,7 +121,7 @@ in
|
||||
) (self.darwinConfigurations or { })
|
||||
// lib.mapAttrs' (n: lib.nameValuePair "package-${n}") (
|
||||
if system == "aarch64-darwin" then
|
||||
lib.filterAttrs (n: _: n != "docs" && n != "deploy-docs" && n != "option-search") packagesToBuild
|
||||
lib.filterAttrs (n: _: n != "docs" && n != "deploy-docs" && n != "docs-options") packagesToBuild
|
||||
else
|
||||
packagesToBuild
|
||||
)
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
fileSystems."/".device = lib.mkDefault "/dev/vda";
|
||||
boot.loader.grub.device = lib.mkDefault "/dev/vda";
|
||||
|
||||
# We need to use `mkForce` because we inherit from `test-install-machine`
|
||||
# which currently hardcodes `nixpkgs.hostPlatform`
|
||||
nixpkgs.hostPlatform = lib.mkForce system;
|
||||
|
||||
imports = [ self.nixosModules.test-flash-machine ];
|
||||
@@ -26,24 +28,10 @@
|
||||
{
|
||||
imports = [ self.nixosModules.test-install-machine-without-system ];
|
||||
|
||||
# We don't want our system to define any `vars` generators as these can't
|
||||
# be generated as the flake is inside `/nix/store`.
|
||||
clan.core.settings.state-version.enable = false;
|
||||
clan.core.vars.generators.test = lib.mkForce { };
|
||||
|
||||
disko.devices.disk.main.preCreateHook = lib.mkForce "";
|
||||
|
||||
# Every option here should match the options set through `clan flash write`
|
||||
# if you get a mass rebuild on the disko derivation, this means you need to
|
||||
# adjust something here. Also make sure that the injected json in clan flash write
|
||||
# is up to date.
|
||||
i18n.defaultLocale = "de_DE.UTF-8";
|
||||
console.keyMap = "de";
|
||||
services.xserver.xkb.layout = "de";
|
||||
users.users.root.openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIRWUusawhlIorx7VFeQJHmMkhl9X3QpnvOdhnV/bQNG root@target\n"
|
||||
];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
perSystem =
|
||||
@@ -56,11 +44,8 @@
|
||||
dependencies = [
|
||||
pkgs.disko
|
||||
pkgs.buildPackages.xorg.lndir
|
||||
pkgs.glibcLocales
|
||||
pkgs.kbd.out
|
||||
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".pkgs.perlPackages.ConfigIniFiles
|
||||
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".pkgs.perlPackages.FileSlurp
|
||||
pkgs.bubblewrap
|
||||
|
||||
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".config.system.build.toplevel
|
||||
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".config.system.build.diskoScript
|
||||
@@ -88,7 +73,7 @@
|
||||
substituters = lib.mkForce [ ];
|
||||
hashed-mirrors = null;
|
||||
connect-timeout = lib.mkForce 3;
|
||||
flake-registry = "";
|
||||
flake-registry = pkgs.writeText "flake-registry" ''{"flakes":[],"version":2}'';
|
||||
experimental-features = [
|
||||
"nix-command"
|
||||
"flakes"
|
||||
@@ -97,10 +82,10 @@
|
||||
};
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine.succeed("echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIRWUusawhlIorx7VFeQJHmMkhl9X3QpnvOdhnV/bQNG root@target' > ./test_id_ed25519.pub")
|
||||
|
||||
# Some distros like to automount disks with spaces
|
||||
machine.succeed('mkdir -p "/mnt/with spaces" && mkfs.ext4 /dev/vdc && mount /dev/vdc "/mnt/with spaces"')
|
||||
machine.succeed("clan flash write --ssh-pubkey ./test_id_ed25519.pub --keymap de --language de_DE.UTF-8 --debug --flake ${self.checks.x86_64-linux.clan-core-for-checks} --yes --disk main /dev/vdc test-flash-machine-${pkgs.hostPlatform.system}")
|
||||
machine.succeed("clan flash write --debug --flake ${self.checks.x86_64-linux.clan-core-for-checks} --yes --disk main /dev/vdc test-flash-machine-${pkgs.hostPlatform.system}")
|
||||
'';
|
||||
} { inherit pkgs self; };
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
config,
|
||||
self,
|
||||
lib,
|
||||
privateInputs,
|
||||
|
||||
...
|
||||
}:
|
||||
{
|
||||
@@ -14,38 +14,31 @@
|
||||
# you can get a new one by adding
|
||||
# client.fail("cat test-flake/machines/test-install-machine/facter.json >&2")
|
||||
# to the installation test.
|
||||
clan.machines = {
|
||||
test-install-machine-without-system = {
|
||||
clan.machines.test-install-machine-without-system = {
|
||||
fileSystems."/".device = lib.mkDefault "/dev/vda";
|
||||
boot.loader.grub.device = lib.mkDefault "/dev/vda";
|
||||
|
||||
imports = [ self.nixosModules.test-install-machine-without-system ];
|
||||
};
|
||||
clan.machines.test-install-machine-with-system =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
# https://git.clan.lol/clan/test-fixtures
|
||||
facter.reportPath = builtins.fetchurl {
|
||||
url = "https://git.clan.lol/clan/test-fixtures/raw/commit/4a2bc56d886578124b05060d3fb7eddc38c019f8/nixos-vm-facter-json/${pkgs.hostPlatform.system}.json";
|
||||
sha256 =
|
||||
{
|
||||
aarch64-linux = "sha256:1rlfymk03rmfkm2qgrc8l5kj5i20srx79n1y1h4nzlpwaz0j7hh2";
|
||||
x86_64-linux = "sha256:16myh0ll2gdwsiwkjw5ba4dl23ppwbsanxx214863j7nvzx42pws";
|
||||
}
|
||||
.${pkgs.hostPlatform.system};
|
||||
};
|
||||
|
||||
fileSystems."/".device = lib.mkDefault "/dev/vda";
|
||||
boot.loader.grub.device = lib.mkDefault "/dev/vda";
|
||||
|
||||
imports = [
|
||||
self.nixosModules.test-install-machine-without-system
|
||||
];
|
||||
imports = [ self.nixosModules.test-install-machine-without-system ];
|
||||
};
|
||||
}
|
||||
// (lib.listToAttrs (
|
||||
lib.map (
|
||||
system:
|
||||
lib.nameValuePair "test-install-machine-${system}" {
|
||||
imports = [
|
||||
self.nixosModules.test-install-machine-without-system
|
||||
(
|
||||
if privateInputs ? test-fixtures then
|
||||
{
|
||||
facter.reportPath = privateInputs.test-fixtures + /nixos-vm-facter-json/${system}.json;
|
||||
}
|
||||
else
|
||||
{ nixpkgs.hostPlatform = system; }
|
||||
)
|
||||
];
|
||||
|
||||
fileSystems."/".device = lib.mkDefault "/dev/vda";
|
||||
boot.loader.grub.device = lib.mkDefault "/dev/vda";
|
||||
}
|
||||
) (lib.filter (lib.hasSuffix "linux") config.systems)
|
||||
));
|
||||
|
||||
flake.nixosModules = {
|
||||
test-install-machine-without-system =
|
||||
{ lib, modulesPath, ... }:
|
||||
@@ -160,9 +153,9 @@
|
||||
closureInfo = pkgs.closureInfo {
|
||||
rootPaths = [
|
||||
privateInputs.clan-core-for-checks
|
||||
self.nixosConfigurations."test-install-machine-${pkgs.hostPlatform.system}".config.system.build.toplevel
|
||||
self.nixosConfigurations."test-install-machine-${pkgs.hostPlatform.system}".config.system.build.initialRamdisk
|
||||
self.nixosConfigurations."test-install-machine-${pkgs.hostPlatform.system}".config.system.build.diskoScript
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.toplevel
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.initialRamdisk
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.diskoScript
|
||||
pkgs.stdenv.drvPath
|
||||
pkgs.bash.drvPath
|
||||
pkgs.buildPackages.xorg.lndir
|
||||
@@ -215,7 +208,7 @@
|
||||
# Prepare test flake and Nix store
|
||||
flake_dir = prepare_test_flake(
|
||||
temp_dir,
|
||||
"${self.checks.${pkgs.hostPlatform.system}.clan-core-for-checks}",
|
||||
"${self.checks.x86_64-linux.clan-core-for-checks}",
|
||||
"${closureInfo}"
|
||||
)
|
||||
|
||||
@@ -226,22 +219,6 @@
|
||||
"${../assets/ssh/privkey}"
|
||||
)
|
||||
|
||||
# Run clan install from host using port forwarding
|
||||
clan_cmd = [
|
||||
"${self.packages.${pkgs.system}.clan-cli-full}/bin/clan",
|
||||
"machines",
|
||||
"init-hardware-config",
|
||||
"--debug",
|
||||
"--flake", str(flake_dir),
|
||||
"--yes", "test-install-machine-without-system",
|
||||
"--host-key-check", "none",
|
||||
"--target-host", f"nonrootuser@localhost:{ssh_conn.host_port}",
|
||||
"-i", ssh_conn.ssh_key,
|
||||
"--option", "store", os.environ['CLAN_TEST_STORE']
|
||||
]
|
||||
subprocess.run(clan_cmd, check=True)
|
||||
|
||||
|
||||
# Run clan install from host using port forwarding
|
||||
clan_cmd = [
|
||||
"${self.packages.${pkgs.system}.clan-cli-full}/bin/clan",
|
||||
@@ -296,7 +273,7 @@
|
||||
# Prepare test flake and Nix store
|
||||
flake_dir = prepare_test_flake(
|
||||
temp_dir,
|
||||
"${self.checks.${pkgs.hostPlatform.system}.clan-core-for-checks}",
|
||||
"${self.checks.x86_64-linux.clan-core-for-checks}",
|
||||
"${closureInfo}"
|
||||
)
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ let
|
||||
networking.useNetworkd = true;
|
||||
services.openssh.enable = true;
|
||||
services.openssh.settings.UseDns = false;
|
||||
services.openssh.settings.PasswordAuthentication = false;
|
||||
system.nixos.variant_id = "installer";
|
||||
environment.systemPackages = [
|
||||
pkgs.nixos-facter
|
||||
@@ -146,11 +147,28 @@ let
|
||||
];
|
||||
doCheck = false;
|
||||
};
|
||||
|
||||
# Common closure info
|
||||
closureInfo = pkgs.closureInfo {
|
||||
rootPaths = [
|
||||
self.checks.x86_64-linux.clan-core-for-checks
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.toplevel
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.initialRamdisk
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.diskoScript
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.clan.deployment.file
|
||||
pkgs.stdenv.drvPath
|
||||
pkgs.bash.drvPath
|
||||
pkgs.buildPackages.xorg.lndir
|
||||
]
|
||||
++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
inherit
|
||||
target
|
||||
baseTestMachine
|
||||
nixosTestLib
|
||||
closureInfo
|
||||
;
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
{ self, pkgs, ... }:
|
||||
|
||||
let
|
||||
|
||||
cli = self.packages.${pkgs.hostPlatform.system}.clan-cli-full;
|
||||
|
||||
ollama-model = pkgs.callPackage ./qwen3-4b-instruct.nix { };
|
||||
in
|
||||
{
|
||||
name = "llm";
|
||||
|
||||
nodes = {
|
||||
peer1 =
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
|
||||
users.users.text-user = {
|
||||
isNormalUser = true;
|
||||
linger = true;
|
||||
uid = 1000;
|
||||
extraGroups = [ "systemd-journal" ];
|
||||
};
|
||||
|
||||
# Set environment variables for user systemd
|
||||
environment.extraInit = ''
|
||||
if [ "$(id -u)" = "1000" ]; then
|
||||
export XDG_RUNTIME_DIR="/run/user/1000"
|
||||
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
|
||||
|
||||
ollama_dir="$HOME/.ollama"
|
||||
mkdir -p "$ollama_dir"
|
||||
ln -sf ${ollama-model}/models "$ollama_dir"/models
|
||||
fi
|
||||
'';
|
||||
|
||||
# Enable PAM for user systemd sessions
|
||||
security.pam.services.systemd-user = {
|
||||
startSession = true;
|
||||
# Workaround for containers - use pam_permit to avoid helper binary issues
|
||||
text = pkgs.lib.mkForce ''
|
||||
account required pam_permit.so
|
||||
session required pam_permit.so
|
||||
session required pam_env.so conffile=/etc/pam/environment readenv=0
|
||||
session required ${pkgs.systemd}/lib/security/pam_systemd.so
|
||||
'';
|
||||
};
|
||||
|
||||
environment.systemPackages = [
|
||||
cli
|
||||
pkgs.ollama
|
||||
(cli.pythonRuntime.withPackages (
|
||||
ps: with ps; [
|
||||
pytest
|
||||
pytest-xdist
|
||||
(cli.pythonRuntime.pkgs.toPythonModule cli)
|
||||
self.legacyPackages.${pkgs.hostPlatform.system}.nixosTestLib
|
||||
]
|
||||
))
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript =
|
||||
{ ... }:
|
||||
''
|
||||
start_all()
|
||||
|
||||
peer1.wait_for_unit("multi-user.target")
|
||||
peer1.wait_for_unit("user@1000.service")
|
||||
|
||||
# Fix user journal permissions so text-user can read their own logs
|
||||
peer1.succeed("chown text-user:systemd-journal /var/log/journal/*/user-1000.journal*")
|
||||
peer1.succeed("chmod 640 /var/log/journal/*/user-1000.journal*")
|
||||
# the -o adopts="" is needed to overwrite any args coming from pyproject.toml
|
||||
# -p no:cacheprovider disables pytest's cacheprovider which tries to write to the nix store in this case
|
||||
cmd = "su - text-user -c 'pytest -s -n0 -m service_runner -p no:cacheprovider -o addopts="" ${cli.passthru.sourceWithTests}/clan_lib/llm'"
|
||||
print("Running tests with command: " + cmd)
|
||||
|
||||
# Run tests as text-user (environment variables are set automatically)
|
||||
peer1.succeed(cmd)
|
||||
'';
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
{ pkgs }:
|
||||
|
||||
let
|
||||
# Got them from https://github.com/Gholamrezadar/ollama-direct-downloader
|
||||
|
||||
# Download manifest
|
||||
manifest = pkgs.fetchurl {
|
||||
url = "https://registry.ollama.ai/v2/library/qwen3/manifests/4b-instruct";
|
||||
# You'll need to calculate this hash - run the derivation once and it will tell you the correct hash
|
||||
hash = "sha256-Dtze80WT6sGqK+nH0GxDLc+BlFrcpeyi8nZiwY8Wi6A=";
|
||||
};
|
||||
|
||||
# Download blobs
|
||||
blob1 = pkgs.fetchurl {
|
||||
url = "https://registry.ollama.ai/v2/library/qwen3/blobs/sha256:b72accf9724e93698c57cbd3b1af2d3341b3d05ec2089d86d273d97964853cd2";
|
||||
hash = "sha256-tyrM+XJOk2mMV8vTsa8tM0Gz0F7CCJ2G0nPZeWSFPNI=";
|
||||
};
|
||||
|
||||
blob2 = pkgs.fetchurl {
|
||||
url = "https://registry.ollama.ai/v2/library/qwen3/blobs/sha256:85e4a5b7b8ef0e48af0e8658f5aaab9c2324c76c1641493f4d1e25fce54b18b9";
|
||||
hash = "sha256-heSlt7jvDkivDoZY9aqrnCMkx2wWQUk/TR4l/OVLGLk=";
|
||||
};
|
||||
|
||||
blob3 = pkgs.fetchurl {
|
||||
url = "https://registry.ollama.ai/v2/library/qwen3/blobs/sha256:eade0a07cac7712787bbce23d12f9306adb4781d873d1df6e16f7840fa37afec";
|
||||
hash = "sha256-6t4KB8rHcSeHu84j0S+TBq20eB2HPR324W94QPo3r+w=";
|
||||
};
|
||||
|
||||
blob4 = pkgs.fetchurl {
|
||||
url = "https://registry.ollama.ai/v2/library/qwen3/blobs/sha256:d18a5cc71b84bc4af394a31116bd3932b42241de70c77d2b76d69a314ec8aa12";
|
||||
hash = "sha256-0YpcxxuEvErzlKMRFr05MrQiQd5wx30rdtaaMU7IqhI=";
|
||||
};
|
||||
|
||||
blob5 = pkgs.fetchurl {
|
||||
url = "https://registry.ollama.ai/v2/library/qwen3/blobs/sha256:0914c7781e001948488d937994217538375b4fd8c1466c5e7a625221abd3ea7a";
|
||||
hash = "sha256-CRTHeB4AGUhIjZN5lCF1ODdbT9jBRmxeemJSIavT6no=";
|
||||
};
|
||||
in
|
||||
pkgs.stdenv.mkDerivation {
|
||||
pname = "ollama-qwen3-4b-instruct";
|
||||
version = "1.0";
|
||||
|
||||
dontUnpack = true;
|
||||
|
||||
buildPhase = ''
|
||||
mkdir -p $out/models/manifests/registry.ollama.ai/library/qwen3
|
||||
mkdir -p $out/models/blobs
|
||||
|
||||
# Copy manifest
|
||||
cp ${manifest} $out/models/manifests/registry.ollama.ai/library/qwen3/4b-instruct
|
||||
|
||||
# Copy blobs with correct names
|
||||
cp ${blob1} $out/models/blobs/sha256-b72accf9724e93698c57cbd3b1af2d3341b3d05ec2089d86d273d97964853cd2
|
||||
cp ${blob2} $out/models/blobs/sha256-85e4a5b7b8ef0e48af0e8658f5aaab9c2324c76c1641493f4d1e25fce54b18b9
|
||||
cp ${blob3} $out/models/blobs/sha256-eade0a07cac7712787bbce23d12f9306adb4781d873d1df6e16f7840fa37afec
|
||||
cp ${blob4} $out/models/blobs/sha256-d18a5cc71b84bc4af394a31116bd3932b42241de70c77d2b76d69a314ec8aa12
|
||||
cp ${blob5} $out/models/blobs/sha256-0914c7781e001948488d937994217538375b4fd8c1466c5e7a625221abd3ea7a
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
# buildPhase already created everything in $out
|
||||
:
|
||||
'';
|
||||
|
||||
meta = with pkgs.lib; {
|
||||
description = "Qwen3 4B Instruct model for Ollama";
|
||||
license = "apache-2.0";
|
||||
platforms = platforms.all;
|
||||
};
|
||||
}
|
||||
@@ -29,34 +29,32 @@ nixosLib.runTest (
|
||||
{ nodes, ... }:
|
||||
''
|
||||
import subprocess
|
||||
import tempfile
|
||||
from nixos_test_lib.nix_setup import setup_nix_in_nix
|
||||
from nixos_test_lib.nix_setup import setup_nix_in_nix # type: ignore[import-untyped]
|
||||
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
setup_nix_in_nix(temp_dir, None) # No closure info for this test
|
||||
setup_nix_in_nix(None) # No closure info for this test
|
||||
|
||||
start_all()
|
||||
admin1.wait_for_unit("multi-user.target")
|
||||
peer1.wait_for_unit("multi-user.target")
|
||||
start_all()
|
||||
admin1.wait_for_unit("multi-user.target")
|
||||
peer1.wait_for_unit("multi-user.target")
|
||||
|
||||
# peer1 should have the 'hello' file
|
||||
peer1.succeed("cat ${nodes.peer1.clan.core.vars.generators.new-service.files.not-a-secret.path}")
|
||||
# peer1 should have the 'hello' file
|
||||
peer1.succeed("cat ${nodes.peer1.clan.core.vars.generators.new-service.files.not-a-secret.path}")
|
||||
|
||||
ls_out = peer1.succeed("ls -la ${nodes.peer1.clan.core.vars.generators.new-service.files.a-secret.path}")
|
||||
# Check that the file is owned by 'nobody'
|
||||
assert "nobody" in ls_out, f"File is not owned by 'nobody': {ls_out}"
|
||||
# Check that the file is in the 'users' group
|
||||
assert "users" in ls_out, f"File is not in the 'users' group: {ls_out}"
|
||||
# Check that the file is in the '0644' mode
|
||||
assert "-rw-r--r--" in ls_out, f"File is not in the '0644' mode: {ls_out}"
|
||||
ls_out = peer1.succeed("ls -la ${nodes.peer1.clan.core.vars.generators.new-service.files.a-secret.path}")
|
||||
# Check that the file is owned by 'nobody'
|
||||
assert "nobody" in ls_out, f"File is not owned by 'nobody': {ls_out}"
|
||||
# Check that the file is in the 'users' group
|
||||
assert "users" in ls_out, f"File is not in the 'users' group: {ls_out}"
|
||||
# Check that the file is in the '0644' mode
|
||||
assert "-rw-r--r--" in ls_out, f"File is not in the '0644' mode: {ls_out}"
|
||||
|
||||
# Run clan command
|
||||
result = subprocess.run(
|
||||
["${
|
||||
clan-core.packages.${hostPkgs.system}.clan-cli
|
||||
}/bin/clan", "machines", "list", "--flake", "${config.clan.test.flakeForSandbox}"],
|
||||
check=True
|
||||
)
|
||||
# Run clan command
|
||||
result = subprocess.run(
|
||||
["${
|
||||
clan-core.packages.${hostPkgs.system}.clan-cli
|
||||
}/bin/clan", "machines", "list", "--flake", "${config.clan.test.flakeForSandbox}"],
|
||||
check=True
|
||||
)
|
||||
'';
|
||||
}
|
||||
)
|
||||
|
||||
@@ -27,10 +27,7 @@
|
||||
modules.new-service = {
|
||||
_class = "clan.service";
|
||||
manifest.name = "new-service";
|
||||
manifest.readme = "Just a sample readme to not trigger the warning.";
|
||||
roles.peer = {
|
||||
description = "A peer that uses the new-service to generate some files.";
|
||||
};
|
||||
roles.peer = { };
|
||||
perMachine = {
|
||||
nixosModule = {
|
||||
# This should be generated by:
|
||||
|
||||
@@ -34,10 +34,7 @@ nixosLib.runTest (
|
||||
modules.new-service = {
|
||||
_class = "clan.service";
|
||||
manifest.name = "new-service";
|
||||
manifest.readme = "Just a sample readme to not trigger the warning.";
|
||||
roles.peer = {
|
||||
description = "A peer that uses the new-service to generate some files.";
|
||||
};
|
||||
roles.peer = { };
|
||||
perMachine = {
|
||||
nixosModule = {
|
||||
# This should be generated by:
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
{ self, pkgs, ... }:
|
||||
|
||||
let
|
||||
|
||||
cli = self.packages.${pkgs.hostPlatform.system}.clan-cli-full;
|
||||
in
|
||||
{
|
||||
name = "systemd-abstraction";
|
||||
|
||||
nodes = {
|
||||
peer1 = {
|
||||
|
||||
users.users.text-user = {
|
||||
isNormalUser = true;
|
||||
linger = true;
|
||||
uid = 1000;
|
||||
extraGroups = [ "systemd-journal" ];
|
||||
};
|
||||
|
||||
# Set environment variables for user systemd
|
||||
environment.extraInit = ''
|
||||
if [ "$(id -u)" = "1000" ]; then
|
||||
export XDG_RUNTIME_DIR="/run/user/1000"
|
||||
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
|
||||
fi
|
||||
'';
|
||||
|
||||
# Enable PAM for user systemd sessions
|
||||
security.pam.services.systemd-user = {
|
||||
startSession = true;
|
||||
# Workaround for containers - use pam_permit to avoid helper binary issues
|
||||
text = pkgs.lib.mkForce ''
|
||||
account required pam_permit.so
|
||||
session required pam_permit.so
|
||||
session required pam_env.so conffile=/etc/pam/environment readenv=0
|
||||
session required ${pkgs.systemd}/lib/security/pam_systemd.so
|
||||
'';
|
||||
};
|
||||
|
||||
environment.systemPackages = [
|
||||
cli
|
||||
(cli.pythonRuntime.withPackages (
|
||||
ps: with ps; [
|
||||
pytest
|
||||
pytest-xdist
|
||||
]
|
||||
))
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
testScript =
|
||||
{ ... }:
|
||||
''
|
||||
start_all()
|
||||
|
||||
peer1.wait_for_unit("multi-user.target")
|
||||
peer1.wait_for_unit("user@1000.service")
|
||||
|
||||
# Fix user journal permissions so text-user can read their own logs
|
||||
peer1.succeed("chown text-user:systemd-journal /var/log/journal/*/user-1000.journal*")
|
||||
peer1.succeed("chmod 640 /var/log/journal/*/user-1000.journal*")
|
||||
|
||||
# Run tests as text-user (environment variables are set automatically)
|
||||
peer1.succeed("su - text-user -c 'pytest -p no:cacheprovider -o addopts="" -s -n0 ${cli.passthru.sourceWithTests}/clan_lib/service_runner'")
|
||||
'';
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
(
|
||||
{ ... }:
|
||||
{
|
||||
name = "test-extra-python-packages";
|
||||
|
||||
extraPythonPackages = ps: [ ps.numpy ];
|
||||
|
||||
nodes.machine =
|
||||
{ ... }:
|
||||
{
|
||||
networking.hostName = "machine";
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
import numpy as np
|
||||
|
||||
start_all()
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
|
||||
# Test availability of numpy
|
||||
arr = np.array([1, 2, 3])
|
||||
print(f"Numpy array: {arr}")
|
||||
assert len(arr) == 3
|
||||
'';
|
||||
}
|
||||
)
|
||||
@@ -67,15 +67,6 @@
|
||||
];
|
||||
};
|
||||
|
||||
nix.settings = {
|
||||
flake-registry = "";
|
||||
# required for setting the `flake-registry`
|
||||
experimental-features = [
|
||||
"nix-command"
|
||||
"flakes"
|
||||
];
|
||||
};
|
||||
|
||||
# Define the mounts that exist in the container to prevent them from being stopped
|
||||
fileSystems = {
|
||||
"/" = {
|
||||
@@ -115,13 +106,12 @@
|
||||
let
|
||||
closureInfo = pkgs.closureInfo {
|
||||
rootPaths = [
|
||||
self.packages.${pkgs.hostPlatform.system}.clan-cli
|
||||
self.checks.${pkgs.hostPlatform.system}.clan-core-for-checks
|
||||
self.packages.${pkgs.system}.clan-cli
|
||||
self.checks.${pkgs.system}.clan-core-for-checks
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test-update-machine.config.system.build.toplevel
|
||||
pkgs.stdenv.drvPath
|
||||
pkgs.bash.drvPath
|
||||
pkgs.buildPackages.xorg.lndir
|
||||
pkgs.bubblewrap
|
||||
]
|
||||
++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
|
||||
};
|
||||
@@ -132,7 +122,7 @@
|
||||
imports = [ self.nixosModules.test-update-machine ];
|
||||
};
|
||||
extraPythonPackages = _p: [
|
||||
self.legacyPackages.${pkgs.hostPlatform.system}.nixosTestLib
|
||||
self.legacyPackages.${pkgs.system}.nixosTestLib
|
||||
];
|
||||
|
||||
testScript = ''
|
||||
@@ -154,7 +144,7 @@
|
||||
# Prepare test flake and Nix store
|
||||
flake_dir = prepare_test_flake(
|
||||
temp_dir,
|
||||
"${self.checks.${pkgs.hostPlatform.system}.clan-core-for-checks}",
|
||||
"${self.checks.x86_64-linux.clan-core-for-checks}",
|
||||
"${closureInfo}"
|
||||
)
|
||||
(flake_dir / ".clan-flake").write_text("") # Ensure .clan-flake exists
|
||||
@@ -221,13 +211,12 @@
|
||||
[
|
||||
"${pkgs.nix}/bin/nix",
|
||||
"copy",
|
||||
"--from",
|
||||
f"{temp_dir}/store",
|
||||
"--to",
|
||||
"ssh://root@192.168.1.1",
|
||||
"--no-check-sigs",
|
||||
f"${self.packages.${pkgs.hostPlatform.system}.clan-cli}",
|
||||
f"${self.packages.${pkgs.system}.clan-cli}",
|
||||
"--extra-experimental-features", "nix-command flakes",
|
||||
"--from", f"{os.environ["TMPDIR"]}/store"
|
||||
],
|
||||
check=True,
|
||||
env={
|
||||
@@ -242,7 +231,7 @@
|
||||
"-o", "UserKnownHostsFile=/dev/null",
|
||||
"-o", "StrictHostKeyChecking=no",
|
||||
f"root@192.168.1.1",
|
||||
"${self.packages.${pkgs.hostPlatform.system}.clan-cli}/bin/clan",
|
||||
"${self.packages.${pkgs.system}.clan-cli}/bin/clan",
|
||||
"machines",
|
||||
"update",
|
||||
"--debug",
|
||||
@@ -270,7 +259,7 @@
|
||||
|
||||
# Run clan update command
|
||||
subprocess.run([
|
||||
"${self.packages.${pkgs.hostPlatform.system}.clan-cli-full}/bin/clan",
|
||||
"${self.packages.${pkgs.system}.clan-cli-full}/bin/clan",
|
||||
"machines",
|
||||
"update",
|
||||
"--debug",
|
||||
@@ -297,7 +286,7 @@
|
||||
|
||||
# Run clan update command with --build-host
|
||||
subprocess.run([
|
||||
"${self.packages.${pkgs.hostPlatform.system}.clan-cli-full}/bin/clan",
|
||||
"${self.packages.${pkgs.system}.clan-cli-full}/bin/clan",
|
||||
"machines",
|
||||
"update",
|
||||
"--debug",
|
||||
|
||||
115
checks/wireguard/default.nix
Normal file
115
checks/wireguard/default.nix
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
pkgs,
|
||||
nixosLib,
|
||||
clan-core,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
nixosLib.runTest (
|
||||
{ ... }:
|
||||
|
||||
let
|
||||
machines = [
|
||||
"controller1"
|
||||
"controller2"
|
||||
"peer1"
|
||||
"peer2"
|
||||
"peer3"
|
||||
];
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
clan-core.modules.nixosTest.clanTest
|
||||
];
|
||||
|
||||
hostPkgs = pkgs;
|
||||
|
||||
name = "wireguard";
|
||||
|
||||
clan = {
|
||||
directory = ./.;
|
||||
modules."@clan/wireguard" = import ../../clanServices/wireguard/default.nix;
|
||||
inventory = {
|
||||
|
||||
machines = lib.genAttrs machines (_: { });
|
||||
|
||||
instances = {
|
||||
|
||||
/*
|
||||
wg-test-one
|
||||
┌───────────────────────────────┐
|
||||
│ ◄───────────── │
|
||||
│ controller2 controller1
|
||||
│ ▲ ─────────────► ▲ ▲
|
||||
│ │ │ │ │ │ │ │ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
│ │ │ │ │ │ │ │ │
|
||||
│ │ │ │ └───────────────┐ │ │ │ │
|
||||
│ │ │ └──────────────┐ │ │ │ │ │
|
||||
│ ▼ │ ▼ ▼ ▼
|
||||
└─► peer2 │ peer1 peer3
|
||||
│ ▲
|
||||
└──────────┘
|
||||
*/
|
||||
|
||||
wg-test-one = {
|
||||
|
||||
module.name = "@clan/wireguard";
|
||||
module.input = "self";
|
||||
|
||||
roles.controller.machines."controller1".settings = {
|
||||
endpoint = "192.168.1.1";
|
||||
};
|
||||
|
||||
roles.controller.machines."controller2".settings = {
|
||||
endpoint = "192.168.1.2";
|
||||
};
|
||||
|
||||
roles.peer.machines = {
|
||||
peer1.settings.controller = "controller1";
|
||||
peer2.settings.controller = "controller2";
|
||||
peer3.settings.controller = "controller1";
|
||||
};
|
||||
};
|
||||
|
||||
# TODO: Will this actually work with conflicting ports? Can we re-use interfaces?
|
||||
#wg-test-two = {
|
||||
# module.name = "@clan/wireguard";
|
||||
|
||||
# roles.controller.machines."controller1".settings = {
|
||||
# endpoint = "192.168.1.1";
|
||||
# port = 51922;
|
||||
# };
|
||||
|
||||
# roles.peer.machines = {
|
||||
# peer1 = { };
|
||||
# };
|
||||
#};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
# Show all addresses
|
||||
machines = [peer1, peer2, peer3, controller1, controller2]
|
||||
for m in machines:
|
||||
m.systemctl("start network-online.target")
|
||||
|
||||
for m in machines:
|
||||
m.wait_for_unit("network-online.target")
|
||||
m.wait_for_unit("systemd-networkd.service")
|
||||
|
||||
print("\n\n" + "="*60)
|
||||
print("STARTING PING TESTS")
|
||||
print("="*60)
|
||||
|
||||
for m1 in machines:
|
||||
for m2 in machines:
|
||||
if m1 != m2:
|
||||
print(f"\n--- Pinging from {m1.name} to {m2.name}.wg-test-one ---")
|
||||
m1.wait_until_succeeds(f"ping -c1 {m2.name}.wg-test-one >&2")
|
||||
'';
|
||||
}
|
||||
)
|
||||
@@ -1,25 +0,0 @@
|
||||
The admin service aggregates components that allow an administrator to log in to and manage the machine.
|
||||
|
||||
The following configuration:
|
||||
|
||||
1. Enables OpenSSH with root login and adds an SSH public key named`myusersKey` to the machine's authorized_keys via the `allowedKeys` setting.
|
||||
|
||||
2. Automatically generates a password for the root user.
|
||||
|
||||
```nix
|
||||
instances = {
|
||||
admin = {
|
||||
roles.default.tags = {
|
||||
all = { };
|
||||
};
|
||||
roles.default.settings = {
|
||||
allowedKeys = {
|
||||
myusersKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEFDNnynMbFWatSFdANzbJ8iiEKL7+9ZpDaMLrWRQjyH lhebendanz@wintux";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{ ... }:
|
||||
{
|
||||
_class = "clan.service";
|
||||
manifest.name = "clan-core/admin";
|
||||
manifest.description = "Adds a root user with ssh access";
|
||||
manifest.description = "Convenient Administration for the Clan App";
|
||||
manifest.categories = [ "Utility" ];
|
||||
manifest.readme = builtins.readFile ./README.md;
|
||||
|
||||
roles.default = {
|
||||
description = "Placeholder role to apply the admin service";
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
|
||||
options = {
|
||||
allowedKeys = lib.mkOption {
|
||||
default = { };
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ ... }:
|
||||
{ lib, ... }:
|
||||
let
|
||||
module = ./default.nix;
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -2,7 +2,7 @@ let
|
||||
public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII6zj7ubTg6z/aDwRNwvM/WlQdUocMprQ8E92NWxl6t+ test@test";
|
||||
in
|
||||
{
|
||||
name = "admin";
|
||||
name = "service-admin";
|
||||
|
||||
clan = {
|
||||
directory = ./.;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
25.11
|
||||
@@ -1 +0,0 @@
|
||||
25.11
|
||||
@@ -5,11 +5,11 @@ inventory.instances = {
|
||||
borgbackup = {
|
||||
module = {
|
||||
name = "borgbackup";
|
||||
input = "clan-core";
|
||||
input = "clan";
|
||||
};
|
||||
roles.client.machines."jon".settings = {
|
||||
destinations."storagebox" = {
|
||||
repo = "username@hostname:/./borgbackup";
|
||||
repo = "username@$hostname:/./borgbackup";
|
||||
rsh = ''ssh -oPort=23 -i /run/secrets/vars/borgbackup/borgbackup.ssh'';
|
||||
};
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
# TODO: a client can only be in one instance, add constraint
|
||||
|
||||
roles.server = {
|
||||
description = "A borgbackup server that stores the backups of clients.";
|
||||
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
@@ -54,7 +54,7 @@
|
||||
authorizedKeys = [ (builtins.readFile (borgbackupIpMachinePath machineName)) ];
|
||||
# };
|
||||
# }) machinesWithKey;
|
||||
}) (roles.client.machines or { });
|
||||
}) roles.client.machines;
|
||||
in
|
||||
hosts;
|
||||
};
|
||||
@@ -62,7 +62,6 @@
|
||||
};
|
||||
|
||||
roles.client = {
|
||||
description = "A borgbackup client that backs up to all borgbackup server roles.";
|
||||
interface =
|
||||
{
|
||||
lib,
|
||||
@@ -188,7 +187,7 @@
|
||||
config.clan.core.vars.generators.borgbackup.files."borgbackup.ssh".path
|
||||
} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=Yes";
|
||||
};
|
||||
}) (builtins.attrNames (roles.server.machines or { }));
|
||||
}) (builtins.attrNames roles.server.machines);
|
||||
in
|
||||
(builtins.listToAttrs destinations);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ ... }:
|
||||
{ lib, ... }:
|
||||
let
|
||||
module = ./default.nix;
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
...
|
||||
}:
|
||||
{
|
||||
name = "borgbackup";
|
||||
name = "service-borgbackup";
|
||||
|
||||
clan = {
|
||||
directory = ./.;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
25.11
|
||||
@@ -1 +0,0 @@
|
||||
25.11
|
||||
@@ -2,12 +2,12 @@
|
||||
{
|
||||
_class = "clan.service";
|
||||
manifest.name = "certificates";
|
||||
manifest.description = "Sets up a PKI certificate chain using step-ca";
|
||||
manifest.description = "Sets up a certificates internal to your Clan";
|
||||
manifest.categories = [ "Network" ];
|
||||
manifest.readme = builtins.readFile ./README.md;
|
||||
|
||||
roles.ca = {
|
||||
description = "A certificate authority that issues and signs certificates for other machines.";
|
||||
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
@@ -184,7 +184,6 @@
|
||||
|
||||
# Empty role, so we can add non-ca machins to the instance to trust the CA
|
||||
roles.default = {
|
||||
description = "A machine that trusts the CA and can get certificates issued by it.";
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
{
|
||||
self,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
module = ./default.nix;
|
||||
module = lib.modules.importApply ./default.nix {
|
||||
inherit (self) packages;
|
||||
};
|
||||
in
|
||||
{
|
||||
clan.modules.certificates = module;
|
||||
|
||||
@@ -8,7 +8,7 @@ The service consists of two roles:
|
||||
- A `server` role: This is the DNS-server that will be queried when trying to
|
||||
resolve clan-internal services. It defines the top-level domain.
|
||||
- A `default` role: This does two things. First, it sets up the nameservers so
|
||||
that clan-internal queries are resolved via the `server` machine, while
|
||||
thatclan-internal queries are resolved via the `server` machine, while
|
||||
external queries are resolved as normal via DHCP. Second, it allows exposing
|
||||
services (see example below).
|
||||
|
||||
@@ -45,15 +45,13 @@ inventory = {
|
||||
# Add the default role to all machines, including `client`
|
||||
roles.default.tags.all = { };
|
||||
|
||||
# DNS server queries to http://<name>.foo are resolved here
|
||||
# DNS server
|
||||
roles.server.machines."dnsserver".settings = {
|
||||
ip = "192.168.1.2";
|
||||
tld = "foo";
|
||||
};
|
||||
|
||||
# First service
|
||||
# Registers http://one.foo will resolve to 192.168.1.3
|
||||
# underlying service runs on server01
|
||||
roles.default.machines."server01".settings = {
|
||||
ip = "192.168.1.3";
|
||||
services = [ "one" ];
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
_class = "clan.service";
|
||||
manifest.name = "coredns";
|
||||
@@ -8,7 +7,7 @@
|
||||
manifest.readme = builtins.readFile ./README.md;
|
||||
|
||||
roles.server = {
|
||||
description = "A DNS server that resolves services in the clan network.";
|
||||
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
@@ -26,12 +25,6 @@
|
||||
# TODO: Set a default
|
||||
description = "IP for the DNS to listen on";
|
||||
};
|
||||
|
||||
options.dnsPort = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 1053;
|
||||
description = "Port of the clan-internal DNS server";
|
||||
};
|
||||
};
|
||||
|
||||
perInstance =
|
||||
@@ -49,8 +42,8 @@
|
||||
}:
|
||||
{
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ settings.dnsPort ];
|
||||
networking.firewall.allowedUDPPorts = [ settings.dnsPort ];
|
||||
networking.firewall.allowedTCPPorts = [ 53 ];
|
||||
networking.firewall.allowedUDPPorts = [ 53 ];
|
||||
|
||||
services.coredns =
|
||||
let
|
||||
@@ -81,29 +74,22 @@
|
||||
in
|
||||
{
|
||||
enable = true;
|
||||
config =
|
||||
config = ''
|
||||
. {
|
||||
forward . 1.1.1.1
|
||||
cache 30
|
||||
}
|
||||
|
||||
let
|
||||
dnsPort = builtins.toString settings.dnsPort;
|
||||
in
|
||||
|
||||
''
|
||||
.:${dnsPort} {
|
||||
forward . 1.1.1.1
|
||||
cache 30
|
||||
}
|
||||
|
||||
${settings.tld}:${dnsPort} {
|
||||
file ${zonefile}
|
||||
}
|
||||
'';
|
||||
${settings.tld} {
|
||||
file ${zonefile}
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
roles.default = {
|
||||
description = "A machine that registers the 'server' role as resolver and registers services under the configured TLD in the resolver.";
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
@@ -121,16 +107,10 @@
|
||||
# TODO: Set a default
|
||||
description = "IP on which the services will listen";
|
||||
};
|
||||
|
||||
options.dnsPort = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 1053;
|
||||
description = "Port of the clan-internal DNS server";
|
||||
};
|
||||
};
|
||||
|
||||
perInstance =
|
||||
{ roles, settings, ... }:
|
||||
{ roles, ... }:
|
||||
{
|
||||
nixosModule =
|
||||
{ lib, ... }:
|
||||
@@ -167,7 +147,7 @@
|
||||
];
|
||||
stub-zone = map (m: {
|
||||
name = "${roles.server.machines.${m}.settings.tld}.";
|
||||
stub-addr = "${roles.server.machines.${m}.settings.ip}@${builtins.toString settings.dnsPort}";
|
||||
stub-addr = "${roles.server.machines.${m}.settings.ip}";
|
||||
}) (lib.attrNames roles.server.machines);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ ... }:
|
||||
{ lib, ... }:
|
||||
let
|
||||
module = ./default.nix;
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -95,15 +95,18 @@
|
||||
for m in machines:
|
||||
m.wait_for_unit("network-online.target")
|
||||
|
||||
# import time
|
||||
# time.sleep(2333333)
|
||||
|
||||
# This should work, but is borken in tests i think? Instead we dig directly
|
||||
|
||||
# client.succeed("curl -k -v http://one.foo")
|
||||
# client.succeed("curl -k -v http://two.foo")
|
||||
|
||||
answer = client.succeed("dig @192.168.1.2 -p 1053 one.foo")
|
||||
answer = client.succeed("dig @192.168.1.2 one.foo")
|
||||
assert "192.168.1.3" in answer, "IP not found"
|
||||
|
||||
answer = client.succeed("dig @192.168.1.2 -p 1053 two.foo")
|
||||
answer = client.succeed("dig @192.168.1.2 two.foo")
|
||||
assert "192.168.1.4" in answer, "IP not found"
|
||||
|
||||
'';
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
{
|
||||
clanLib,
|
||||
...
|
||||
}:
|
||||
{ ... }:
|
||||
let
|
||||
sharedInterface =
|
||||
{ lib, ... }:
|
||||
@@ -54,15 +51,15 @@ let
|
||||
builtins.foldl' (
|
||||
urls: name:
|
||||
let
|
||||
ip = clanLib.vars.getPublicValue {
|
||||
flake = config.clan.core.settings.directory;
|
||||
machine = name;
|
||||
generator = "zerotier";
|
||||
file = "zerotier-ip";
|
||||
default = null;
|
||||
};
|
||||
ipPath = "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value";
|
||||
in
|
||||
if ip != null then urls ++ [ "[${ip}]:${builtins.toString settings.network.port}" ] else urls
|
||||
if builtins.pathExists ipPath then
|
||||
let
|
||||
ip = builtins.readFile ipPath;
|
||||
in
|
||||
urls ++ [ "[${ip}]:${builtins.toString settings.network.port}" ]
|
||||
else
|
||||
urls
|
||||
) [ ] (builtins.attrNames ((roles.admin.machines or { }) // (roles.signer.machines or { })))
|
||||
);
|
||||
|
||||
@@ -104,7 +101,6 @@ in
|
||||
manifest.readme = builtins.readFile ./README.md;
|
||||
|
||||
roles.admin = {
|
||||
description = "A data-mesher admin node that bootstraps the network and can sign new nodes into the network.";
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
@@ -159,14 +155,9 @@ in
|
||||
readHostKey =
|
||||
machine:
|
||||
let
|
||||
publicKey = clanLib.vars.getPublicValue {
|
||||
flake = config.clan.core.settings.directory;
|
||||
inherit machine;
|
||||
generator = "data-mesher-host-key";
|
||||
file = "public_key";
|
||||
};
|
||||
path = "${config.clan.core.settings.directory}/vars/per-machine/${machine}/data-mesher-host-key/public_key/value";
|
||||
in
|
||||
builtins.elemAt (lib.splitString "\n" publicKey) 1;
|
||||
builtins.elemAt (lib.splitString "\n" (builtins.readFile path)) 1;
|
||||
in
|
||||
{
|
||||
enable = true;
|
||||
@@ -186,7 +177,6 @@ in
|
||||
};
|
||||
|
||||
roles.signer = {
|
||||
description = "A data-mesher signer node that can sign new nodes into the network.";
|
||||
interface = sharedInterface;
|
||||
perInstance =
|
||||
{
|
||||
@@ -218,7 +208,6 @@ in
|
||||
};
|
||||
|
||||
roles.peer = {
|
||||
description = "A data-mesher peer node that connects to the network.";
|
||||
interface = sharedInterface;
|
||||
perInstance =
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ ... }:
|
||||
{ lib, ... }:
|
||||
let
|
||||
module = ./default.nix;
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
@@ -9,7 +9,7 @@ in
|
||||
perSystem =
|
||||
{ ... }:
|
||||
{
|
||||
clan.nixosTests.data-mesher = {
|
||||
clan.nixosTests.service-data-mesher = {
|
||||
imports = [ ./tests/vm/default.nix ];
|
||||
clan.modules."@clan/data-mesher" = module;
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
...
|
||||
}:
|
||||
{
|
||||
name = "data-mesher";
|
||||
name = "service-data-mesher";
|
||||
|
||||
clan = {
|
||||
directory = ./.;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
25.11
|
||||
@@ -1 +0,0 @@
|
||||
25.11
|
||||
@@ -1 +0,0 @@
|
||||
25.11
|
||||
@@ -2,12 +2,11 @@
|
||||
{
|
||||
_class = "clan.service";
|
||||
manifest.name = "clan-core/dyndns";
|
||||
manifest.description = "A dynamic DNS service to auto update domain IPs";
|
||||
manifest.description = "A dynamic DNS service to update domain IPs";
|
||||
manifest.categories = [ "Network" ];
|
||||
manifest.readme = builtins.readFile ./README.md;
|
||||
|
||||
roles.default = {
|
||||
description = "Placeholder role to apply the dyndns service";
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ ... }:
|
||||
{ lib, ... }:
|
||||
let
|
||||
module = ./default.nix;
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
...
|
||||
}:
|
||||
{
|
||||
name = "dyndns";
|
||||
name = "service-dyndns";
|
||||
|
||||
clan = {
|
||||
directory = ./.;
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
[
|
||||
{
|
||||
"publickey": "age164wrhlnake7f7duhzs936lq6w49dtg53hcdyxqwxj0agad6tqg2s2u4yta",
|
||||
"type": "age"
|
||||
}
|
||||
]
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:seLxbv590dO0KvMJmtN7WVvUcH27VYwAc3rmyD7q6ZmwCgswOKx55LFnh0stRDKSZa8K7Dq1x7D9adhZtPAMWX8tbJswBeNMPt8=,iv:G52eugxfTi0tTzH4EN4CWmpyv6feSL34++UVSjb0aAo=,tag:6r10/a7kD2hBAmae0nz2OQ==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHVC8wZUZJYUl5MXVNa2k5\ndGV1MnFWbUNLNVdxeEtCVUc3MTd0ck9aeFFBCnFhZW40amVYc3FlN1FPRTFSWTJR\nQzhNOERKbnRnSlJVeElNSEM5ZUJsZGsKLS0tIG1uNnlNN3MweHlYczNRTW9xSytu\neThzUmxKZTJBT2lCcTdiNUI4N3paTVEKgS9j2/GVt1KBoggUj9d6UK/mIlK4niLQ\nzVq2BHt3irxQpkpGUogXH2b86zSAOEJFzsL1Rk8HM1mogTG8jqf0qA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-10-19T12:49:11Z",
|
||||
"mac": "ENC[AES256_GCM,data:T/2xw2mvUi8YALyxz78qG/g/xguoUTeHNzcZfXwwSyCXMg9ircsGGLO9SOVWy/QNkibnw3Yp80tXNJyr4oJH28PhFH7RrRp8jzNdopF49ZNJb2IqJ3C7xNYRZMHfjOCd/raka+ehZq8YGilEpXUWLRk1ere9lbBMh1ycL7jJS3c=,iv:FZbY/jTNPM+p4qD41FD0K7B9zoppGuvnUY5hL/EkmYM=,tag:IF5QTyUkHXWthlAGBn9R8w==,type:str]",
|
||||
"version": "3.11.0"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
25.11
|
||||
@@ -1 +0,0 @@
|
||||
../../../../../sops/machines/server
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:Zu+n+DDYP7rQRTS17PJ6Apo=,iv:5WOs81Pj+S85kdC1AlOXSyPMGDfwM5UD8x7nyRZtRYQ=,tag:2JYkGnLugAni49Upv43o2g==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age164wrhlnake7f7duhzs936lq6w49dtg53hcdyxqwxj0agad6tqg2s2u4yta",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlR3RGQ2ZLTkR3ZWxNVCsv\naXJHRjBiVUVYZVRIY2swY2xubGhmb3pLRkNvCldhQUV2WDlqYjZ4ZUFWYXkvUEEw\nZi9XRWw0Mi9mRENDcnI0aENDR2Z4MHcKLS0tIGFQU3Q4WEErbnBjOHpNR1BSR2cr\nRFg0anE1cHExT0sySmxuUks1R05nczAKZO3R6+f9co2+YGO8HPufoq1fLqqrdTWD\n4zqemMmG2BjMRDumxtcKp8CLaZWlJoP4e/+tonfdoe42qmNF5NJcFw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzZWo4WGh1cWxKeDhDdlBm\nTVFjVFBIUU9xaGRkanNHaUVUUHN1czNRSUhNCkp5MmwzSGdycmsrZGhaRUhEbXBF\nNUhtdEF6bHZQOGJYUVhFVHlYc3FPODAKLS0tIDBRQ2VGT2IvU1F4MEVabzhYSFJq\nOWZmbGpkQmNSMnNKa0s4K2JXdGgwRlkKUQRREpG5H1mNHSc/cZrdMiSz0veJFR4N\n+W49XL/wQUZwajykwYj++G+dWDO7DQ+fpbB9w4mzbsAmCsXirseTLA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-10-19T12:49:11Z",
|
||||
"mac": "ENC[AES256_GCM,data:0msda7WbQQxXQ+juT7yErgT7NADgnzqEZLTQw+4JPuAE4xcqRIYwrrAALaA0GCCM2aIWlICzJigLCuzQUfSUbIzeP79tEHiKez+NOt/xgSM9ljz7GlsmLd0vzkxdt3WSxP+sHxy0S866N2sLMUkLqPGdqeTjB+Jji5ghGhzk9ys=,iv:8UU7iA4SdR6ZlVolm708l2Iea0sQYRT+5wPBBP5tpS0=,tag:VQXslAlqLqs1QEkwW6x6qg==,type:str]",
|
||||
"version": "3.11.0"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user