Merge pull request 'dummy-test: add vars' (#3940) from davhau/test into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/3940
This commit is contained in:
61
checks/dummy-inventory-test-from-flake/default.nix
Normal file
61
checks/dummy-inventory-test-from-flake/default.nix
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
nixosLib,
|
||||||
|
clan-core,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
nixosLib.runTest (
|
||||||
|
{ hostPkgs, config, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
clan-core.modules.nixosVmTest.clanTest
|
||||||
|
];
|
||||||
|
|
||||||
|
hostPkgs = pkgs;
|
||||||
|
|
||||||
|
# This tests the compatibility of the inventory
|
||||||
|
# With the test framework
|
||||||
|
# - legacy-modules
|
||||||
|
# - clan.service modules
|
||||||
|
name = "dummy-inventory-test-from-flake";
|
||||||
|
|
||||||
|
clan.test.fromFlake = ./.;
|
||||||
|
|
||||||
|
testScript =
|
||||||
|
{ nodes, ... }:
|
||||||
|
''
|
||||||
|
${clan-core.legacyPackages.${hostPkgs.system}.setupNixInNixPython}
|
||||||
|
|
||||||
|
def run_clan(cmd: list[str], **kwargs) -> str:
|
||||||
|
import subprocess
|
||||||
|
clan = "${clan-core.packages.${hostPkgs.system}.clan-cli}/bin/clan"
|
||||||
|
clan_args = ["--flake", "${config.clan.test.flakeForSandbox}"]
|
||||||
|
return subprocess.run(
|
||||||
|
["${hostPkgs.util-linux}/bin/unshare", "--user", "--map-user", "1000", "--map-group", "1000", clan, *cmd, *clan_args],
|
||||||
|
**kwargs,
|
||||||
|
check=True,
|
||||||
|
).stdout
|
||||||
|
|
||||||
|
start_all()
|
||||||
|
admin1.wait_for_unit("multi-user.target")
|
||||||
|
peer1.wait_for_unit("multi-user.target")
|
||||||
|
# Provided by the legacy module
|
||||||
|
print(admin1.succeed("systemctl status dummy-service"))
|
||||||
|
print(peer1.succeed("systemctl status dummy-service"))
|
||||||
|
|
||||||
|
# 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}"
|
||||||
|
|
||||||
|
run_clan(["machines", "list"])
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
)
|
||||||
70
checks/dummy-inventory-test-from-flake/flake.nix
Normal file
70
checks/dummy-inventory-test-from-flake/flake.nix
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
inputs.clan-core.url = "https://git.clan.lol/clan/clan-core/archive/main.tar.gz";
|
||||||
|
inputs.nixpkgs.follows = "clan-core/nixpkgs";
|
||||||
|
|
||||||
|
outputs =
|
||||||
|
{ self, clan-core, ... }:
|
||||||
|
let
|
||||||
|
# Usage see: https://docs.clan.lol
|
||||||
|
clan = clan-core.clanLib.buildClan {
|
||||||
|
inherit self;
|
||||||
|
|
||||||
|
inventory =
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
meta.name = "foo";
|
||||||
|
machines.peer1 = { };
|
||||||
|
machines.admin1 = { };
|
||||||
|
services = {
|
||||||
|
legacy-module.default = {
|
||||||
|
roles.peer.machines = [ "peer1" ];
|
||||||
|
roles.admin.machines = [ "admin1" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
instances."test" = {
|
||||||
|
module.name = "new-service";
|
||||||
|
roles.peer.machines.peer1 = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
modules = {
|
||||||
|
legacy-module = ./legacy-module;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
modules.new-service = {
|
||||||
|
_class = "clan.service";
|
||||||
|
manifest.name = "new-service";
|
||||||
|
roles.peer = { };
|
||||||
|
perMachine = {
|
||||||
|
nixosModule = {
|
||||||
|
# This should be generated by:
|
||||||
|
# nix run .#generate-test-vars -- checks/dummy-inventory-test dummy-inventory-test
|
||||||
|
clan.core.vars.generators.new-service = {
|
||||||
|
files.not-a-secret = {
|
||||||
|
secret = false;
|
||||||
|
deploy = true;
|
||||||
|
};
|
||||||
|
files.a-secret = {
|
||||||
|
secret = true;
|
||||||
|
deploy = true;
|
||||||
|
owner = "nobody";
|
||||||
|
group = "users";
|
||||||
|
mode = "0644";
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
# This is a dummy script that does nothing
|
||||||
|
echo -n "not-a-secret" > $out/not-a-secret
|
||||||
|
echo -n "a-secret" > $out/a-secret
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# all machines managed by Clan
|
||||||
|
inherit (clan) nixosConfigurations nixosModules clanInternals;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
description = "Set up dummy-module"
|
||||||
|
categories = ["System"]
|
||||||
|
features = [ "inventory" ]
|
||||||
|
|
||||||
|
[constraints]
|
||||||
|
roles.admin.min = 1
|
||||||
|
roles.admin.max = 1
|
||||||
|
---
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
imports = [
|
||||||
|
../shared.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
imports = [
|
||||||
|
../shared.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
|
systemd.services.dummy-service = {
|
||||||
|
enable = true;
|
||||||
|
description = "Dummy service";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
generated_password_path="${config.clan.core.vars.generators.dummy-generator.files.generated-password.path}"
|
||||||
|
if [ ! -f "$generated_password_path" ]; then
|
||||||
|
echo "Generated password file not found: $generated_password_path"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
host_id_path="${config.clan.core.vars.generators.dummy-generator.files.host-id.path}"
|
||||||
|
if [ ! -e "$host_id_path" ]; then
|
||||||
|
echo "Host ID file not found: $host_id_path"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO: add and prompt and make it work in the test framework
|
||||||
|
clan.core.vars.generators.dummy-generator = {
|
||||||
|
files.host-id.secret = false;
|
||||||
|
files.generated-password.secret = true;
|
||||||
|
script = ''
|
||||||
|
echo $RANDOM > "$out"/host-id
|
||||||
|
echo $RANDOM > "$out"/generated-password
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
6
checks/dummy-inventory-test-from-flake/sops/machines/admin1/key.json
Executable file
6
checks/dummy-inventory-test-from-flake/sops/machines/admin1/key.json
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"publickey": "age12yt078p9ewxy2sh0a36nxdpgglv8wqqftmj4dkj9rgy5fuyn4p0q5nje9m",
|
||||||
|
"type": "age"
|
||||||
|
}
|
||||||
|
]
|
||||||
6
checks/dummy-inventory-test-from-flake/sops/machines/peer1/key.json
Executable file
6
checks/dummy-inventory-test-from-flake/sops/machines/peer1/key.json
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"publickey": "age12w2ld4vxfyf3hdq2d8la4cu0tye4pq97egvv3me4wary7xkdnq2snh0zx2",
|
||||||
|
"type": "age"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"data": "ENC[AES256_GCM,data:GPpsUhSzWPtTP8EUNKsobFXjYqDldhkkIH6hBk11RsDLAGWdhVrwcISGbhsWpYhvAdPKA84DB6Zqyh9lL2bLM9//ybC1kzY20BQ=,iv:NrxMLdedT2FCkUAD00SwsAHchIsxWvqe7BQekWuJcxw=,tag:pMDXcMyHnLF2t3Qhb1KolA==,type:str]",
|
||||||
|
"sops": {
|
||||||
|
"age": [
|
||||||
|
{
|
||||||
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzb2tWb1ExKzdmUTRzaGVj\nK3cyYTBHZTJwVjM1SzUvbHFiMnVhY05iKzFZCnJTSE1VSVdpcUFLSEJuaE1CZzJD\nWjZxYzN2cUltdThNMVRKU3FIb20vUXMKLS0tIFlHQXRIdnMybDZFUVEzWlQrc1dw\nbUxhZURXblhHd0pka0JIK1FTZEVqdUEKI/rfxQRBc+xGRelhswkJQ9GcZs6lzfgy\nuCxS5JI9npdPLQ/131F3b21+sP5YWqks41uZG+vslM1zQ+BlENNhDw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastmodified": "2025-05-04T12:44:13Z",
|
||||||
|
"mac": "ENC[AES256_GCM,data:fWxLHXBWolHVxv6Q7utcy6OVLV13ziswrIYyNKiwy1vsU8i7xvvuGO1HlnE+q43D2WuHR53liKq1UHuf1JMrWzTwZ0PYe+CVugtoEtbR2qu3rK/jAkOyMyhmmHzmf6Rp4ZMCzKgZeC/X2bDKY/z0firHAvjWydEyogutHpvtznM=,iv:OQI3FfkLneqbdztAXVQB3UkHwDPK+0hWu5hZ9m8Oczg=,tag:em6GfS2QHsXs391QKPxfmA==,type:str]",
|
||||||
|
"unencrypted_suffix": "_unencrypted",
|
||||||
|
"version": "3.10.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../users/admin
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"data": "ENC[AES256_GCM,data:W3cOkUYL5/YulW2pEISyTlMaA/t7/WBE7BoCdFlqrqgaCL7tG4IV2HgjiPWzIVMs0zvDSaghdEvAIoB4wOf470d1nSWs0/E8SDk=,iv:wXXaZIw3sPY8L/wxsu7+C5v+d3RQRuwxZRP4YLkS8K4=,tag:HeK4okj7O7XDA9JDz2KULw==,type:str]",
|
||||||
|
"sops": {
|
||||||
|
"age": [
|
||||||
|
{
|
||||||
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxRC83b3dtSVpXcGovNnVs\nTzFka2J2MEFhYkF1ajVrdjMrNUtPWGRObjM4Cm5zSUR5OGw0T0FaL3BaWmR6L29W\nU2syMFIyMUhFRUZpWFpCT28vWko2ZU0KLS0tIFpHK3BjU1V1L0FrMGtwTGFuU3Mz\nRkV5VjI2Vndod202bUR3RWQwNXpmVzQKNk8/y7M62wTIIKqY4r3ZRk5aUCRUfine\n1LUSHMKa2bRe+hR7nS7AF4BGXp03h2UPY0FP5+U5q8XuIj1jfMX8kg==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastmodified": "2025-05-04T12:44:16Z",
|
||||||
|
"mac": "ENC[AES256_GCM,data:yTkQeFvKrN1+5FP+yInsaRWSAG+ZGG0uWF3+gVRvzJTFxab8kT2XkAMc+4D7SKgcjsmwBBb77GNoAKaKByhZ92UaCfZ2X66i7ZmYUwLM1NVVmm+xiwwjsh7PJXlZO/70anTzd1evtlZse0jEmRnV5Y0F0M6YqXmuwU+qGUJU2F8=,iv:sy6ozhXonWVruaQfa7pdEoV5GkNZR/UbbINKAPbgWeg=,tag:VMruQ1KExmlMR7TsGNgMlg==,type:str]",
|
||||||
|
"unencrypted_suffix": "_unencrypted",
|
||||||
|
"version": "3.10.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../users/admin
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
|
"type": "age"
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../../../sops/machines/admin1
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"data": "ENC[AES256_GCM,data:T8edCvw=,iv:7/G5xt5fv38I9uFzk7WMIr9xQdz/6lFxqOC+18HBg8Q=,tag:F39Cxbgmzml+lZLsZ59Kmg==,type:str]",
|
||||||
|
"sops": {
|
||||||
|
"age": [
|
||||||
|
{
|
||||||
|
"recipient": "age12yt078p9ewxy2sh0a36nxdpgglv8wqqftmj4dkj9rgy5fuyn4p0q5nje9m",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPNUhiYkZWK3dPMHNiRTVM\nRHNvaHFsOFp1c0UxQitwVG0zY01MNDZRV1E4CjEybENoTVIzN29vQ3FtUTRSYmFU\nNXIzQllVSllXRGN2M1B6WXJLdHZSajgKLS0tIDllZ0ZmZUcxMHhDQUpUOEdWbmkv\neUQweHArYTdFSmNteVpuQ3BKdnh0Y0UKs8Hm3D+rXRRfpUVSZM3zYjs6b9z8g10D\nGTkvreUMim4CS22pjdQ3eNA9TGeDXfWXE7XzwXLCb+wVcf7KwbDmvg==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKSDhpT3cvck9PenZYVEZH\ndFQreVRBdG93L1dBUGlvYjFWcDlHWUJsZUVBCm9DMTJ4UytiYzlEVHNWdUcwS1ds\nT0dhbzAzNDdmbDBCU0dvL2xNeHpXcGsKLS0tIFArbmpsbzU3WnpJdUt1MGN0L1d0\nV1JkTDJYWUxsbmhTQVNOeVRaSUhTODQKk9Vph2eldS5nwuvVX0SCsxEm4B+sO76Z\ndIjJ3OQxzoZmXMaOOuKHC5U0Y75Qn7eXC43w5KHsl2CMIUYsBGJOZw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastmodified": "2025-05-04T12:44:14Z",
|
||||||
|
"mac": "ENC[AES256_GCM,data:6fKrS1eLLUWlHkQpxLFXBRk6f2wa5ADLMViVvYXXGU24ayl9UuNSKrCRHp9cbzhqhti3HdwyNt6TM+2X6qhiiAQanKEB2PF7JRYX74NfNKil9BEDjt5AqqtpSgVv5l7Ku/uSHaPkd2sDmzHsy5Q4bSGxJQokStk1kidrwle+mbc=,iv:I/Aad82L/TCxStM8d8IZICUrwdjRbGx2fuGWqexr21o=,tag:BfgRbGUxhPZzK2fLik1kxA==,type:str]",
|
||||||
|
"unencrypted_suffix": "_unencrypted",
|
||||||
|
"version": "3.10.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../../../sops/users/admin
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
18650
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../../../sops/machines/peer1
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"data": "ENC[AES256_GCM,data:vp0yW0Gt,iv:FO2cy+UpEl5aRay/LUGu//c82QiVxuKuGSaVh0rGJvc=,tag:vf2RAOPpcRW0HwxHoGy17A==,type:str]",
|
||||||
|
"sops": {
|
||||||
|
"age": [
|
||||||
|
{
|
||||||
|
"recipient": "age12w2ld4vxfyf3hdq2d8la4cu0tye4pq97egvv3me4wary7xkdnq2snh0zx2",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjaFVNMEd2YUxpSm5XVVRi\nY2ZUc3NTOStJUFNMWWVPQTgxZ2tCK1QrMW1ZCjYwMlA4dkIzSlc0TGtvZjcyK3Bi\nM3pob2JOOFUyeVJ6M2JpaTRCZlc1R0kKLS0tIDJMb1dFcVRWckhwYWNCQng0RlFO\nTkw3OGt4dkFIZVY5aVEzZE5mMzJSM0EKUv8bUqg48L2FfYVUVlpXvyZvPye699of\nG6PcjLh1ZMbNCfnsCzr+P8Vdk/F4J/ifxL66lRGfu2xOLxwciwQ+5Q==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnZ2dDbVhoQngxM3lTSmZF\nUTAwS1lCTGhEMU1GVXpFUzlIUFdqZy9LajF3Ck9mdVpBRjlyVUNhZXZIUFZjUzF1\nNlhFN28vNmwzcUVkNmlzUnpkWjJuZE0KLS0tIHpXVHVlNk9vU1ZPTGRrYStWbmRO\nbDM4U2o1SlEwYWtqOXBqd3BFUTAvMHcKkI8UVd0v+x+ELZ5CoGq9DzlA6DnVNU2r\nrV9wLfbFd7RHxS0/TYZh5tmU42nO3iMYA9FqERQXCtZgXS9KvfqHwQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastmodified": "2025-05-04T12:44:18Z",
|
||||||
|
"mac": "ENC[AES256_GCM,data:1ZZ+ZI1JsHmxTov1bRijfol3kTkyheg2o3ivLsMHRhCmScsUry97hQJchF78+y2Izt7avaQEHYn6pVbYt/0rLrSYD7Ru7ITVxXoYHOiN5Qb98masUzpibZjrdyg5nO+LW5/Hmmwsc3yn/+o3IH1AUYpsxlJRdnHHCmoSOFaiFFM=,iv:OQlgmpOTw4ljujNzqwQ5/0Mz8pQpCSUtqRvj3FJAxDs=,tag:foZvdeW7gK9ZVKkWqnlxGA==,type:str]",
|
||||||
|
"unencrypted_suffix": "_unencrypted",
|
||||||
|
"version": "3.10.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../../../sops/users/admin
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
6745
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../../../sops/machines/peer1
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"data": "ENC[AES256_GCM,data:prFl0EJy8bM=,iv:zITWxf+6Ebk0iB5vhhd7SBQa1HFrIJXm8xpSM+D9I0M=,tag:NZCRMCs1SzNKLBu/KUDKMQ==,type:str]",
|
||||||
|
"sops": {
|
||||||
|
"age": [
|
||||||
|
{
|
||||||
|
"recipient": "age12w2ld4vxfyf3hdq2d8la4cu0tye4pq97egvv3me4wary7xkdnq2snh0zx2",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0S0RZRWxaZVZvTUhjdWVL\naU9WZmtEcm1qa2JsRmdvdmZmNENMaWFEVUFRCmdoVnRXSGlpRlFjNmVVbDJ5VnFT\nMnVJUlVnM3lxNmZCRTdoRVJ4NW1oYWcKLS0tIFFNbXBFUk1RWnlUTW1SeG1vYzlM\nVVpEclFVOE9PWWQxVkZ0eEgwWndoRWcKDAOHe+FIxqGsc6LhxMy164qjwG6t2Ei2\nP0FSs+bcKMDpudxeuxCjnDm/VoLxOWeuqkB+9K2vSm2W/c/fHTSbrA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||||
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2VU5jOEpwYUtDVEVFcVpU\nQkExTVZ3ejZHcGo5TG8zdUQwNktoV09WdUZvCmQ0dE1TOWRFbTlxdVd4WWRxd3VF\nQUNTTkNNT3NKYjQ5dEJDY0xVZ3pZVUUKLS0tIDFjajRZNFJZUTdNeS8yN05FMFZU\ncEtjRjhRbGE0MnRLdk10NkFLMkxqencKGzJ66dHluIghH04RV/FccfEQP07yqnfb\n25Hi0XIVJfXBwje4UEyszrWTxPPwVXdQDQmoNKf76Qy2jYqJ56uksw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"lastmodified": "2025-05-04T12:44:20Z",
|
||||||
|
"mac": "ENC[AES256_GCM,data:FIkilsni5kOdNlVwDuLsQ/zExypHRWdqIBQDNWMLTwe8OrsNPkX+KYutUvt9GaSoGv4iDULaMRoizO/OZUNfc2d8XYSdj0cxOG1Joov4GPUcC/UGyNuQneAejZBKolvlnidKZArofnuK9g+lOTANEUtEXUTnx8L+VahqPZayQas=,iv:NAo6sT3L8OOB3wv1pjr3RY2FwXgVmZ4N0F4BEX4YPUY=,tag:zHwmXygyvkdpASZCodQT9Q==,type:str]",
|
||||||
|
"unencrypted_suffix": "_unencrypted",
|
||||||
|
"version": "3.10.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
../../../../../../sops/users/admin
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
not-a-secret
|
||||||
@@ -51,6 +51,7 @@ in
|
|||||||
postgresql = self.clanLib.test.containerTest ./postgresql nixosTestArgs;
|
postgresql = self.clanLib.test.containerTest ./postgresql nixosTestArgs;
|
||||||
|
|
||||||
dummy-inventory-test = import ./dummy-inventory-test nixosTestArgs;
|
dummy-inventory-test = import ./dummy-inventory-test nixosTestArgs;
|
||||||
|
dummy-inventory-test-from-flake = import ./dummy-inventory-test-from-flake nixosTestArgs;
|
||||||
data-mesher = import ./data-mesher nixosTestArgs;
|
data-mesher = import ./data-mesher nixosTestArgs;
|
||||||
}
|
}
|
||||||
// lib.optionalAttrs (pkgs.stdenv.hostPlatform.system == "aarch64-linux") {
|
// lib.optionalAttrs (pkgs.stdenv.hostPlatform.system == "aarch64-linux") {
|
||||||
|
|||||||
@@ -7,11 +7,10 @@
|
|||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
flatten
|
flatten
|
||||||
flip
|
|
||||||
mapAttrs'
|
|
||||||
mapAttrsToList
|
mapAttrsToList
|
||||||
|
mkForce
|
||||||
|
mkIf
|
||||||
mkOption
|
mkOption
|
||||||
removePrefix
|
|
||||||
types
|
types
|
||||||
unique
|
unique
|
||||||
;
|
;
|
||||||
@@ -24,9 +23,48 @@ in
|
|||||||
flake.modules.nixosVmTest.clanTest =
|
flake.modules.nixosVmTest.clanTest =
|
||||||
{ config, hostPkgs, ... }:
|
{ config, hostPkgs, ... }:
|
||||||
let
|
let
|
||||||
clanFlakeResult = config.clan;
|
|
||||||
testName = config.name;
|
testName = config.name;
|
||||||
|
|
||||||
|
clan-core = self;
|
||||||
|
|
||||||
|
inherit (lib)
|
||||||
|
filterAttrs
|
||||||
|
flip
|
||||||
|
hasPrefix
|
||||||
|
intersectAttrs
|
||||||
|
mapAttrs'
|
||||||
|
pathExists
|
||||||
|
removePrefix
|
||||||
|
throwIf
|
||||||
|
;
|
||||||
|
|
||||||
|
# only relevant if config.clan.test.fromFlake is used
|
||||||
|
importFlake =
|
||||||
|
flakeDir:
|
||||||
|
let
|
||||||
|
flakeExpr = import (flakeDir + "/flake.nix");
|
||||||
|
inputs = intersectAttrs flakeExpr.inputs clan-core.inputs;
|
||||||
|
flake = flakeExpr.outputs (
|
||||||
|
inputs
|
||||||
|
// {
|
||||||
|
self = flake // {
|
||||||
|
outPath = flakeDir;
|
||||||
|
};
|
||||||
|
clan-core = clan-core;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
in
|
||||||
|
throwIf (pathExists (
|
||||||
|
flakeDir + "/flake.lock"
|
||||||
|
)) "Test ${testName} should not have a flake.lock file" flake;
|
||||||
|
|
||||||
|
clanFlakeResult =
|
||||||
|
if config.clan.test.fromFlake != null then importFlake config.clan.test.fromFlake else config.clan;
|
||||||
|
|
||||||
|
machineModules = flip filterAttrs clanFlakeResult.nixosModules (
|
||||||
|
name: _module: hasPrefix "clan-machine-" name
|
||||||
|
);
|
||||||
|
|
||||||
update-vars-script = "${
|
update-vars-script = "${
|
||||||
self.packages.${hostPkgs.system}.generate-test-vars
|
self.packages.${hostPkgs.system}.generate-test-vars
|
||||||
}/bin/generate-test-vars";
|
}/bin/generate-test-vars";
|
||||||
@@ -48,7 +86,7 @@ in
|
|||||||
);
|
);
|
||||||
|
|
||||||
vars-check =
|
vars-check =
|
||||||
hostPkgs.runCommand "update-vars-check"
|
hostPkgs.runCommand "update-vars-check-${testName}"
|
||||||
{
|
{
|
||||||
nativeBuildInputs = generatorRuntimeInputs ++ [
|
nativeBuildInputs = generatorRuntimeInputs ++ [
|
||||||
hostPkgs.nix
|
hostPkgs.nix
|
||||||
@@ -89,6 +127,16 @@ in
|
|||||||
fi
|
fi
|
||||||
touch $out
|
touch $out
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
# the test's flake.nix with locked clan-core input
|
||||||
|
flakeForSandbox = hostPkgs.runCommand "offline-flake-for-test-${config.name}" { } ''
|
||||||
|
cp -r ${config.clan.directory} $out
|
||||||
|
chmod +w -R $out
|
||||||
|
substituteInPlace $out/flake.nix \
|
||||||
|
--replace-fail \
|
||||||
|
"https://git.clan.lol/clan/clan-core/archive/main.tar.gz" \
|
||||||
|
"${clan-core.packages.${hostPkgs.system}.clan-core-flake}"
|
||||||
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
@@ -115,6 +163,9 @@ in
|
|||||||
nixpkgs
|
nixpkgs
|
||||||
nix-darwin
|
nix-darwin
|
||||||
;
|
;
|
||||||
|
# By default clan.directory defaults to self, but we don't
|
||||||
|
# have a sensible default for self here
|
||||||
|
self = throw "set clan.directory in the test";
|
||||||
};
|
};
|
||||||
modules = [
|
modules = [
|
||||||
clanLib.buildClanModule.flakePartsModule
|
clanLib.buildClanModule.flakePartsModule
|
||||||
@@ -134,6 +185,28 @@ in
|
|||||||
type = types.bool;
|
type = types.bool;
|
||||||
description = "Whether to use containers for the test.";
|
description = "Whether to use containers for the test.";
|
||||||
};
|
};
|
||||||
|
test.fromFlake = mkOption {
|
||||||
|
default = null;
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
description = ''
|
||||||
|
path to a directory containing a `flake.nix` defining the clan
|
||||||
|
|
||||||
|
Only use this if the clan CLI needs to be used inside the test.
|
||||||
|
Otherwise, use the other clan.XXX options instead to specify the clan.
|
||||||
|
|
||||||
|
Loads the clan from a flake instead of using clan.XXX options.
|
||||||
|
This has the benefit that a real flake.nix will be available in the test.
|
||||||
|
This is useful to test CLI interactions which require a flake.nix.
|
||||||
|
|
||||||
|
Using this introduces dependencies that should otherwise be avoided.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
test.flakeForSandbox = mkOption {
|
||||||
|
default = flakeForSandbox;
|
||||||
|
type = types.path;
|
||||||
|
description = "The flake.nix to use for the test.";
|
||||||
|
readOnly = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -141,10 +214,12 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
|
clan.directory = mkIf (config.clan.test.fromFlake != null) (mkForce config.clan.test.fromFlake);
|
||||||
|
|
||||||
# Inherit all nodes from the clan
|
# Inherit all nodes from the clan
|
||||||
# i.e. nodes.jon <- clan.machines.jon
|
# i.e. nodes.jon <- clan.machines.jon
|
||||||
# clanInternals.nixosModules contains nixosModules per node
|
# clanInternals.nixosModules contains nixosModules per node
|
||||||
nodes = flip mapAttrs' clanFlakeResult.nixosModules (
|
nodes = flip mapAttrs' machineModules (
|
||||||
name: machineModule: {
|
name: machineModule: {
|
||||||
name = removePrefix "clan-machine-" name;
|
name = removePrefix "clan-machine-" name;
|
||||||
value = machineModule;
|
value = machineModule;
|
||||||
@@ -169,11 +244,6 @@ in
|
|||||||
clanLib.test.sopsModule
|
clanLib.test.sopsModule
|
||||||
];
|
];
|
||||||
|
|
||||||
# Disable documentation
|
|
||||||
# This is nice to speed up the evaluation
|
|
||||||
# And also suppresses any warnings or errors about the documentation
|
|
||||||
documentation.enable = lib.mkDefault false;
|
|
||||||
|
|
||||||
# Disable garbage collection during the test
|
# Disable garbage collection during the test
|
||||||
# https://nix.dev/manual/nix/2.28/command-ref/conf-file.html?highlight=min-free#available-settings
|
# https://nix.dev/manual/nix/2.28/command-ref/conf-file.html?highlight=min-free#available-settings
|
||||||
nix.settings.min-free = 0;
|
nix.settings.min-free = 0;
|
||||||
|
|||||||
@@ -8,4 +8,5 @@
|
|||||||
nix.registry = lib.mkForce { };
|
nix.registry = lib.mkForce { };
|
||||||
documentation.doc.enable = false;
|
documentation.doc.enable = false;
|
||||||
documentation.man.enable = false;
|
documentation.man.enable = false;
|
||||||
|
documentation.enable = lib.mkDefault false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
perSystem = {
|
perSystem = {
|
||||||
legacyPackages.setupNixInNix = ''
|
legacyPackages = {
|
||||||
|
setupNixInNix = ''
|
||||||
export HOME=$TMPDIR
|
export HOME=$TMPDIR
|
||||||
export NIX_STATE_DIR=$TMPDIR/nix
|
export NIX_STATE_DIR=$TMPDIR/nix
|
||||||
export NIX_CONF_DIR=$TMPDIR/etc
|
export NIX_CONF_DIR=$TMPDIR/etc
|
||||||
@@ -15,5 +16,22 @@
|
|||||||
nix-store --load-db --store "$CLAN_TEST_STORE" < "$closureInfo/registration"
|
nix-store --load-db --store "$CLAN_TEST_STORE" < "$closureInfo/registration"
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
setupNixInNixPython = ''
|
||||||
|
from os import environ
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
environ['HOME'] = environ['TMPDIR']
|
||||||
|
environ['NIX_STATE_DIR'] = environ['TMPDIR'] + '/nix'
|
||||||
|
environ['NIX_CONF_DIR'] = environ['TMPDIR'] + '/etc'
|
||||||
|
environ['IN_NIX_SANDBOX'] = '1'
|
||||||
|
environ['CLAN_TEST_STORE'] = environ['TMPDIR'] + '/store'
|
||||||
|
environ['LOCK_NIX'] = environ['TMPDIR'] + '/nix_lock'
|
||||||
|
Path(environ['CLAN_TEST_STORE'] + '/nix/store').mkdir(parents=True, exist_ok=True)
|
||||||
|
Path(environ['CLAN_TEST_STORE'] + '/nix/var/nix/gcroots').mkdir(parents=True, exist_ok=True)
|
||||||
|
if 'closureInfo' in environ:
|
||||||
|
subprocess.run(['cp', '--recursive', '--target', environ['CLAN_TEST_STORE'] + '/nix/store'] + environ['closureInfo'].split(), check=True)
|
||||||
|
subprocess.run(['nix-store', '--load-db', '--store', environ['CLAN_TEST_STORE']] + ['<', environ['closureInfo'] + '/registration'], shell=True, check=True)
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user