re-format with nixfmt
This commit is contained in:
@@ -14,21 +14,27 @@ let
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
flake.nixosConfigurations = { inherit (clan.nixosConfigurations) test_backup_client; };
|
flake.nixosConfigurations = {
|
||||||
|
inherit (clan.nixosConfigurations) test_backup_client;
|
||||||
|
};
|
||||||
flake.clanInternals = clan.clanInternals;
|
flake.clanInternals = clan.clanInternals;
|
||||||
flake.nixosModules = {
|
flake.nixosModules = {
|
||||||
test_backup_server = { ... }: {
|
test_backup_server =
|
||||||
imports = [
|
{ ... }:
|
||||||
self.clanModules.borgbackup
|
{
|
||||||
];
|
imports = [ self.clanModules.borgbackup ];
|
||||||
services.sshd.enable = true;
|
services.sshd.enable = true;
|
||||||
services.borgbackup.repos.testrepo = {
|
services.borgbackup.repos.testrepo = {
|
||||||
authorizedKeys = [
|
authorizedKeys = [ (builtins.readFile ../lib/ssh/pubkey) ];
|
||||||
(builtins.readFile ../lib/ssh/pubkey)
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
test_backup_client = { pkgs, lib, config, ... }:
|
test_backup_client =
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
dependencies = [
|
dependencies = [
|
||||||
self
|
self
|
||||||
@@ -38,14 +44,10 @@ in
|
|||||||
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
|
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [ self.clanModules.borgbackup ];
|
||||||
self.clanModules.borgbackup
|
|
||||||
];
|
|
||||||
networking.hostName = "client";
|
networking.hostName = "client";
|
||||||
services.sshd.enable = true;
|
services.sshd.enable = true;
|
||||||
users.users.root.openssh.authorizedKeys.keyFiles = [
|
users.users.root.openssh.authorizedKeys.keyFiles = [ ../lib/ssh/pubkey ];
|
||||||
../lib/ssh/pubkey
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.tmpfiles.settings."vmsecrets" = {
|
systemd.tmpfiles.settings."vmsecrets" = {
|
||||||
"/etc/secrets/borgbackup.ssh" = {
|
"/etc/secrets/borgbackup.ssh" = {
|
||||||
@@ -78,11 +80,11 @@ in
|
|||||||
clan.borgbackup.destinations.test_backup_server.repo = "borg@server:.";
|
clan.borgbackup.destinations.test_backup_server.repo = "borg@server:.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
perSystem = { nodes, pkgs, ... }: {
|
perSystem =
|
||||||
checks = pkgs.lib.mkIf (pkgs.stdenv.isLinux) {
|
{ nodes, pkgs, ... }:
|
||||||
test-backups =
|
|
||||||
(import ../lib/test-base.nix)
|
|
||||||
{
|
{
|
||||||
|
checks = pkgs.lib.mkIf (pkgs.stdenv.isLinux) {
|
||||||
|
test-backups = (import ../lib/test-base.nix) {
|
||||||
name = "test-backups";
|
name = "test-backups";
|
||||||
nodes.server = {
|
nodes.server = {
|
||||||
imports = [
|
imports = [
|
||||||
@@ -135,8 +137,7 @@ in
|
|||||||
client.succeed(f"clan --debug --flake ${../..} backups restore test_backup_client borgbackup {backup_id}")
|
client.succeed(f"clan --debug --flake ${../..} backups restore test_backup_client borgbackup {backup_id}")
|
||||||
assert(client.succeed("cat /var/test-backups/somefile").strip() == "testing")
|
assert(client.succeed("cat /var/test-backups/somefile").strip() == "testing")
|
||||||
'';
|
'';
|
||||||
}
|
} { inherit pkgs self; };
|
||||||
{ inherit pkgs self; };
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
(import ../lib/test-base.nix) ({ ... }: {
|
(import ../lib/test-base.nix) (
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
name = "borgbackup";
|
name = "borgbackup";
|
||||||
|
|
||||||
nodes.machine = { self, pkgs, ... }: {
|
nodes.machine =
|
||||||
|
{ self, pkgs, ... }:
|
||||||
|
{
|
||||||
imports = [
|
imports = [
|
||||||
self.clanModules.borgbackup
|
self.clanModules.borgbackup
|
||||||
self.nixosModules.clanCore
|
self.nixosModules.clanCore
|
||||||
{
|
{
|
||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
services.borgbackup.repos.testrepo = {
|
services.borgbackup.repos.testrepo = {
|
||||||
authorizedKeys = [
|
authorizedKeys = [ (builtins.readFile ../lib/ssh/pubkey) ];
|
||||||
(builtins.readFile ../lib/ssh/pubkey)
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@@ -45,4 +47,5 @@
|
|||||||
machine.systemctl("start --wait borgbackup-job-test.service")
|
machine.systemctl("start --wait borgbackup-job-test.service")
|
||||||
assert "machine-test" in machine.succeed("BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes /run/current-system/sw/bin/borg-job-test list")
|
assert "machine-test" in machine.succeed("BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK=yes /run/current-system/sw/bin/borg-job-test list")
|
||||||
'';
|
'';
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
(import ../lib/container-test.nix) ({ ... }: {
|
(import ../lib/container-test.nix) (
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
name = "secrets";
|
name = "secrets";
|
||||||
|
|
||||||
nodes.machine = { ... }: {
|
nodes.machine =
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
networking.hostName = "machine";
|
networking.hostName = "machine";
|
||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
services.openssh.startWhenNeeded = false;
|
services.openssh.startWhenNeeded = false;
|
||||||
@@ -11,4 +15,5 @@
|
|||||||
machine.succeed("systemctl status sshd")
|
machine.succeed("systemctl status sshd")
|
||||||
machine.wait_for_unit("sshd")
|
machine.wait_for_unit("sshd")
|
||||||
'';
|
'';
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
(import ../lib/container-test.nix) ({ pkgs, ... }: {
|
(import ../lib/container-test.nix) (
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
name = "secrets";
|
name = "secrets";
|
||||||
|
|
||||||
nodes.machine = { self, ... }: {
|
nodes.machine =
|
||||||
|
{ self, ... }:
|
||||||
|
{
|
||||||
imports = [
|
imports = [
|
||||||
self.clanModules.deltachat
|
self.clanModules.deltachat
|
||||||
self.nixosModules.clanCore
|
self.nixosModules.clanCore
|
||||||
@@ -21,4 +25,5 @@
|
|||||||
# smtp
|
# smtp
|
||||||
machine.succeed("${pkgs.netcat}/bin/nc -z -v ::1 25")
|
machine.succeed("${pkgs.netcat}/bin/nc -z -v ::1 25")
|
||||||
'';
|
'';
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
{ self, ... }: {
|
{ self, ... }:
|
||||||
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./impure/flake-module.nix
|
./impure/flake-module.nix
|
||||||
./backups/flake-module.nix
|
./backups/flake-module.nix
|
||||||
./installation/flake-module.nix
|
./installation/flake-module.nix
|
||||||
./flash/flake-module.nix
|
./flash/flake-module.nix
|
||||||
];
|
];
|
||||||
perSystem = { pkgs, lib, self', ... }: {
|
perSystem =
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
self',
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
checks =
|
checks =
|
||||||
let
|
let
|
||||||
nixosTestArgs = {
|
nixosTestArgs = {
|
||||||
@@ -24,14 +32,17 @@
|
|||||||
syncthing = import ./syncthing nixosTestArgs;
|
syncthing = import ./syncthing nixosTestArgs;
|
||||||
wayland-proxy-virtwl = import ./wayland-proxy-virtwl nixosTestArgs;
|
wayland-proxy-virtwl = import ./wayland-proxy-virtwl nixosTestArgs;
|
||||||
};
|
};
|
||||||
schemaTests = pkgs.callPackages ./schemas.nix {
|
schemaTests = pkgs.callPackages ./schemas.nix { inherit self; };
|
||||||
inherit self;
|
|
||||||
};
|
|
||||||
|
|
||||||
flakeOutputs = lib.mapAttrs' (name: config: lib.nameValuePair "nixos-${name}" config.config.system.build.toplevel) self.nixosConfigurations
|
flakeOutputs =
|
||||||
|
lib.mapAttrs' (
|
||||||
|
name: config: lib.nameValuePair "nixos-${name}" config.config.system.build.toplevel
|
||||||
|
) self.nixosConfigurations
|
||||||
// lib.mapAttrs' (n: lib.nameValuePair "package-${n}") self'.packages
|
// lib.mapAttrs' (n: lib.nameValuePair "package-${n}") self'.packages
|
||||||
// lib.mapAttrs' (n: lib.nameValuePair "devShell-${n}") self'.devShells
|
// lib.mapAttrs' (n: lib.nameValuePair "devShell-${n}") self'.devShells
|
||||||
// lib.mapAttrs' (name: config: lib.nameValuePair "home-manager-${name}" config.activation-script) (self'.legacyPackages.homeConfigurations or { });
|
// lib.mapAttrs' (name: config: lib.nameValuePair "home-manager-${name}" config.activation-script) (
|
||||||
|
self'.legacyPackages.homeConfigurations or { }
|
||||||
|
);
|
||||||
in
|
in
|
||||||
nixosTests // schemaTests // flakeOutputs;
|
nixosTests // schemaTests // flakeOutputs;
|
||||||
legacyPackages = {
|
legacyPackages = {
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
{ self, ... }:
|
{ self, ... }:
|
||||||
{
|
{
|
||||||
perSystem = { nodes, pkgs, lib, ... }:
|
perSystem =
|
||||||
|
{
|
||||||
|
nodes,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
dependencies = [
|
dependencies = [
|
||||||
self
|
self
|
||||||
@@ -14,9 +20,7 @@
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
checks = pkgs.lib.mkIf (pkgs.stdenv.isLinux) {
|
checks = pkgs.lib.mkIf (pkgs.stdenv.isLinux) {
|
||||||
flash =
|
flash = (import ../lib/test-base.nix) {
|
||||||
(import ../lib/test-base.nix)
|
|
||||||
{
|
|
||||||
name = "flash";
|
name = "flash";
|
||||||
nodes.target = {
|
nodes.target = {
|
||||||
virtualisation.emptyDiskImages = [ 4096 ];
|
virtualisation.emptyDiskImages = [ 4096 ];
|
||||||
@@ -39,8 +43,7 @@
|
|||||||
start_all()
|
start_all()
|
||||||
machine.succeed("clan --flake ${../..} flash --debug --yes --disk main /dev/vdb test_install_machine")
|
machine.succeed("clan --flake ${../..} flash --debug --yes --disk main /dev/vdb test_install_machine")
|
||||||
'';
|
'';
|
||||||
}
|
} { inherit pkgs self; };
|
||||||
{ inherit pkgs self; };
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
{
|
{
|
||||||
perSystem = { pkgs, lib, ... }: {
|
perSystem =
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
{
|
||||||
# a script that executes all other checks
|
# a script that executes all other checks
|
||||||
packages.impure-checks = pkgs.writeShellScriptBin "impure-checks" ''
|
packages.impure-checks = pkgs.writeShellScriptBin "impure-checks" ''
|
||||||
#!${pkgs.bash}/bin/bash
|
#!${pkgs.bash}/bin/bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
export PATH="${lib.makeBinPath [
|
export PATH="${
|
||||||
|
lib.makeBinPath [
|
||||||
pkgs.gitMinimal
|
pkgs.gitMinimal
|
||||||
pkgs.nix
|
pkgs.nix
|
||||||
pkgs.rsync # needed to have rsync installed on the dummy ssh server
|
pkgs.rsync # needed to have rsync installed on the dummy ssh server
|
||||||
]}"
|
]
|
||||||
|
}"
|
||||||
ROOT=$(git rev-parse --show-toplevel)
|
ROOT=$(git rev-parse --show-toplevel)
|
||||||
cd "$ROOT/pkgs/clan-cli"
|
cd "$ROOT/pkgs/clan-cli"
|
||||||
nix develop "$ROOT#clan-cli" -c bash -c "TMPDIR=/tmp python -m pytest -s -m impure ./tests $@"
|
nix develop "$ROOT#clan-cli" -c bash -c "TMPDIR=/tmp python -m pytest -s -m impure ./tests $@"
|
||||||
|
|||||||
@@ -12,10 +12,14 @@ let
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
flake.nixosConfigurations = { inherit (clan.nixosConfigurations) test_install_machine; };
|
flake.nixosConfigurations = {
|
||||||
|
inherit (clan.nixosConfigurations) test_install_machine;
|
||||||
|
};
|
||||||
flake.clanInternals = clan.clanInternals;
|
flake.clanInternals = clan.clanInternals;
|
||||||
flake.nixosModules = {
|
flake.nixosModules = {
|
||||||
test_install_machine = { lib, modulesPath, ... }: {
|
test_install_machine =
|
||||||
|
{ lib, modulesPath, ... }:
|
||||||
|
{
|
||||||
imports = [
|
imports = [
|
||||||
self.clanModules.diskLayouts
|
self.clanModules.diskLayouts
|
||||||
(modulesPath + "/testing/test-instrumentation.nix") # we need these 2 modules always to be able to run the tests
|
(modulesPath + "/testing/test-instrumentation.nix") # we need these 2 modules always to be able to run the tests
|
||||||
@@ -26,12 +30,16 @@ in
|
|||||||
environment.etc."install-successful".text = "ok";
|
environment.etc."install-successful".text = "ok";
|
||||||
|
|
||||||
boot.consoleLogLevel = lib.mkForce 100;
|
boot.consoleLogLevel = lib.mkForce 100;
|
||||||
boot.kernelParams = [
|
boot.kernelParams = [ "boot.shell_on_fail" ];
|
||||||
"boot.shell_on_fail"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
perSystem = { nodes, pkgs, lib, ... }:
|
perSystem =
|
||||||
|
{
|
||||||
|
nodes,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
dependencies = [
|
dependencies = [
|
||||||
self
|
self
|
||||||
@@ -45,15 +53,11 @@ in
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
checks = pkgs.lib.mkIf (pkgs.stdenv.isLinux) {
|
checks = pkgs.lib.mkIf (pkgs.stdenv.isLinux) {
|
||||||
test-installation =
|
test-installation = (import ../lib/test-base.nix) {
|
||||||
(import ../lib/test-base.nix)
|
|
||||||
{
|
|
||||||
name = "test-installation";
|
name = "test-installation";
|
||||||
nodes.target = {
|
nodes.target = {
|
||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
users.users.root.openssh.authorizedKeys.keyFiles = [
|
users.users.root.openssh.authorizedKeys.keyFiles = [ ../lib/ssh/pubkey ];
|
||||||
../lib/ssh/pubkey
|
|
||||||
];
|
|
||||||
system.nixos.variant_id = "installer";
|
system.nixos.variant_id = "installer";
|
||||||
virtualisation.emptyDiskImages = [ 4096 ];
|
virtualisation.emptyDiskImages = [ 4096 ];
|
||||||
nix.settings = {
|
nix.settings = {
|
||||||
@@ -111,8 +115,7 @@ in
|
|||||||
new_machine = create_test_machine(oldmachine=target, args={ "name": "new_machine" })
|
new_machine = create_test_machine(oldmachine=target, args={ "name": "new_machine" })
|
||||||
assert(new_machine.succeed("cat /etc/install-successful").strip() == "ok")
|
assert(new_machine.succeed("cat /etc/install-successful").strip() == "ok")
|
||||||
'';
|
'';
|
||||||
}
|
} { inherit pkgs self; };
|
||||||
{ inherit pkgs self; };
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
{ hostPkgs, lib, config, ... }:
|
{
|
||||||
|
hostPkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
testDriver = hostPkgs.python3.pkgs.callPackage ./package.nix {
|
testDriver = hostPkgs.python3.pkgs.callPackage ./package.nix {
|
||||||
inherit (config) extraPythonPackages;
|
inherit (config) extraPythonPackages;
|
||||||
inherit (hostPkgs.pkgs) util-linux systemd;
|
inherit (hostPkgs.pkgs) util-linux systemd;
|
||||||
};
|
};
|
||||||
containers = map (m: m.system.build.toplevel) (lib.attrValues config.nodes);
|
containers = map (m: m.system.build.toplevel) (lib.attrValues config.nodes);
|
||||||
pythonizeName = name:
|
pythonizeName =
|
||||||
|
name:
|
||||||
let
|
let
|
||||||
head = lib.substring 0 1 name;
|
head = lib.substring 0 1 name;
|
||||||
tail = lib.substring 1 (-1) name;
|
tail = lib.substring 1 (-1) name;
|
||||||
in
|
in
|
||||||
(if builtins.match "[A-z_]" head == null then "_" else head) +
|
(if builtins.match "[A-z_]" head == null then "_" else head)
|
||||||
lib.stringAsChars (c: if builtins.match "[A-z0-9_]" c == null then "_" else c) tail;
|
+ lib.stringAsChars (c: if builtins.match "[A-z0-9_]" c == null then "_" else c) tail;
|
||||||
nodeHostNames =
|
nodeHostNames =
|
||||||
let
|
let
|
||||||
nodesList = map (c: c.system.name) (lib.attrValues config.nodes);
|
nodesList = map (c: c.system.name) (lib.attrValues config.nodes);
|
||||||
@@ -21,7 +27,8 @@ let
|
|||||||
pythonizedNames = map pythonizeName nodeHostNames;
|
pythonizedNames = map pythonizeName nodeHostNames;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
driver = lib.mkForce (hostPkgs.runCommand "nixos-test-driver-${config.name}"
|
driver = lib.mkForce (
|
||||||
|
hostPkgs.runCommand "nixos-test-driver-${config.name}"
|
||||||
{
|
{
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
hostPkgs.makeWrapper
|
hostPkgs.makeWrapper
|
||||||
@@ -61,9 +68,11 @@ in
|
|||||||
wrapProgram $out/bin/nixos-test-driver \
|
wrapProgram $out/bin/nixos-test-driver \
|
||||||
${lib.concatStringsSep " " (map (name: "--add-flags '--container ${name}'") containers)} \
|
${lib.concatStringsSep " " (map (name: "--add-flags '--container ${name}'") containers)} \
|
||||||
--add-flags "--test-script '$out/test-script'"
|
--add-flags "--test-script '$out/test-script'"
|
||||||
'');
|
''
|
||||||
|
);
|
||||||
|
|
||||||
test = lib.mkForce (lib.lazyDerivation {
|
test = lib.mkForce (
|
||||||
|
lib.lazyDerivation {
|
||||||
# lazyDerivation improves performance when only passthru items and/or meta are used.
|
# lazyDerivation improves performance when only passthru items and/or meta are used.
|
||||||
derivation = hostPkgs.stdenv.mkDerivation {
|
derivation = hostPkgs.stdenv.mkDerivation {
|
||||||
name = "vm-test-run-${config.name}";
|
name = "vm-test-run-${config.name}";
|
||||||
@@ -84,5 +93,6 @@ in
|
|||||||
meta = config.meta;
|
meta = config.meta;
|
||||||
};
|
};
|
||||||
inherit (config) passthru meta;
|
inherit (config) passthru meta;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,18 @@
|
|||||||
{ extraPythonPackages, python3Packages, buildPythonApplication, setuptools, util-linux, systemd }:
|
{
|
||||||
|
extraPythonPackages,
|
||||||
|
python3Packages,
|
||||||
|
buildPythonApplication,
|
||||||
|
setuptools,
|
||||||
|
util-linux,
|
||||||
|
systemd,
|
||||||
|
}:
|
||||||
buildPythonApplication {
|
buildPythonApplication {
|
||||||
pname = "test-driver";
|
pname = "test-driver";
|
||||||
version = "0.0.1";
|
version = "0.0.1";
|
||||||
propagatedBuildInputs = [ util-linux systemd ] ++ extraPythonPackages python3Packages;
|
propagatedBuildInputs = [
|
||||||
|
util-linux
|
||||||
|
systemd
|
||||||
|
] ++ extraPythonPackages python3Packages;
|
||||||
nativeBuildInputs = [ setuptools ];
|
nativeBuildInputs = [ setuptools ];
|
||||||
format = "pyproject";
|
format = "pyproject";
|
||||||
src = ./.;
|
src = ./.;
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
test:
|
test:
|
||||||
{ pkgs
|
{ pkgs, self, ... }:
|
||||||
, self
|
|
||||||
, ...
|
|
||||||
}:
|
|
||||||
let
|
let
|
||||||
inherit (pkgs) lib;
|
inherit (pkgs) lib;
|
||||||
nixos-lib = import (pkgs.path + "/nixos/lib") { };
|
nixos-lib = import (pkgs.path + "/nixos/lib") { };
|
||||||
in
|
in
|
||||||
(nixos-lib.runTest ({ hostPkgs, ... }: {
|
(nixos-lib.runTest (
|
||||||
|
{ hostPkgs, ... }:
|
||||||
|
{
|
||||||
hostPkgs = pkgs;
|
hostPkgs = pkgs;
|
||||||
# speed-up evaluation
|
# speed-up evaluation
|
||||||
defaults = {
|
defaults = {
|
||||||
@@ -30,4 +29,5 @@ in
|
|||||||
test
|
test
|
||||||
./container-driver/module.nix
|
./container-driver/module.nix
|
||||||
];
|
];
|
||||||
})).config.result
|
}
|
||||||
|
)).config.result
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
test:
|
test:
|
||||||
{ pkgs
|
{ pkgs, self, ... }:
|
||||||
, self
|
|
||||||
, ...
|
|
||||||
}:
|
|
||||||
let
|
let
|
||||||
inherit (pkgs) lib;
|
inherit (pkgs) lib;
|
||||||
nixos-lib = import (pkgs.path + "/nixos/lib") { };
|
nixos-lib = import (pkgs.path + "/nixos/lib") { };
|
||||||
|
|||||||
@@ -1,35 +1,48 @@
|
|||||||
{ self, runCommand, check-jsonschema, pkgs, lib, ... }:
|
{
|
||||||
|
self,
|
||||||
|
runCommand,
|
||||||
|
check-jsonschema,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
clanModules.clanCore = self.nixosModules.clanCore;
|
clanModules.clanCore = self.nixosModules.clanCore;
|
||||||
|
|
||||||
baseModule = {
|
baseModule = {
|
||||||
imports =
|
imports = (import (pkgs.path + "/nixos/modules/module-list.nix")) ++ [
|
||||||
(import (pkgs.path + "/nixos/modules/module-list.nix"))
|
{
|
||||||
++ [{
|
|
||||||
nixpkgs.hostPlatform = "x86_64-linux";
|
nixpkgs.hostPlatform = "x86_64-linux";
|
||||||
clanCore.clanName = "dummy";
|
clanCore.clanName = "dummy";
|
||||||
}];
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
optionsFromModule = module:
|
optionsFromModule =
|
||||||
|
module:
|
||||||
let
|
let
|
||||||
evaled = lib.evalModules {
|
evaled = lib.evalModules {
|
||||||
modules = [ module baseModule ];
|
modules = [
|
||||||
|
module
|
||||||
|
baseModule
|
||||||
|
];
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
evaled.options.clan;
|
evaled.options.clan;
|
||||||
|
|
||||||
clanModuleSchemas = lib.mapAttrs (_: module: self.lib.jsonschema.parseOptions (optionsFromModule module)) clanModules;
|
clanModuleSchemas = lib.mapAttrs (
|
||||||
|
_: module: self.lib.jsonschema.parseOptions (optionsFromModule module)
|
||||||
|
) clanModules;
|
||||||
|
|
||||||
mkTest = name: schema: runCommand "schema-${name}" { } ''
|
mkTest =
|
||||||
|
name: schema:
|
||||||
|
runCommand "schema-${name}" { } ''
|
||||||
${check-jsonschema}/bin/check-jsonschema \
|
${check-jsonschema}/bin/check-jsonschema \
|
||||||
--check-metaschema ${builtins.toFile "schema-${name}" (builtins.toJSON schema)}
|
--check-metaschema ${builtins.toFile "schema-${name}" (builtins.toJSON schema)}
|
||||||
touch $out
|
touch $out
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
lib.mapAttrs'
|
lib.mapAttrs' (name: schema: {
|
||||||
(name: schema: {
|
|
||||||
name = "schema-${name}";
|
name = "schema-${name}";
|
||||||
value = mkTest name schema;
|
value = mkTest name schema;
|
||||||
})
|
}) clanModuleSchemas
|
||||||
clanModuleSchemas
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
(import ../lib/test-base.nix) {
|
(import ../lib/test-base.nix) {
|
||||||
name = "secrets";
|
name = "secrets";
|
||||||
|
|
||||||
nodes.machine = { self, config, ... }: {
|
nodes.machine =
|
||||||
imports = [
|
{ self, config, ... }:
|
||||||
(self.nixosModules.clanCore)
|
{
|
||||||
];
|
imports = [ (self.nixosModules.clanCore) ];
|
||||||
environment.etc."secret".source = config.sops.secrets.secret.path;
|
environment.etc."secret".source = config.sops.secrets.secret.path;
|
||||||
environment.etc."group-secret".source = config.sops.secrets.group-secret.path;
|
environment.etc."group-secret".source = config.sops.secrets.group-secret.path;
|
||||||
sops.age.keyFile = ./key.age;
|
sops.age.keyFile = ./key.age;
|
||||||
|
|||||||
@@ -1,7 +1,16 @@
|
|||||||
import ../lib/test-base.nix ({ config, pkgs, lib, ... }: {
|
import ../lib/test-base.nix (
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
name = "wayland-proxy-virtwl";
|
name = "wayland-proxy-virtwl";
|
||||||
|
|
||||||
nodes.machine = { self, ... }: {
|
nodes.machine =
|
||||||
|
{ self, ... }:
|
||||||
|
{
|
||||||
imports = [
|
imports = [
|
||||||
self.nixosModules.clanCore
|
self.nixosModules.clanCore
|
||||||
{
|
{
|
||||||
@@ -22,4 +31,5 @@ import ../lib/test-base.nix ({ config, pkgs, lib, ... }: {
|
|||||||
# use machinectl
|
# use machinectl
|
||||||
machine.succeed("machinectl shell .host ${config.nodes.machine.systemd.package}/bin/systemctl --user start wayland-proxy-virtwl >&2")
|
machine.succeed("machinectl shell .host ${config.nodes.machine.systemd.package}/bin/systemctl --user start wayland-proxy-virtwl >&2")
|
||||||
'';
|
'';
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
(import ../lib/container-test.nix) ({ pkgs, ... }: {
|
(import ../lib/container-test.nix) (
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
name = "zt-tcp-relay";
|
name = "zt-tcp-relay";
|
||||||
|
|
||||||
nodes.machine = { self, ... }: {
|
nodes.machine =
|
||||||
|
{ self, ... }:
|
||||||
|
{
|
||||||
imports = [
|
imports = [
|
||||||
self.nixosModules.clanCore
|
self.nixosModules.clanCore
|
||||||
self.clanModules.zt-tcp-relay
|
self.clanModules.zt-tcp-relay
|
||||||
@@ -17,4 +21,5 @@
|
|||||||
out = machine.succeed("${pkgs.netcat}/bin/nc -z -v localhost 4443")
|
out = machine.succeed("${pkgs.netcat}/bin/nc -z -v localhost 4443")
|
||||||
print(out)
|
print(out)
|
||||||
'';
|
'';
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
cfg = config.clan.borgbackup;
|
cfg = config.clan.borgbackup;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.clan.borgbackup.destinations = lib.mkOption {
|
options.clan.borgbackup.destinations = lib.mkOption {
|
||||||
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: {
|
type = lib.types.attrsOf (
|
||||||
|
lib.types.submodule (
|
||||||
|
{ name, ... }:
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
name = lib.mkOption {
|
name = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -17,23 +25,31 @@ in
|
|||||||
};
|
};
|
||||||
rsh = lib.mkOption {
|
rsh = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "ssh -i ${config.clanCore.secrets.borgbackup.secrets."borgbackup.ssh".path} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null";
|
default = "ssh -i ${
|
||||||
|
config.clanCore.secrets.borgbackup.secrets."borgbackup.ssh".path
|
||||||
|
} -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null";
|
||||||
description = "the rsh to use for the backup";
|
description = "the rsh to use for the backup";
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}));
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
default = { };
|
default = { };
|
||||||
description = ''
|
description = ''
|
||||||
destinations where the machine should be backuped to
|
destinations where the machine should be backuped to
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
imports = [ (lib.mkRemovedOptionModule [ "clan" "borgbackup" "enable" ] "Just define clan.borgbackup.destinations to enable it") ];
|
imports = [
|
||||||
|
(lib.mkRemovedOptionModule [
|
||||||
|
"clan"
|
||||||
|
"borgbackup"
|
||||||
|
"enable"
|
||||||
|
] "Just define clan.borgbackup.destinations to enable it")
|
||||||
|
];
|
||||||
|
|
||||||
config = lib.mkIf (cfg.destinations != { }) {
|
config = lib.mkIf (cfg.destinations != { }) {
|
||||||
services.borgbackup.jobs = lib.mapAttrs
|
services.borgbackup.jobs = lib.mapAttrs (_: dest: {
|
||||||
(_: dest: {
|
|
||||||
paths = lib.flatten (map (state: state.folders) (lib.attrValues config.clanCore.state));
|
paths = lib.flatten (map (state: state.folders) (lib.attrValues config.clanCore.state));
|
||||||
exclude = [ "*.pyc" ];
|
exclude = [ "*.pyc" ];
|
||||||
repo = dest.repo;
|
repo = dest.repo;
|
||||||
@@ -56,14 +72,17 @@ in
|
|||||||
weekly = 4;
|
weekly = 4;
|
||||||
monthly = 0;
|
monthly = 0;
|
||||||
};
|
};
|
||||||
})
|
}) cfg.destinations;
|
||||||
cfg.destinations;
|
|
||||||
|
|
||||||
clanCore.secrets.borgbackup = {
|
clanCore.secrets.borgbackup = {
|
||||||
facts."borgbackup.ssh.pub" = { };
|
facts."borgbackup.ssh.pub" = { };
|
||||||
secrets."borgbackup.ssh" = { };
|
secrets."borgbackup.ssh" = { };
|
||||||
secrets."borgbackup.repokey" = { };
|
secrets."borgbackup.repokey" = { };
|
||||||
generator.path = [ pkgs.openssh pkgs.coreutils pkgs.xkcdpass ];
|
generator.path = [
|
||||||
|
pkgs.openssh
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.xkcdpass
|
||||||
|
];
|
||||||
generator.script = ''
|
generator.script = ''
|
||||||
ssh-keygen -t ed25519 -N "" -f "$secrets"/borgbackup.ssh
|
ssh-keygen -t ed25519 -N "" -f "$secrets"/borgbackup.ssh
|
||||||
mv "$secrets"/borgbackup.ssh.pub "$facts"/borgbackup.ssh.pub
|
mv "$secrets"/borgbackup.ssh.pub "$facts"/borgbackup.ssh.pub
|
||||||
@@ -75,8 +94,9 @@ in
|
|||||||
# TODO list needs to run locally or on the remote machine
|
# TODO list needs to run locally or on the remote machine
|
||||||
list = ''
|
list = ''
|
||||||
# we need yes here to skip the changed url verification
|
# we need yes here to skip the changed url verification
|
||||||
${lib.concatMapStringsSep "\n" (dest: ''yes y | borg-job-${dest.name} list --json | jq -r '. + {"job-name": "${dest.name}"}' '')
|
${lib.concatMapStringsSep "\n" (
|
||||||
(lib.attrValues cfg.destinations)}
|
dest: ''yes y | borg-job-${dest.name} list --json | jq -r '. + {"job-name": "${dest.name}"}' ''
|
||||||
|
) (lib.attrValues cfg.destinations)}
|
||||||
'';
|
'';
|
||||||
create = ''
|
create = ''
|
||||||
${lib.concatMapStringsSep "\n" (dest: ''
|
${lib.concatMapStringsSep "\n" (dest: ''
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{ config, pkgs, ... }: {
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
networking.firewall.interfaces."zt+".allowedTCPPorts = [ 25 ]; # smtp with other hosts
|
networking.firewall.interfaces."zt+".allowedTCPPorts = [ 25 ]; # smtp with other hosts
|
||||||
environment.systemPackages = [ pkgs.deltachat-desktop ];
|
environment.systemPackages = [ pkgs.deltachat-desktop ];
|
||||||
|
|
||||||
@@ -134,9 +135,7 @@
|
|||||||
storage &local_mailboxes
|
storage &local_mailboxes
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
ensureAccounts = [
|
ensureAccounts = [ "user@${domain}" ];
|
||||||
"user@${domain}"
|
|
||||||
];
|
|
||||||
ensureCredentials = {
|
ensureCredentials = {
|
||||||
"user@${domain}".passwordFile = pkgs.writeText "dummy" "foobar";
|
"user@${domain}".passwordFile = pkgs.writeText "dummy" "foobar";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,4 +41,3 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{ inputs, ... }: {
|
{ inputs, ... }:
|
||||||
|
{
|
||||||
flake.clanModules = {
|
flake.clanModules = {
|
||||||
diskLayouts = {
|
diskLayouts = {
|
||||||
imports = [
|
imports = [
|
||||||
|
|||||||
@@ -1,4 +1 @@
|
|||||||
_:
|
_: { fonts.enableDefaultPackages = true; }
|
||||||
{
|
|
||||||
fonts.enableDefaultPackages = true;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
{ config
|
{
|
||||||
, pkgs
|
config,
|
||||||
, lib
|
pkgs,
|
||||||
, ...
|
lib,
|
||||||
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
# Integration can be improved, if the following issues get implemented:
|
# Integration can be improved, if the following issues get implemented:
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{ pkgs, ... }: {
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
hardware.opengl.enable = true;
|
hardware.opengl.enable = true;
|
||||||
environment.systemPackages = [ pkgs.moonlight-qt ];
|
environment.systemPackages = [ pkgs.moonlight-qt ];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
{ config, pkgs, ... }: {
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
services.openssh.enable = true;
|
services.openssh.enable = true;
|
||||||
|
|
||||||
services.openssh.hostKeys = [{
|
services.openssh.hostKeys = [
|
||||||
|
{
|
||||||
path = config.clanCore.secrets.openssh.secrets."ssh.id_ed25519".path;
|
path = config.clanCore.secrets.openssh.secrets."ssh.id_ed25519".path;
|
||||||
type = "ed25519";
|
type = "ed25519";
|
||||||
}];
|
}
|
||||||
|
];
|
||||||
|
|
||||||
clanCore.secrets.openssh = {
|
clanCore.secrets.openssh = {
|
||||||
secrets."ssh.id_ed25519" = { };
|
secrets."ssh.id_ed25519" = { };
|
||||||
facts."ssh.id_ed25519.pub" = { };
|
facts."ssh.id_ed25519.pub" = { };
|
||||||
generator.path = [ pkgs.coreutils pkgs.openssh ];
|
generator.path = [
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.openssh
|
||||||
|
];
|
||||||
generator.script = ''
|
generator.script = ''
|
||||||
ssh-keygen -t ed25519 -N "" -f $secrets/ssh.id_ed25519
|
ssh-keygen -t ed25519 -N "" -f $secrets/ssh.id_ed25519
|
||||||
mv $secrets/ssh.id_ed25519.pub $facts/ssh.id_ed25519.pub
|
mv $secrets/ssh.id_ed25519.pub $facts/ssh.id_ed25519.pub
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{ pkgs, options, ... }:
|
{ pkgs, options, ... }:
|
||||||
let
|
let
|
||||||
apps = pkgs.writeText "apps.json" (builtins.toJSON
|
apps = pkgs.writeText "apps.json" (
|
||||||
{
|
builtins.toJSON {
|
||||||
env = {
|
env = {
|
||||||
PATH = "$(PATH):$(HOME)/.local/bin:/run/current-system/sw/bin";
|
PATH = "$(PATH):$(HOME)/.local/bin:/run/current-system/sw/bin";
|
||||||
};
|
};
|
||||||
@@ -22,13 +22,12 @@ let
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "Steam Big Picture";
|
name = "Steam Big Picture";
|
||||||
detached = [
|
detached = [ "setsid steam steam://open/bigpicture" ];
|
||||||
"setsid steam steam://open/bigpicture"
|
|
||||||
];
|
|
||||||
image-path = "steam.png";
|
image-path = "steam.png";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
});
|
}
|
||||||
|
);
|
||||||
sunshineConfiguration = pkgs.writeText "sunshine.conf" ''
|
sunshineConfiguration = pkgs.writeText "sunshine.conf" ''
|
||||||
address_family = both
|
address_family = both
|
||||||
channels = 5
|
channels = 5
|
||||||
@@ -78,11 +77,9 @@ in
|
|||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
pkgs.sunshine
|
pkgs.sunshine
|
||||||
(pkgs.writers.writeDashBin "sun" ''
|
(pkgs.writers.writeDashBin "sun" ''
|
||||||
${pkgs.sunshine}/bin/sunshine -1 ${
|
${pkgs.sunshine}/bin/sunshine -1 ${pkgs.writeText "sunshine.conf" ''
|
||||||
pkgs.writeText "sunshine.conf" ''
|
|
||||||
address_family = both
|
address_family = both
|
||||||
''
|
''} "$@"
|
||||||
} "$@"
|
|
||||||
'')
|
'')
|
||||||
# Create a dummy account, for easier setup,
|
# Create a dummy account, for easier setup,
|
||||||
# don't use this account in actual production yet.
|
# don't use this account in actual production yet.
|
||||||
@@ -113,11 +110,7 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [ "d '/var/lib/sunshine' 0770 'user' 'users' - -" ];
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"d '/var/lib/sunshine' 0770 'user' 'users' - -"
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
systemd.user.services.sunshine = {
|
systemd.user.services.sunshine = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -128,9 +121,7 @@ in
|
|||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
RestartSec = "5s";
|
RestartSec = "5s";
|
||||||
ReadWritePaths = [
|
ReadWritePaths = [ "/var/lib/sunshine" ];
|
||||||
"/var/lib/sunshine"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
wantedBy = [ "graphical-session.target" ];
|
wantedBy = [ "graphical-session.target" ];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
{ config
|
{
|
||||||
, pkgs
|
config,
|
||||||
, lib
|
pkgs,
|
||||||
, ...
|
lib,
|
||||||
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
options.clan.syncthing = {
|
options.clan.syncthing = {
|
||||||
@@ -53,9 +54,9 @@
|
|||||||
|
|
||||||
assertions = [
|
assertions = [
|
||||||
{
|
{
|
||||||
assertion =
|
assertion = lib.all (
|
||||||
lib.all (attr: builtins.hasAttr attr config.services.syncthing.settings.folders)
|
attr: builtins.hasAttr attr config.services.syncthing.settings.folders
|
||||||
config.clan.syncthing.autoShares;
|
) config.clan.syncthing.autoShares;
|
||||||
message = ''
|
message = ''
|
||||||
Syncthing: If you want to AutoShare a folder, you need to have it configured on the sharing device.
|
Syncthing: If you want to AutoShare a folder, you need to have it configured on the sharing device.
|
||||||
'';
|
'';
|
||||||
@@ -80,12 +81,8 @@
|
|||||||
|
|
||||||
group = "syncthing";
|
group = "syncthing";
|
||||||
|
|
||||||
key =
|
key = lib.mkDefault config.clan.secrets.syncthing.secrets."syncthing.key".path or null;
|
||||||
lib.mkDefault
|
cert = lib.mkDefault config.clan.secrets.syncthing.secrets."syncthing.cert".path or null;
|
||||||
config.clan.secrets.syncthing.secrets."syncthing.key".path or null;
|
|
||||||
cert =
|
|
||||||
lib.mkDefault
|
|
||||||
config.clan.secrets.syncthing.secrets."syncthing.cert".path or null;
|
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
options = {
|
options = {
|
||||||
@@ -127,38 +124,24 @@
|
|||||||
set -x
|
set -x
|
||||||
# query pending deviceID's
|
# query pending deviceID's
|
||||||
APIKEY=$(cat ${apiKey})
|
APIKEY=$(cat ${apiKey})
|
||||||
PENDING=$(${
|
PENDING=$(${lib.getExe pkgs.curl} -X GET -H "X-API-Key: $APIKEY" ${baseAddress}${getPendingDevices})
|
||||||
lib.getExe pkgs.curl
|
|
||||||
} -X GET -H "X-API-Key: $APIKEY" ${baseAddress}${getPendingDevices})
|
|
||||||
PENDING=$(echo $PENDING | ${lib.getExe pkgs.jq} keys[])
|
PENDING=$(echo $PENDING | ${lib.getExe pkgs.jq} keys[])
|
||||||
|
|
||||||
# accept pending deviceID's
|
# accept pending deviceID's
|
||||||
for ID in $PENDING;do
|
for ID in $PENDING;do
|
||||||
${
|
${lib.getExe pkgs.curl} -X POST -d "{\"deviceId\": $ID}" -H "Content-Type: application/json" -H "X-API-Key: $APIKEY" ${baseAddress}${postNewDevice}
|
||||||
lib.getExe pkgs.curl
|
|
||||||
} -X POST -d "{\"deviceId\": $ID}" -H "Content-Type: application/json" -H "X-API-Key: $APIKEY" ${baseAddress}${postNewDevice}
|
|
||||||
|
|
||||||
# get all shared folders by their ID
|
# get all shared folders by their ID
|
||||||
for folder in ${builtins.toString config.clan.syncthing.autoShares}; do
|
for folder in ${builtins.toString config.clan.syncthing.autoShares}; do
|
||||||
SHARED_IDS=$(${
|
SHARED_IDS=$(${lib.getExe pkgs.curl} -X GET -H "X-API-Key: $APIKEY" ${baseAddress}${SharedFolderById}"$folder" | ${lib.getExe pkgs.jq} ."devices")
|
||||||
lib.getExe pkgs.curl
|
PATCHED_IDS=$(echo $SHARED_IDS | ${lib.getExe pkgs.jq} ".+= [{\"deviceID\": $ID, \"introducedBy\": \"\", \"encryptionPassword\": \"\"}]")
|
||||||
} -X GET -H "X-API-Key: $APIKEY" ${baseAddress}${SharedFolderById}"$folder" | ${
|
${lib.getExe pkgs.curl} -X PATCH -d "{\"devices\": $PATCHED_IDS}" -H "X-API-Key: $APIKEY" ${baseAddress}${SharedFolderById}"$folder"
|
||||||
lib.getExe pkgs.jq
|
|
||||||
} ."devices")
|
|
||||||
PATCHED_IDS=$(echo $SHARED_IDS | ${
|
|
||||||
lib.getExe pkgs.jq
|
|
||||||
} ".+= [{\"deviceID\": $ID, \"introducedBy\": \"\", \"encryptionPassword\": \"\"}]")
|
|
||||||
${
|
|
||||||
lib.getExe pkgs.curl
|
|
||||||
} -X PATCH -d "{\"devices\": $PATCHED_IDS}" -H "X-API-Key: $APIKEY" ${baseAddress}${SharedFolderById}"$folder"
|
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.timers.syncthing-auto-accept =
|
systemd.timers.syncthing-auto-accept = lib.mkIf config.clan.syncthing.autoAcceptDevices {
|
||||||
lib.mkIf config.clan.syncthing.autoAcceptDevices
|
|
||||||
{
|
|
||||||
description = "Syncthing Auto Accept";
|
description = "Syncthing Auto Accept";
|
||||||
|
|
||||||
wantedBy = [ "syncthing-auto-accept.service" ];
|
wantedBy = [ "syncthing-auto-accept.service" ];
|
||||||
@@ -182,9 +165,7 @@
|
|||||||
set -efu pipefail
|
set -efu pipefail
|
||||||
|
|
||||||
APIKEY=$(cat ${apiKey})
|
APIKEY=$(cat ${apiKey})
|
||||||
${
|
${lib.getExe pkgs.gnused} -i "s/<apikey>.*<\/apikey>/<apikey>$APIKEY<\/apikey>/" /var/lib/syncthing/config.xml
|
||||||
lib.getExe pkgs.gnused
|
|
||||||
} -i "s/<apikey>.*<\/apikey>/<apikey>$APIKEY<\/apikey>/" /var/lib/syncthing/config.xml
|
|
||||||
# sudo systemctl restart syncthing.service
|
# sudo systemctl restart syncthing.service
|
||||||
systemctl restart syncthing.service
|
systemctl restart syncthing.service
|
||||||
'';
|
'';
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
{ pkgs
|
{
|
||||||
, lib
|
pkgs,
|
||||||
, config
|
lib,
|
||||||
, ...
|
config,
|
||||||
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
options.clan.services.waypipe = {
|
options.clan.services.waypipe = {
|
||||||
@@ -49,7 +50,10 @@
|
|||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
uid = 1000;
|
uid = 1000;
|
||||||
password = "";
|
password = "";
|
||||||
extraGroups = [ "wheel" "video" ];
|
extraGroups = [
|
||||||
|
"wheel"
|
||||||
|
"video"
|
||||||
|
];
|
||||||
shell = "/run/current-system/sw/bin/bash";
|
shell = "/run/current-system/sw/bin/bash";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
{ pkgs, lib, config, ... }: {
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
options.clan.zt-tcp-relay = {
|
options.clan.zt-tcp-relay = {
|
||||||
port = lib.mkOption {
|
port = lib.mkOption {
|
||||||
type = lib.types.port;
|
type = lib.types.port;
|
||||||
@@ -13,7 +19,9 @@
|
|||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${pkgs.callPackage ../pkgs/zt-tcp-relay {}}/bin/zt-tcp-relay --listen [::]:${builtins.toString config.clan.zt-tcp-relay.port}";
|
ExecStart = "${
|
||||||
|
pkgs.callPackage ../pkgs/zt-tcp-relay { }
|
||||||
|
}/bin/zt-tcp-relay --listen [::]:${builtins.toString config.clan.zt-tcp-relay.port}";
|
||||||
Restart = "always";
|
Restart = "always";
|
||||||
RestartSec = "5";
|
RestartSec = "5";
|
||||||
dynamicUsers = true;
|
dynamicUsers = true;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
perSystem =
|
perSystem =
|
||||||
{ pkgs
|
{
|
||||||
, self'
|
pkgs,
|
||||||
, lib
|
self',
|
||||||
, ...
|
lib,
|
||||||
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
python3 = pkgs.python3;
|
python3 = pkgs.python3;
|
||||||
@@ -20,9 +21,7 @@
|
|||||||
ps.pygobject3
|
ps.pygobject3
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
linuxOnlyPackages = lib.optionals pkgs.stdenv.isLinux [
|
linuxOnlyPackages = lib.optionals pkgs.stdenv.isLinux [ pkgs.xdg-utils ];
|
||||||
pkgs.xdg-utils
|
|
||||||
];
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
devShells.python = pkgs.mkShell {
|
devShells.python = pkgs.mkShell {
|
||||||
|
|||||||
12
devShell.nix
12
devShell.nix
@@ -1,9 +1,10 @@
|
|||||||
{
|
{
|
||||||
perSystem =
|
perSystem =
|
||||||
{ pkgs
|
{
|
||||||
, self'
|
pkgs,
|
||||||
, config
|
self',
|
||||||
, ...
|
config,
|
||||||
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
writers = pkgs.callPackage ./pkgs/builders/script-writers.nix { };
|
writers = pkgs.callPackage ./pkgs/builders/script-writers.nix { };
|
||||||
@@ -16,8 +17,7 @@
|
|||||||
# A python program to switch between dev-shells
|
# A python program to switch between dev-shells
|
||||||
# usage: select-shell shell-name
|
# usage: select-shell shell-name
|
||||||
# the currently enabled dev-shell gets stored in ./.direnv/selected-shell
|
# the currently enabled dev-shell gets stored in ./.direnv/selected-shell
|
||||||
select-shell = writers.writePython3Bin "select-shell"
|
select-shell = writers.writePython3Bin "select-shell" {
|
||||||
{
|
|
||||||
flakeIgnore = [ "E501" ];
|
flakeIgnore = [ "E501" ];
|
||||||
} ./pkgs/scripts/select-shell.py;
|
} ./pkgs/scripts/select-shell.py;
|
||||||
in
|
in
|
||||||
|
|||||||
26
flake.nix
26
flake.nix
@@ -2,7 +2,9 @@
|
|||||||
description = "clan.lol base operating system";
|
description = "clan.lol base operating system";
|
||||||
|
|
||||||
nixConfig.extra-substituters = [ "https://cache.clan.lol" ];
|
nixConfig.extra-substituters = [ "https://cache.clan.lol" ];
|
||||||
nixConfig.extra-trusted-public-keys = [ "cache.clan.lol-1:3KztgSAB5R1M+Dz7vzkBGzXdodizbgLXGXKXlcQLA28=" ];
|
nixConfig.extra-trusted-public-keys = [
|
||||||
|
"cache.clan.lol-1:3KztgSAB5R1M+Dz7vzkBGzXdodizbgLXGXKXlcQLA28="
|
||||||
|
];
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable-small";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable-small";
|
||||||
@@ -20,8 +22,11 @@
|
|||||||
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
|
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = inputs @ { flake-parts, ... }:
|
outputs =
|
||||||
flake-parts.lib.mkFlake { inherit inputs; } ({ lib, ... }: {
|
inputs@{ flake-parts, ... }:
|
||||||
|
flake-parts.lib.mkFlake { inherit inputs; } (
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
systems = [
|
systems = [
|
||||||
"x86_64-linux"
|
"x86_64-linux"
|
||||||
"aarch64-linux"
|
"aarch64-linux"
|
||||||
@@ -44,20 +49,15 @@
|
|||||||
clanInternals = lib.mkOption {
|
clanInternals = lib.mkOption {
|
||||||
type = lib.types.submodule {
|
type = lib.types.submodule {
|
||||||
options = {
|
options = {
|
||||||
all-machines-json = lib.mkOption {
|
all-machines-json = lib.mkOption { type = lib.types.attrsOf lib.types.str; };
|
||||||
type = lib.types.attrsOf lib.types.str;
|
machines = lib.mkOption { type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified); };
|
||||||
};
|
machinesFunc = lib.mkOption { type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified); };
|
||||||
machines = lib.mkOption {
|
|
||||||
type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified);
|
|
||||||
};
|
|
||||||
machinesFunc = lib.mkOption {
|
|
||||||
type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
{ lib
|
{ lib, inputs, ... }:
|
||||||
, inputs
|
{
|
||||||
, ...
|
imports = [ inputs.treefmt-nix.flakeModule ];
|
||||||
}: {
|
perSystem =
|
||||||
imports = [
|
{ self', pkgs, ... }:
|
||||||
inputs.treefmt-nix.flakeModule
|
{
|
||||||
];
|
|
||||||
perSystem = { self', pkgs, ... }: {
|
|
||||||
treefmt.projectRootFile = "flake.nix";
|
treefmt.projectRootFile = "flake.nix";
|
||||||
treefmt.programs.shellcheck.enable = true;
|
treefmt.programs.shellcheck.enable = true;
|
||||||
|
|
||||||
|
|||||||
@@ -1,38 +1,51 @@
|
|||||||
{ clan-core, nixpkgs, lib }:
|
{
|
||||||
{ directory # The directory containing the machines subdirectory
|
clan-core,
|
||||||
, specialArgs ? { } # Extra arguments to pass to nixosSystem i.e. useful to make self available
|
nixpkgs,
|
||||||
, machines ? { } # allows to include machine-specific modules i.e. machines.${name} = { ... }
|
lib,
|
||||||
, clanName # Needs to be (globally) unique, as this determines the folder name where the flake gets downloaded to.
|
}:
|
||||||
, clanIcon ? null # A path to an icon to be used for the clan, should be the same for all machines
|
{
|
||||||
, pkgsForSystem ? (_system: null) # A map from arch to pkgs, if specified this nixpkgs will be only imported once for each system.
|
directory, # The directory containing the machines subdirectory
|
||||||
# This improves performance, but all nipxkgs.* options will be ignored.
|
specialArgs ? { }, # Extra arguments to pass to nixosSystem i.e. useful to make self available
|
||||||
|
machines ? { }, # allows to include machine-specific modules i.e. machines.${name} = { ... }
|
||||||
|
clanName, # Needs to be (globally) unique, as this determines the folder name where the flake gets downloaded to.
|
||||||
|
clanIcon ? null, # A path to an icon to be used for the clan, should be the same for all machines
|
||||||
|
pkgsForSystem ? (_system: null), # A map from arch to pkgs, if specified this nixpkgs will be only imported once for each system.
|
||||||
|
# This improves performance, but all nipxkgs.* options will be ignored.
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
machinesDirs = lib.optionalAttrs (builtins.pathExists "${directory}/machines") (builtins.readDir (directory + /machines));
|
machinesDirs = lib.optionalAttrs (builtins.pathExists "${directory}/machines") (
|
||||||
|
builtins.readDir (directory + /machines)
|
||||||
|
);
|
||||||
|
|
||||||
machineSettings = machineName:
|
machineSettings =
|
||||||
|
machineName:
|
||||||
# CLAN_MACHINE_SETTINGS_FILE allows to override the settings file temporarily
|
# CLAN_MACHINE_SETTINGS_FILE allows to override the settings file temporarily
|
||||||
# This is useful for doing a dry-run before writing changes into the settings.json
|
# This is useful for doing a dry-run before writing changes into the settings.json
|
||||||
# Using CLAN_MACHINE_SETTINGS_FILE requires passing --impure to nix eval
|
# Using CLAN_MACHINE_SETTINGS_FILE requires passing --impure to nix eval
|
||||||
if builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE" != ""
|
if builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE" != "" then
|
||||||
then builtins.fromJSON (builtins.readFile (builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE"))
|
builtins.fromJSON (builtins.readFile (builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE"))
|
||||||
else
|
else
|
||||||
lib.optionalAttrs (builtins.pathExists "${directory}/machines/${machineName}/settings.json")
|
lib.optionalAttrs (builtins.pathExists "${directory}/machines/${machineName}/settings.json") (
|
||||||
(builtins.fromJSON
|
builtins.fromJSON (builtins.readFile (directory + /machines/${machineName}/settings.json))
|
||||||
(builtins.readFile (directory + /machines/${machineName}/settings.json)));
|
);
|
||||||
|
|
||||||
# Read additional imports specified via a config option in settings.json
|
# Read additional imports specified via a config option in settings.json
|
||||||
# This is not an infinite recursion, because the imports are discovered here
|
# This is not an infinite recursion, because the imports are discovered here
|
||||||
# before calling evalModules.
|
# before calling evalModules.
|
||||||
# It is still useful to have the imports as an option, as this allows for type
|
# It is still useful to have the imports as an option, as this allows for type
|
||||||
# checking and easy integration with the config frontend(s)
|
# checking and easy integration with the config frontend(s)
|
||||||
machineImports = machineSettings:
|
machineImports =
|
||||||
map
|
machineSettings: map (module: clan-core.clanModules.${module}) (machineSettings.clanImports or [ ]);
|
||||||
(module: clan-core.clanModules.${module})
|
|
||||||
(machineSettings.clanImports or [ ]);
|
|
||||||
|
|
||||||
# TODO: remove default system once we have a hardware-config mechanism
|
# TODO: remove default system once we have a hardware-config mechanism
|
||||||
nixosConfiguration = { system ? "x86_64-linux", name, pkgs ? null, extraConfig ? { } }: nixpkgs.lib.nixosSystem {
|
nixosConfiguration =
|
||||||
|
{
|
||||||
|
system ? "x86_64-linux",
|
||||||
|
name,
|
||||||
|
pkgs ? null,
|
||||||
|
extraConfig ? { },
|
||||||
|
}:
|
||||||
|
nixpkgs.lib.nixosSystem {
|
||||||
modules =
|
modules =
|
||||||
let
|
let
|
||||||
settings = machineSettings name;
|
settings = machineSettings name;
|
||||||
@@ -43,7 +56,8 @@ let
|
|||||||
clan-core.nixosModules.clanCore
|
clan-core.nixosModules.clanCore
|
||||||
extraConfig
|
extraConfig
|
||||||
(machines.${name} or { })
|
(machines.${name} or { })
|
||||||
({
|
(
|
||||||
|
{
|
||||||
clanCore.clanName = clanName;
|
clanCore.clanName = clanName;
|
||||||
clanCore.clanIcon = clanIcon;
|
clanCore.clanIcon = clanIcon;
|
||||||
clanCore.clanDir = directory;
|
clanCore.clanDir = directory;
|
||||||
@@ -55,9 +69,9 @@ let
|
|||||||
type = "path";
|
type = "path";
|
||||||
path = lib.mkDefault nixpkgs;
|
path = lib.mkDefault nixpkgs;
|
||||||
};
|
};
|
||||||
} // lib.optionalAttrs (pkgs != null) {
|
}
|
||||||
nixpkgs.pkgs = lib.mkForce pkgs;
|
// lib.optionalAttrs (pkgs != null) { nixpkgs.pkgs = lib.mkForce pkgs; }
|
||||||
})
|
)
|
||||||
];
|
];
|
||||||
inherit specialArgs;
|
inherit specialArgs;
|
||||||
};
|
};
|
||||||
@@ -77,27 +91,38 @@ let
|
|||||||
# This instantiates nixos for each system that we support:
|
# This instantiates nixos for each system that we support:
|
||||||
# configPerSystem = <system>.<machine>.nixosConfiguration
|
# configPerSystem = <system>.<machine>.nixosConfiguration
|
||||||
# We need this to build nixos secret generators for each system
|
# We need this to build nixos secret generators for each system
|
||||||
configsPerSystem = builtins.listToAttrs
|
configsPerSystem = builtins.listToAttrs (
|
||||||
(builtins.map
|
builtins.map (
|
||||||
(system: lib.nameValuePair system
|
system:
|
||||||
(lib.mapAttrs
|
lib.nameValuePair system (
|
||||||
(name: _: nixosConfiguration {
|
lib.mapAttrs (
|
||||||
|
name: _:
|
||||||
|
nixosConfiguration {
|
||||||
inherit name system;
|
inherit name system;
|
||||||
pkgs = pkgsForSystem system;
|
pkgs = pkgsForSystem system;
|
||||||
})
|
}
|
||||||
allMachines))
|
) allMachines
|
||||||
supportedSystems);
|
)
|
||||||
|
) supportedSystems
|
||||||
|
);
|
||||||
|
|
||||||
configsFuncPerSystem = builtins.listToAttrs
|
configsFuncPerSystem = builtins.listToAttrs (
|
||||||
(builtins.map
|
builtins.map (
|
||||||
(system: lib.nameValuePair system
|
system:
|
||||||
(lib.mapAttrs
|
lib.nameValuePair system (
|
||||||
(name: _: args: nixosConfiguration (args // {
|
lib.mapAttrs (
|
||||||
|
name: _: args:
|
||||||
|
nixosConfiguration (
|
||||||
|
args
|
||||||
|
// {
|
||||||
inherit name system;
|
inherit name system;
|
||||||
pkgs = pkgsForSystem system;
|
pkgs = pkgsForSystem system;
|
||||||
}))
|
}
|
||||||
allMachines))
|
)
|
||||||
supportedSystems);
|
) allMachines
|
||||||
|
)
|
||||||
|
) supportedSystems
|
||||||
|
);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
inherit nixosConfigurations;
|
inherit nixosConfigurations;
|
||||||
@@ -105,8 +130,11 @@ in
|
|||||||
clanInternals = {
|
clanInternals = {
|
||||||
machines = configsPerSystem;
|
machines = configsPerSystem;
|
||||||
machinesFunc = configsFuncPerSystem;
|
machinesFunc = configsFuncPerSystem;
|
||||||
all-machines-json = lib.mapAttrs
|
all-machines-json = lib.mapAttrs (
|
||||||
(system: configs: nixpkgs.legacyPackages.${system}.writers.writeJSON "machines.json" (lib.mapAttrs (_: m: m.config.system.clan.deployment.data) configs))
|
system: configs:
|
||||||
configsPerSystem;
|
nixpkgs.legacyPackages.${system}.writers.writeJSON "machines.json" (
|
||||||
|
lib.mapAttrs (_: m: m.config.system.clan.deployment.data) configs
|
||||||
|
)
|
||||||
|
) configsPerSystem;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
{ lib, clan-core, nixpkgs, ... }:
|
{
|
||||||
|
lib,
|
||||||
|
clan-core,
|
||||||
|
nixpkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
{
|
{
|
||||||
jsonschema = import ./jsonschema { inherit lib; };
|
jsonschema = import ./jsonschema { inherit lib; };
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{ lib
|
{
|
||||||
, inputs
|
lib,
|
||||||
, self
|
inputs,
|
||||||
, ...
|
self,
|
||||||
}: {
|
...
|
||||||
imports = [
|
}:
|
||||||
./jsonschema/flake-module.nix
|
{
|
||||||
];
|
imports = [ ./jsonschema/flake-module.nix ];
|
||||||
flake.lib = import ./default.nix {
|
flake.lib = import ./default.nix {
|
||||||
inherit lib;
|
inherit lib;
|
||||||
inherit (inputs) nixpkgs;
|
inherit (inputs) nixpkgs;
|
||||||
|
|||||||
@@ -1,65 +1,72 @@
|
|||||||
{ lib ? import <nixpkgs/lib>
|
{
|
||||||
, excludedTypes ? [
|
lib ? import <nixpkgs/lib>,
|
||||||
|
excludedTypes ? [
|
||||||
"functionTo"
|
"functionTo"
|
||||||
"package"
|
"package"
|
||||||
]
|
],
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
# remove _module attribute from options
|
# remove _module attribute from options
|
||||||
clean = opts: builtins.removeAttrs opts [ "_module" ];
|
clean = opts: builtins.removeAttrs opts [ "_module" ];
|
||||||
|
|
||||||
# throw error if option type is not supported
|
# throw error if option type is not supported
|
||||||
notSupported = option: lib.trace option throw ''
|
notSupported =
|
||||||
|
option:
|
||||||
|
lib.trace option throw ''
|
||||||
option type '${option.type.name}' ('${option.type.description}') not supported by jsonschema converter
|
option type '${option.type.name}' ('${option.type.description}') not supported by jsonschema converter
|
||||||
location: ${lib.concatStringsSep "." option.loc}
|
location: ${lib.concatStringsSep "." option.loc}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
isExcludedOption = option: (lib.elem (option.type.name or null) excludedTypes);
|
isExcludedOption = option: (lib.elem (option.type.name or null) excludedTypes);
|
||||||
|
|
||||||
filterExcluded = lib.filter (opt: ! isExcludedOption opt);
|
filterExcluded = lib.filter (opt: !isExcludedOption opt);
|
||||||
|
|
||||||
filterExcludedAttrs = lib.filterAttrs (_name: opt: ! isExcludedOption opt);
|
filterExcludedAttrs = lib.filterAttrs (_name: opt: !isExcludedOption opt);
|
||||||
|
|
||||||
allBasicTypes =
|
|
||||||
[ "boolean" "integer" "number" "string" "array" "object" "null" ];
|
|
||||||
|
|
||||||
|
allBasicTypes = [
|
||||||
|
"boolean"
|
||||||
|
"integer"
|
||||||
|
"number"
|
||||||
|
"string"
|
||||||
|
"array"
|
||||||
|
"object"
|
||||||
|
"null"
|
||||||
|
];
|
||||||
in
|
in
|
||||||
rec {
|
rec {
|
||||||
|
|
||||||
# parses a nixos module to a jsonschema
|
# parses a nixos module to a jsonschema
|
||||||
parseModule = module:
|
parseModule =
|
||||||
|
module:
|
||||||
let
|
let
|
||||||
evaled = lib.evalModules {
|
evaled = lib.evalModules { modules = [ module ]; };
|
||||||
modules = [ module ];
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
parseOptions evaled.options;
|
parseOptions evaled.options;
|
||||||
|
|
||||||
# parses a set of evaluated nixos options to a jsonschema
|
# parses a set of evaluated nixos options to a jsonschema
|
||||||
parseOptions = options':
|
parseOptions =
|
||||||
|
options':
|
||||||
let
|
let
|
||||||
options = filterExcludedAttrs (clean options');
|
options = filterExcludedAttrs (clean options');
|
||||||
# parse options to jsonschema properties
|
# parse options to jsonschema properties
|
||||||
properties = lib.mapAttrs (_name: option: parseOption option) options;
|
properties = lib.mapAttrs (_name: option: parseOption option) options;
|
||||||
# TODO: figure out how to handle if prop.anyOf is used
|
# TODO: figure out how to handle if prop.anyOf is used
|
||||||
isRequired = prop: ! (prop ? default || prop.type or null == "object");
|
isRequired = prop: !(prop ? default || prop.type or null == "object");
|
||||||
requiredProps = lib.filterAttrs (_: prop: isRequired prop) properties;
|
requiredProps = lib.filterAttrs (_: prop: isRequired prop) properties;
|
||||||
required = lib.optionalAttrs (requiredProps != { }) {
|
required = lib.optionalAttrs (requiredProps != { }) { required = lib.attrNames requiredProps; };
|
||||||
required = lib.attrNames requiredProps;
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
# return jsonschema
|
# return jsonschema
|
||||||
required // {
|
required
|
||||||
|
// {
|
||||||
type = "object";
|
type = "object";
|
||||||
inherit properties;
|
inherit properties;
|
||||||
};
|
};
|
||||||
|
|
||||||
# parses and evaluated nixos option to a jsonschema property definition
|
# parses and evaluated nixos option to a jsonschema property definition
|
||||||
parseOption = option:
|
parseOption =
|
||||||
|
option:
|
||||||
let
|
let
|
||||||
default = lib.optionalAttrs (option ? default) {
|
default = lib.optionalAttrs (option ? default) { inherit (option) default; };
|
||||||
inherit (option) default;
|
|
||||||
};
|
|
||||||
description = lib.optionalAttrs (option ? description) {
|
description = lib.optionalAttrs (option ? description) {
|
||||||
description = option.description.text or option.description;
|
description = option.description.text or option.description;
|
||||||
};
|
};
|
||||||
@@ -67,177 +74,217 @@ rec {
|
|||||||
|
|
||||||
# either type
|
# either type
|
||||||
# TODO: if all nested optiosn are excluded, the parent sould be excluded too
|
# TODO: if all nested optiosn are excluded, the parent sould be excluded too
|
||||||
if option.type.name or null == "either"
|
if
|
||||||
|
option.type.name or null == "either"
|
||||||
# return jsonschema property definition for either
|
# return jsonschema property definition for either
|
||||||
then
|
then
|
||||||
let
|
let
|
||||||
optionsList' = [
|
optionsList' = [
|
||||||
{ type = option.type.nestedTypes.left; _type = "option"; loc = option.loc; }
|
{
|
||||||
{ type = option.type.nestedTypes.right; _type = "option"; loc = option.loc; }
|
type = option.type.nestedTypes.left;
|
||||||
|
_type = "option";
|
||||||
|
loc = option.loc;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type = option.type.nestedTypes.right;
|
||||||
|
_type = "option";
|
||||||
|
loc = option.loc;
|
||||||
|
}
|
||||||
];
|
];
|
||||||
optionsList = filterExcluded optionsList';
|
optionsList = filterExcluded optionsList';
|
||||||
in
|
in
|
||||||
default // description // {
|
default // description // { anyOf = map parseOption optionsList; }
|
||||||
anyOf = map parseOption optionsList;
|
|
||||||
}
|
|
||||||
|
|
||||||
# handle nested options (not a submodule)
|
# handle nested options (not a submodule)
|
||||||
else if ! option ? _type
|
else if !option ? _type then
|
||||||
then parseOptions option
|
parseOptions option
|
||||||
|
|
||||||
# throw if not an option
|
# throw if not an option
|
||||||
else if option._type != "option" && option._type != "option-type"
|
else if option._type != "option" && option._type != "option-type" then
|
||||||
then throw "parseOption: not an option"
|
throw "parseOption: not an option"
|
||||||
|
|
||||||
# parse nullOr
|
# parse nullOr
|
||||||
else if option.type.name == "nullOr"
|
else if
|
||||||
|
option.type.name == "nullOr"
|
||||||
# return jsonschema property definition for nullOr
|
# return jsonschema property definition for nullOr
|
||||||
then
|
then
|
||||||
let
|
let
|
||||||
nestedOption =
|
nestedOption = {
|
||||||
{ type = option.type.nestedTypes.elemType; _type = "option"; loc = option.loc; };
|
type = option.type.nestedTypes.elemType;
|
||||||
|
_type = "option";
|
||||||
|
loc = option.loc;
|
||||||
|
};
|
||||||
in
|
in
|
||||||
default // description // {
|
default
|
||||||
anyOf =
|
// description
|
||||||
[{ type = "null"; }]
|
// {
|
||||||
++ (
|
anyOf = [
|
||||||
lib.optional (! isExcludedOption nestedOption)
|
{ type = "null"; }
|
||||||
(parseOption nestedOption)
|
] ++ (lib.optional (!isExcludedOption nestedOption) (parseOption nestedOption));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# parse bool
|
# parse bool
|
||||||
else if option.type.name == "bool"
|
else if
|
||||||
|
option.type.name == "bool"
|
||||||
# return jsonschema property definition for bool
|
# return jsonschema property definition for bool
|
||||||
then default // description // {
|
then
|
||||||
type = "boolean";
|
default // description // { type = "boolean"; }
|
||||||
}
|
|
||||||
|
|
||||||
# parse float
|
# parse float
|
||||||
else if option.type.name == "float"
|
else if
|
||||||
|
option.type.name == "float"
|
||||||
# return jsonschema property definition for float
|
# return jsonschema property definition for float
|
||||||
then default // description // {
|
then
|
||||||
type = "number";
|
default // description // { type = "number"; }
|
||||||
}
|
|
||||||
|
|
||||||
# parse int
|
# parse int
|
||||||
else if (option.type.name == "int" || option.type.name == "positiveInt")
|
else if
|
||||||
|
(option.type.name == "int" || option.type.name == "positiveInt")
|
||||||
# return jsonschema property definition for int
|
# return jsonschema property definition for int
|
||||||
then default // description // {
|
then
|
||||||
type = "integer";
|
default // description // { type = "integer"; }
|
||||||
}
|
|
||||||
|
|
||||||
# parse string
|
# parse string
|
||||||
else if option.type.name == "str"
|
else if
|
||||||
|
option.type.name == "str"
|
||||||
# return jsonschema property definition for string
|
# return jsonschema property definition for string
|
||||||
then default // description // {
|
then
|
||||||
type = "string";
|
default // description // { type = "string"; }
|
||||||
}
|
|
||||||
|
|
||||||
# parse string
|
# parse string
|
||||||
else if option.type.name == "path"
|
else if
|
||||||
|
option.type.name == "path"
|
||||||
# return jsonschema property definition for path
|
# return jsonschema property definition for path
|
||||||
then default // description // {
|
then
|
||||||
type = "string";
|
default // description // { type = "string"; }
|
||||||
}
|
|
||||||
|
|
||||||
# parse anything
|
# parse anything
|
||||||
else if option.type.name == "anything"
|
else if
|
||||||
|
option.type.name == "anything"
|
||||||
# return jsonschema property definition for anything
|
# return jsonschema property definition for anything
|
||||||
then default // description // {
|
then
|
||||||
type = allBasicTypes;
|
default // description // { type = allBasicTypes; }
|
||||||
}
|
|
||||||
|
|
||||||
# parse unspecified
|
# parse unspecified
|
||||||
else if option.type.name == "unspecified"
|
else if
|
||||||
|
option.type.name == "unspecified"
|
||||||
# return jsonschema property definition for unspecified
|
# return jsonschema property definition for unspecified
|
||||||
then default // description // {
|
then
|
||||||
type = allBasicTypes;
|
default // description // { type = allBasicTypes; }
|
||||||
}
|
|
||||||
|
|
||||||
# parse raw
|
# parse raw
|
||||||
else if option.type.name == "raw"
|
else if
|
||||||
|
option.type.name == "raw"
|
||||||
# return jsonschema property definition for raw
|
# return jsonschema property definition for raw
|
||||||
then default // description // {
|
then
|
||||||
type = allBasicTypes;
|
default // description // { type = allBasicTypes; }
|
||||||
}
|
|
||||||
|
|
||||||
# parse enum
|
# parse enum
|
||||||
else if option.type.name == "enum"
|
else if
|
||||||
|
option.type.name == "enum"
|
||||||
# return jsonschema property definition for enum
|
# return jsonschema property definition for enum
|
||||||
then default // description // {
|
then
|
||||||
enum = option.type.functor.payload;
|
default // description // { enum = option.type.functor.payload; }
|
||||||
}
|
|
||||||
|
|
||||||
# parse listOf submodule
|
# parse listOf submodule
|
||||||
else if option.type.name == "listOf" && option.type.functor.wrapped.name == "submodule"
|
else if
|
||||||
|
option.type.name == "listOf" && option.type.functor.wrapped.name == "submodule"
|
||||||
# return jsonschema property definition for listOf submodule
|
# return jsonschema property definition for listOf submodule
|
||||||
then default // description // {
|
then
|
||||||
|
default
|
||||||
|
// description
|
||||||
|
// {
|
||||||
type = "array";
|
type = "array";
|
||||||
items = parseOptions (option.type.functor.wrapped.getSubOptions option.loc);
|
items = parseOptions (option.type.functor.wrapped.getSubOptions option.loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
# parse list
|
# parse list
|
||||||
else if (option.type.name == "listOf")
|
else if
|
||||||
|
(option.type.name == "listOf")
|
||||||
# return jsonschema property definition for list
|
# return jsonschema property definition for list
|
||||||
then
|
then
|
||||||
let
|
let
|
||||||
nestedOption = { type = option.type.functor.wrapped; _type = "option"; loc = option.loc; };
|
nestedOption = {
|
||||||
|
type = option.type.functor.wrapped;
|
||||||
|
_type = "option";
|
||||||
|
loc = option.loc;
|
||||||
|
};
|
||||||
in
|
in
|
||||||
default // description // {
|
default
|
||||||
|
// description
|
||||||
|
// {
|
||||||
type = "array";
|
type = "array";
|
||||||
}
|
}
|
||||||
// (lib.optionalAttrs (! isExcludedOption nestedOption) {
|
// (lib.optionalAttrs (!isExcludedOption nestedOption) { items = parseOption nestedOption; })
|
||||||
items = parseOption nestedOption;
|
|
||||||
})
|
|
||||||
|
|
||||||
# parse list of unspecified
|
# parse list of unspecified
|
||||||
else if
|
else if
|
||||||
(option.type.name == "listOf")
|
(option.type.name == "listOf") && (option.type.functor.wrapped.name == "unspecified")
|
||||||
&& (option.type.functor.wrapped.name == "unspecified")
|
|
||||||
# return jsonschema property definition for list
|
# return jsonschema property definition for list
|
||||||
then default // description // {
|
then
|
||||||
type = "array";
|
default // description // { type = "array"; }
|
||||||
}
|
|
||||||
|
|
||||||
# parse attrsOf submodule
|
# parse attrsOf submodule
|
||||||
else if option.type.name == "attrsOf" && option.type.nestedTypes.elemType.name == "submodule"
|
else if
|
||||||
|
option.type.name == "attrsOf" && option.type.nestedTypes.elemType.name == "submodule"
|
||||||
# return jsonschema property definition for attrsOf submodule
|
# return jsonschema property definition for attrsOf submodule
|
||||||
then default // description // {
|
then
|
||||||
|
default
|
||||||
|
// description
|
||||||
|
// {
|
||||||
type = "object";
|
type = "object";
|
||||||
additionalProperties = parseOptions (option.type.nestedTypes.elemType.getSubOptions option.loc);
|
additionalProperties = parseOptions (option.type.nestedTypes.elemType.getSubOptions option.loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
# parse attrs
|
# parse attrs
|
||||||
else if option.type.name == "attrs"
|
else if
|
||||||
|
option.type.name == "attrs"
|
||||||
# return jsonschema property definition for attrs
|
# return jsonschema property definition for attrs
|
||||||
then default // description // {
|
then
|
||||||
|
default
|
||||||
|
// description
|
||||||
|
// {
|
||||||
type = "object";
|
type = "object";
|
||||||
additionalProperties = true;
|
additionalProperties = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
# parse attrsOf
|
# parse attrsOf
|
||||||
# TODO: if nested option is excluded, the parent sould be excluded too
|
# TODO: if nested option is excluded, the parent sould be excluded too
|
||||||
else if option.type.name == "attrsOf" || option.type.name == "lazyAttrsOf"
|
else if
|
||||||
|
option.type.name == "attrsOf" || option.type.name == "lazyAttrsOf"
|
||||||
# return jsonschema property definition for attrs
|
# return jsonschema property definition for attrs
|
||||||
then
|
then
|
||||||
let
|
let
|
||||||
nestedOption = { type = option.type.nestedTypes.elemType; _type = "option"; loc = option.loc; };
|
nestedOption = {
|
||||||
|
type = option.type.nestedTypes.elemType;
|
||||||
|
_type = "option";
|
||||||
|
loc = option.loc;
|
||||||
|
};
|
||||||
in
|
in
|
||||||
default // description // {
|
default
|
||||||
|
// description
|
||||||
|
// {
|
||||||
type = "object";
|
type = "object";
|
||||||
additionalProperties =
|
additionalProperties =
|
||||||
if ! isExcludedOption nestedOption
|
if !isExcludedOption nestedOption then
|
||||||
then parseOption { type = option.type.nestedTypes.elemType; _type = "option"; loc = option.loc; }
|
parseOption {
|
||||||
else false;
|
type = option.type.nestedTypes.elemType;
|
||||||
|
_type = "option";
|
||||||
|
loc = option.loc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
false;
|
||||||
}
|
}
|
||||||
|
|
||||||
# parse submodule
|
# parse submodule
|
||||||
else if option.type.name == "submodule"
|
else if
|
||||||
|
option.type.name == "submodule"
|
||||||
# return jsonschema property definition for submodule
|
# return jsonschema property definition for submodule
|
||||||
# then (lib.attrNames (option.type.getSubOptions option.loc).opt)
|
# then (lib.attrNames (option.type.getSubOptions option.loc).opt)
|
||||||
then parseOptions (option.type.getSubOptions option.loc)
|
then
|
||||||
|
parseOptions (option.type.getSubOptions option.loc)
|
||||||
|
|
||||||
# throw error if option type is not supported
|
# throw error if option type is not supported
|
||||||
else notSupported option;
|
else
|
||||||
|
notSupported option;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
/*
|
# An example nixos module declaring an interface.
|
||||||
An example nixos module declaring an interface.
|
{ lib, ... }:
|
||||||
*/
|
{
|
||||||
{ lib, ... }: {
|
|
||||||
options = {
|
options = {
|
||||||
# str
|
# str
|
||||||
name = lib.mkOption {
|
name = lib.mkOption {
|
||||||
@@ -44,7 +43,11 @@
|
|||||||
# list of str
|
# list of str
|
||||||
kernelModules = lib.mkOption {
|
kernelModules = lib.mkOption {
|
||||||
type = lib.types.listOf lib.types.str;
|
type = lib.types.listOf lib.types.str;
|
||||||
default = [ "nvme" "xhci_pci" "ahci" ];
|
default = [
|
||||||
|
"nvme"
|
||||||
|
"xhci_pci"
|
||||||
|
"ahci"
|
||||||
|
];
|
||||||
description = "A list of enabled kernel modules";
|
description = "A list of enabled kernel modules";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
perSystem = { pkgs, ... }: {
|
perSystem =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
checks = {
|
checks = {
|
||||||
|
|
||||||
# check if the `clan config` example jsonschema and data is valid
|
# check if the `clan config` example jsonschema and data is valid
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# run these tests via `nix-unit ./test.nix`
|
# run these tests via `nix-unit ./test.nix`
|
||||||
{ lib ? (import <nixpkgs> { }).lib
|
{
|
||||||
, slib ? import ./. { inherit lib; }
|
lib ? (import <nixpkgs> { }).lib,
|
||||||
|
slib ? import ./. { inherit lib; },
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
parseOption = import ./test_parseOption.nix { inherit lib slib; };
|
parseOption = import ./test_parseOption.nix { inherit lib slib; };
|
||||||
|
|||||||
@@ -1,21 +1,25 @@
|
|||||||
# tests for the nixos options to jsonschema converter
|
# tests for the nixos options to jsonschema converter
|
||||||
# run these tests via `nix-unit ./test.nix`
|
# run these tests via `nix-unit ./test.nix`
|
||||||
{ lib ? (import <nixpkgs> { }).lib
|
{
|
||||||
, slib ? import ./. { inherit lib; }
|
lib ? (import <nixpkgs> { }).lib,
|
||||||
|
slib ? import ./. { inherit lib; },
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
description = "Test Description";
|
description = "Test Description";
|
||||||
|
|
||||||
evalType = type: default:
|
evalType =
|
||||||
|
type: default:
|
||||||
let
|
let
|
||||||
evaledConfig = lib.evalModules {
|
evaledConfig = lib.evalModules {
|
||||||
modules = [{
|
modules = [
|
||||||
|
{
|
||||||
options.opt = lib.mkOption {
|
options.opt = lib.mkOption {
|
||||||
inherit type;
|
inherit type;
|
||||||
inherit default;
|
inherit default;
|
||||||
inherit description;
|
inherit description;
|
||||||
};
|
};
|
||||||
}];
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
evaledConfig.options.opt;
|
evaledConfig.options.opt;
|
||||||
@@ -25,11 +29,7 @@ in
|
|||||||
testNoDefaultNoDescription =
|
testNoDefaultNoDescription =
|
||||||
let
|
let
|
||||||
evaledConfig = lib.evalModules {
|
evaledConfig = lib.evalModules {
|
||||||
modules = [{
|
modules = [ { options.opt = lib.mkOption { type = lib.types.bool; }; } ];
|
||||||
options.opt = lib.mkOption {
|
|
||||||
type = lib.types.bool;
|
|
||||||
};
|
|
||||||
}];
|
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@@ -42,7 +42,8 @@ in
|
|||||||
testDescriptionIsAttrs =
|
testDescriptionIsAttrs =
|
||||||
let
|
let
|
||||||
evaledConfig = lib.evalModules {
|
evaledConfig = lib.evalModules {
|
||||||
modules = [{
|
modules = [
|
||||||
|
{
|
||||||
options.opt = lib.mkOption {
|
options.opt = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
description = {
|
description = {
|
||||||
@@ -50,7 +51,8 @@ in
|
|||||||
text = description;
|
text = description;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}];
|
}
|
||||||
|
];
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@@ -112,7 +114,11 @@ in
|
|||||||
testEnum =
|
testEnum =
|
||||||
let
|
let
|
||||||
default = "foo";
|
default = "foo";
|
||||||
values = [ "foo" "bar" "baz" ];
|
values = [
|
||||||
|
"foo"
|
||||||
|
"bar"
|
||||||
|
"baz"
|
||||||
|
];
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
expr = slib.parseOption (evalType (lib.types.enum values) default);
|
expr = slib.parseOption (evalType (lib.types.enum values) default);
|
||||||
@@ -124,7 +130,11 @@ in
|
|||||||
|
|
||||||
testListOfInt =
|
testListOfInt =
|
||||||
let
|
let
|
||||||
default = [ 1 2 3 ];
|
default = [
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
];
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
expr = slib.parseOption (evalType (lib.types.listOf lib.types.int) default);
|
expr = slib.parseOption (evalType (lib.types.listOf lib.types.int) default);
|
||||||
@@ -139,14 +149,26 @@ in
|
|||||||
|
|
||||||
testListOfUnspecified =
|
testListOfUnspecified =
|
||||||
let
|
let
|
||||||
default = [ 1 2 3 ];
|
default = [
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
];
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
expr = slib.parseOption (evalType (lib.types.listOf lib.types.unspecified) default);
|
expr = slib.parseOption (evalType (lib.types.listOf lib.types.unspecified) default);
|
||||||
expected = {
|
expected = {
|
||||||
type = "array";
|
type = "array";
|
||||||
items = {
|
items = {
|
||||||
type = [ "boolean" "integer" "number" "string" "array" "object" "null" ];
|
type = [
|
||||||
|
"boolean"
|
||||||
|
"integer"
|
||||||
|
"number"
|
||||||
|
"string"
|
||||||
|
"array"
|
||||||
|
"object"
|
||||||
|
"null"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
inherit default description;
|
inherit default description;
|
||||||
};
|
};
|
||||||
@@ -154,7 +176,11 @@ in
|
|||||||
|
|
||||||
testAttrs =
|
testAttrs =
|
||||||
let
|
let
|
||||||
default = { foo = 1; bar = 2; baz = 3; };
|
default = {
|
||||||
|
foo = 1;
|
||||||
|
bar = 2;
|
||||||
|
baz = 3;
|
||||||
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
expr = slib.parseOption (evalType (lib.types.attrs) default);
|
expr = slib.parseOption (evalType (lib.types.attrs) default);
|
||||||
@@ -167,7 +193,11 @@ in
|
|||||||
|
|
||||||
testAttrsOfInt =
|
testAttrsOfInt =
|
||||||
let
|
let
|
||||||
default = { foo = 1; bar = 2; baz = 3; };
|
default = {
|
||||||
|
foo = 1;
|
||||||
|
bar = 2;
|
||||||
|
baz = 3;
|
||||||
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
expr = slib.parseOption (evalType (lib.types.attrsOf lib.types.int) default);
|
expr = slib.parseOption (evalType (lib.types.attrsOf lib.types.int) default);
|
||||||
@@ -182,7 +212,11 @@ in
|
|||||||
|
|
||||||
testLazyAttrsOfInt =
|
testLazyAttrsOfInt =
|
||||||
let
|
let
|
||||||
default = { foo = 1; bar = 2; baz = 3; };
|
default = {
|
||||||
|
foo = 1;
|
||||||
|
bar = 2;
|
||||||
|
baz = 3;
|
||||||
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
expr = slib.parseOption (evalType (lib.types.lazyAttrsOf lib.types.int) default);
|
expr = slib.parseOption (evalType (lib.types.lazyAttrsOf lib.types.int) default);
|
||||||
@@ -286,7 +320,10 @@ in
|
|||||||
inherit description;
|
inherit description;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
default = { foo.opt = false; bar.opt = true; };
|
default = {
|
||||||
|
foo.opt = false;
|
||||||
|
bar.opt = true;
|
||||||
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
expr = slib.parseOption (evalType (lib.types.attrsOf (lib.types.submodule subModule)) default);
|
expr = slib.parseOption (evalType (lib.types.attrsOf (lib.types.submodule subModule)) default);
|
||||||
@@ -315,7 +352,10 @@ in
|
|||||||
inherit description;
|
inherit description;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
default = [{ opt = false; } { opt = true; }];
|
default = [
|
||||||
|
{ opt = false; }
|
||||||
|
{ opt = true; }
|
||||||
|
];
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
expr = slib.parseOption (evalType (lib.types.listOf (lib.types.submodule subModule)) default);
|
expr = slib.parseOption (evalType (lib.types.listOf (lib.types.submodule subModule)) default);
|
||||||
@@ -358,7 +398,15 @@ in
|
|||||||
expr = slib.parseOption (evalType lib.types.anything default);
|
expr = slib.parseOption (evalType lib.types.anything default);
|
||||||
expected = {
|
expected = {
|
||||||
inherit default description;
|
inherit default description;
|
||||||
type = [ "boolean" "integer" "number" "string" "array" "object" "null" ];
|
type = [
|
||||||
|
"boolean"
|
||||||
|
"integer"
|
||||||
|
"number"
|
||||||
|
"string"
|
||||||
|
"array"
|
||||||
|
"object"
|
||||||
|
"null"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -370,7 +418,15 @@ in
|
|||||||
expr = slib.parseOption (evalType lib.types.unspecified default);
|
expr = slib.parseOption (evalType lib.types.unspecified default);
|
||||||
expected = {
|
expected = {
|
||||||
inherit default description;
|
inherit default description;
|
||||||
type = [ "boolean" "integer" "number" "string" "array" "object" "null" ];
|
type = [
|
||||||
|
"boolean"
|
||||||
|
"integer"
|
||||||
|
"number"
|
||||||
|
"string"
|
||||||
|
"array"
|
||||||
|
"object"
|
||||||
|
"null"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -382,7 +438,15 @@ in
|
|||||||
expr = slib.parseOption (evalType lib.types.raw default);
|
expr = slib.parseOption (evalType lib.types.raw default);
|
||||||
expected = {
|
expected = {
|
||||||
inherit default description;
|
inherit default description;
|
||||||
type = [ "boolean" "integer" "number" "string" "array" "object" "null" ];
|
type = [
|
||||||
|
"boolean"
|
||||||
|
"integer"
|
||||||
|
"number"
|
||||||
|
"string"
|
||||||
|
"array"
|
||||||
|
"object"
|
||||||
|
"null"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
# tests for the nixos options to jsonschema converter
|
# tests for the nixos options to jsonschema converter
|
||||||
# run these tests via `nix-unit ./test.nix`
|
# run these tests via `nix-unit ./test.nix`
|
||||||
{ lib ? (import <nixpkgs> { }).lib
|
{
|
||||||
, slib ? import ./. { inherit lib; }
|
lib ? (import <nixpkgs> { }).lib,
|
||||||
|
slib ? import ./. { inherit lib; },
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
evaledOptions =
|
evaledOptions =
|
||||||
let
|
let
|
||||||
evaledConfig = lib.evalModules {
|
evaledConfig = lib.evalModules { modules = [ ./example-interface.nix ]; };
|
||||||
modules = [ ./example-interface.nix ];
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
evaledConfig.options;
|
evaledConfig.options;
|
||||||
in
|
in
|
||||||
@@ -21,11 +20,7 @@ in
|
|||||||
testParseNestedOptions =
|
testParseNestedOptions =
|
||||||
let
|
let
|
||||||
evaled = lib.evalModules {
|
evaled = lib.evalModules {
|
||||||
modules = [{
|
modules = [ { options.foo.bar = lib.mkOption { type = lib.types.bool; }; } ];
|
||||||
options.foo.bar = lib.mkOption {
|
|
||||||
type = lib.types.bool;
|
|
||||||
};
|
|
||||||
}];
|
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
@@ -34,7 +29,9 @@ in
|
|||||||
properties = {
|
properties = {
|
||||||
foo = {
|
foo = {
|
||||||
properties = {
|
properties = {
|
||||||
bar = { type = "boolean"; };
|
bar = {
|
||||||
|
type = "boolean";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
required = [ "bar" ];
|
required = [ "bar" ];
|
||||||
type = "object";
|
type = "object";
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
{ lib, ... }:
|
{ lib, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [ ./state.nix ];
|
||||||
./state.nix
|
|
||||||
];
|
|
||||||
options.clanCore.backups = {
|
options.clanCore.backups = {
|
||||||
providers = lib.mkOption {
|
providers = lib.mkOption {
|
||||||
type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: {
|
type = lib.types.attrsOf (
|
||||||
|
lib.types.submodule (
|
||||||
|
{ name, ... }:
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
name = lib.mkOption {
|
name = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -39,7 +40,9 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}));
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
default = { };
|
default = { };
|
||||||
description = ''
|
description = ''
|
||||||
Configured backup providers which are used by this machine
|
Configured backup providers which are used by this machine
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{ lib
|
{ lib, ... }:
|
||||||
, ...
|
{
|
||||||
}: {
|
|
||||||
/*
|
/*
|
||||||
Declaring imports inside the module system does not trigger an infinite
|
Declaring imports inside the module system does not trigger an infinite
|
||||||
recursion in this case because buildClan generates the imports from the
|
recursion in this case because buildClan generates the imports from the
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
{ pkgs, ... }: { documentation.nixos.enable = pkgs.lib.mkDefault false; }
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
documentation.nixos.enable = pkgs.lib.mkDefault false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{ lib, pkgs, ... }: {
|
{ lib, pkgs, ... }:
|
||||||
|
{
|
||||||
options.clanCore = {
|
options.clanCore = {
|
||||||
clanName = lib.mkOption {
|
clanName = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
|
|||||||
@@ -49,7 +49,18 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
(lib.mkRenamedOptionModule [ "clan" "networking" "deploymentAddress" ] [ "clan" "networking" "targetHost" ])
|
(lib.mkRenamedOptionModule
|
||||||
|
[
|
||||||
|
"clan"
|
||||||
|
"networking"
|
||||||
|
"deploymentAddress"
|
||||||
|
]
|
||||||
|
[
|
||||||
|
"clan"
|
||||||
|
"networking"
|
||||||
|
"targetHost"
|
||||||
|
]
|
||||||
|
)
|
||||||
];
|
];
|
||||||
config = {
|
config = {
|
||||||
# conflicts with systemd-resolved
|
# conflicts with systemd-resolved
|
||||||
@@ -64,7 +75,9 @@
|
|||||||
systemd.network.wait-online.enable = false;
|
systemd.network.wait-online.enable = false;
|
||||||
|
|
||||||
# Provide a default network configuration but don't compete with network-manager or dhcpcd
|
# Provide a default network configuration but don't compete with network-manager or dhcpcd
|
||||||
systemd.network.networks."50-uplink" = lib.mkIf (!(config.networking.networkmanager.enable || config.networking.dhcpcd.enable)) {
|
systemd.network.networks."50-uplink" =
|
||||||
|
lib.mkIf (!(config.networking.networkmanager.enable || config.networking.dhcpcd.enable))
|
||||||
|
{
|
||||||
matchConfig.Type = "ether";
|
matchConfig.Type = "ether";
|
||||||
networkConfig = {
|
networkConfig = {
|
||||||
DHCP = "yes";
|
DHCP = "yes";
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
{ pkgs, options, lib, ... }: {
|
{
|
||||||
|
pkgs,
|
||||||
|
options,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
options.clanCore.optionsNix = lib.mkOption {
|
options.clanCore.optionsNix = lib.mkOption {
|
||||||
type = lib.types.raw;
|
type = lib.types.raw;
|
||||||
internal = true;
|
internal = true;
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
{ config, lib, pkgs, ... }: {
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
# TODO: factor these out into a separate interface.nix.
|
# TODO: factor these out into a separate interface.nix.
|
||||||
# Also think about moving these options out of `system.clan`.
|
# Also think about moving these options out of `system.clan`.
|
||||||
# Maybe we should not re-use the already polluted confg.system namespace
|
# Maybe we should not re-use the already polluted confg.system namespace
|
||||||
@@ -90,6 +96,8 @@
|
|||||||
inherit (config.clan.deployment) requireExplicitUpdate;
|
inherit (config.clan.deployment) requireExplicitUpdate;
|
||||||
inherit (config.clanCore) secretsUploadDirectory;
|
inherit (config.clanCore) secretsUploadDirectory;
|
||||||
};
|
};
|
||||||
system.clan.deployment.file = pkgs.writeText "deployment.json" (builtins.toJSON config.system.clan.deployment.data);
|
system.clan.deployment.file = pkgs.writeText "deployment.json" (
|
||||||
|
builtins.toJSON config.system.clan.deployment.data
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{ pkgs, ... }: {
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
# essential debugging tools for networked services
|
# essential debugging tools for networked services
|
||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
pkgs.dnsutils
|
pkgs.dnsutils
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
{
|
{
|
||||||
options.clanCore.secretStore = lib.mkOption {
|
options.clanCore.secretStore = lib.mkOption {
|
||||||
type = lib.types.enum [ "sops" "password-store" "vm" "custom" ];
|
type = lib.types.enum [
|
||||||
|
"sops"
|
||||||
|
"password-store"
|
||||||
|
"vm"
|
||||||
|
"custom"
|
||||||
|
];
|
||||||
default = "sops";
|
default = "sops";
|
||||||
description = ''
|
description = ''
|
||||||
method to store secrets
|
method to store secrets
|
||||||
@@ -34,8 +44,8 @@
|
|||||||
|
|
||||||
options.clanCore.secrets = lib.mkOption {
|
options.clanCore.secrets = lib.mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
type = lib.types.attrsOf
|
type = lib.types.attrsOf (
|
||||||
(lib.types.submodule (service: {
|
lib.types.submodule (service: {
|
||||||
options = {
|
options = {
|
||||||
name = lib.mkOption {
|
name = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -45,7 +55,9 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
generator = lib.mkOption {
|
generator = lib.mkOption {
|
||||||
type = lib.types.submodule ({ config, ... }: {
|
type = lib.types.submodule (
|
||||||
|
{ config, ... }:
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
path = lib.mkOption {
|
path = lib.mkOption {
|
||||||
type = lib.types.listOf (lib.types.either lib.types.path lib.types.package);
|
type = lib.types.listOf (lib.types.either lib.types.path lib.types.package);
|
||||||
@@ -83,17 +95,20 @@
|
|||||||
|
|
||||||
# prepare sandbox user
|
# prepare sandbox user
|
||||||
mkdir -p /etc
|
mkdir -p /etc
|
||||||
cp ${pkgs.runCommand "fake-etc" {} ''
|
cp ${
|
||||||
|
pkgs.runCommand "fake-etc" { } ''
|
||||||
export PATH="${pkgs.coreutils}/bin"
|
export PATH="${pkgs.coreutils}/bin"
|
||||||
mkdir -p $out
|
mkdir -p $out
|
||||||
cp /etc/* $out/
|
cp /etc/* $out/
|
||||||
''}/* /etc/
|
''
|
||||||
|
}/* /etc/
|
||||||
|
|
||||||
${config.script}
|
${config.script}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
secrets =
|
secrets =
|
||||||
let
|
let
|
||||||
@@ -101,8 +116,12 @@
|
|||||||
in
|
in
|
||||||
lib.mkOption {
|
lib.mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
type = lib.types.attrsOf (lib.types.submodule ({ config, name, ... }: {
|
type = lib.types.attrsOf (
|
||||||
options = {
|
lib.types.submodule (
|
||||||
|
{ config, name, ... }:
|
||||||
|
{
|
||||||
|
options =
|
||||||
|
{
|
||||||
name = lib.mkOption {
|
name = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
description = ''
|
description = ''
|
||||||
@@ -117,7 +136,8 @@
|
|||||||
'';
|
'';
|
||||||
default = "${config'.clanCore.secretsDirectory}/${config'.clanCore.secretsPrefix}${config.name}";
|
default = "${config'.clanCore.secretsDirectory}/${config'.clanCore.secretsPrefix}${config.name}";
|
||||||
};
|
};
|
||||||
} // lib.optionalAttrs (config'.clanCore.secretStore == "sops") {
|
}
|
||||||
|
// lib.optionalAttrs (config'.clanCore.secretStore == "sops") {
|
||||||
groups = lib.mkOption {
|
groups = lib.mkOption {
|
||||||
type = lib.types.listOf lib.types.str;
|
type = lib.types.listOf lib.types.str;
|
||||||
default = config'.clanCore.sops.defaultGroups;
|
default = config'.clanCore.sops.defaultGroups;
|
||||||
@@ -126,14 +146,17 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}));
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
description = ''
|
description = ''
|
||||||
path where the secret is located in the filesystem
|
path where the secret is located in the filesystem
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
facts = lib.mkOption {
|
facts = lib.mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
type = lib.types.attrsOf (lib.types.submodule (fact: {
|
type = lib.types.attrsOf (
|
||||||
|
lib.types.submodule (fact: {
|
||||||
options = {
|
options = {
|
||||||
name = lib.mkOption {
|
name = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
@@ -147,22 +170,23 @@
|
|||||||
description = ''
|
description = ''
|
||||||
path to a fact which is generated by the generator
|
path to a fact which is generated by the generator
|
||||||
'';
|
'';
|
||||||
default = config.clanCore.clanDir + "/machines/${config.clanCore.machineName}/facts/${fact.config._module.args.name}";
|
default =
|
||||||
|
config.clanCore.clanDir
|
||||||
|
+ "/machines/${config.clanCore.machineName}/facts/${fact.config._module.args.name}";
|
||||||
};
|
};
|
||||||
value = lib.mkOption {
|
value = lib.mkOption {
|
||||||
defaultText = lib.literalExpression "\${config.clanCore.clanDir}/\${fact.config.path}";
|
defaultText = lib.literalExpression "\${config.clanCore.clanDir}/\${fact.config.path}";
|
||||||
type = lib.types.nullOr lib.types.str;
|
type = lib.types.nullOr lib.types.str;
|
||||||
default =
|
default =
|
||||||
if builtins.pathExists fact.config.path then
|
if builtins.pathExists fact.config.path then lib.strings.fileContents fact.config.path else null;
|
||||||
lib.strings.fileContents fact.config.path
|
|
||||||
else
|
|
||||||
null;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
imports = [
|
imports = [
|
||||||
./sops.nix
|
./sops.nix
|
||||||
|
|||||||
@@ -13,4 +13,3 @@
|
|||||||
system.clan.secretsModule = "clan_cli.secrets.modules.password_store";
|
system.clan.secretsModule = "clan_cli.secrets.modules.password_store";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,33 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
secretsDir = config.clanCore.clanDir + "/sops/secrets";
|
secretsDir = config.clanCore.clanDir + "/sops/secrets";
|
||||||
groupsDir = config.clanCore.clanDir + "/sops/groups";
|
groupsDir = config.clanCore.clanDir + "/sops/groups";
|
||||||
|
|
||||||
|
|
||||||
# My symlink is in the nixos module detected as a directory also it works in the repl. Is this because of pure evaluation?
|
# My symlink is in the nixos module detected as a directory also it works in the repl. Is this because of pure evaluation?
|
||||||
containsSymlink = path:
|
containsSymlink =
|
||||||
builtins.pathExists path && (builtins.readFileType path == "directory" || builtins.readFileType path == "symlink");
|
path:
|
||||||
|
builtins.pathExists path
|
||||||
|
&& (builtins.readFileType path == "directory" || builtins.readFileType path == "symlink");
|
||||||
|
|
||||||
containsMachine = parent: name: type:
|
containsMachine =
|
||||||
|
parent: name: type:
|
||||||
type == "directory" && containsSymlink "${parent}/${name}/machines/${config.clanCore.machineName}";
|
type == "directory" && containsSymlink "${parent}/${name}/machines/${config.clanCore.machineName}";
|
||||||
|
|
||||||
containsMachineOrGroups = name: type:
|
containsMachineOrGroups =
|
||||||
(containsMachine secretsDir name type) || lib.any (group: type == "directory" && containsSymlink "${secretsDir}/${name}/groups/${group}") groups;
|
name: type:
|
||||||
|
(containsMachine secretsDir name type)
|
||||||
|
|| lib.any (
|
||||||
|
group: type == "directory" && containsSymlink "${secretsDir}/${name}/groups/${group}"
|
||||||
|
) groups;
|
||||||
|
|
||||||
filterDir = filter: dir:
|
filterDir =
|
||||||
lib.optionalAttrs (builtins.pathExists dir)
|
filter: dir:
|
||||||
(lib.filterAttrs filter (builtins.readDir dir));
|
lib.optionalAttrs (builtins.pathExists dir) (lib.filterAttrs filter (builtins.readDir dir));
|
||||||
|
|
||||||
groups = builtins.attrNames (filterDir (containsMachine groupsDir) groupsDir);
|
groups = builtins.attrNames (filterDir (containsMachine groupsDir) groupsDir);
|
||||||
secrets = filterDir containsMachineOrGroups secretsDir;
|
secrets = filterDir containsMachineOrGroups secretsDir;
|
||||||
@@ -34,17 +45,18 @@ in
|
|||||||
clanCore.secretsDirectory = "/run/secrets";
|
clanCore.secretsDirectory = "/run/secrets";
|
||||||
clanCore.secretsPrefix = config.clanCore.machineName + "-";
|
clanCore.secretsPrefix = config.clanCore.machineName + "-";
|
||||||
system.clan.secretsModule = "clan_cli.secrets.modules.sops";
|
system.clan.secretsModule = "clan_cli.secrets.modules.sops";
|
||||||
sops.secrets = builtins.mapAttrs
|
sops.secrets = builtins.mapAttrs (name: _: {
|
||||||
(name: _: {
|
|
||||||
sopsFile = config.clanCore.clanDir + "/sops/secrets/${name}/secret";
|
sopsFile = config.clanCore.clanDir + "/sops/secrets/${name}/secret";
|
||||||
format = "binary";
|
format = "binary";
|
||||||
})
|
}) secrets;
|
||||||
secrets;
|
|
||||||
# To get proper error messages about missing secrets we need a dummy secret file that is always present
|
# To get proper error messages about missing secrets we need a dummy secret file that is always present
|
||||||
sops.defaultSopsFile = lib.mkIf config.sops.validateSopsFiles (lib.mkDefault (builtins.toString (pkgs.writeText "dummy.yaml" "")));
|
sops.defaultSopsFile = lib.mkIf config.sops.validateSopsFiles (
|
||||||
|
lib.mkDefault (builtins.toString (pkgs.writeText "dummy.yaml" ""))
|
||||||
|
);
|
||||||
|
|
||||||
sops.age.keyFile = lib.mkIf (builtins.pathExists (config.clanCore.clanDir + "/sops/secrets/${config.clanCore.machineName}-age.key/secret"))
|
sops.age.keyFile = lib.mkIf (builtins.pathExists (
|
||||||
(lib.mkDefault "/var/lib/sops-nix/key.txt");
|
config.clanCore.clanDir + "/sops/secrets/${config.clanCore.machineName}-age.key/secret"
|
||||||
|
)) (lib.mkDefault "/var/lib/sops-nix/key.txt");
|
||||||
clanCore.secretsUploadDirectory = lib.mkDefault "/var/lib/sops-nix";
|
clanCore.secretsUploadDirectory = lib.mkDefault "/var/lib/sops-nix";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,4 +7,3 @@
|
|||||||
system.clan.factsModule = "clan_cli.facts.modules.vm";
|
system.clan.factsModule = "clan_cli.facts.modules.vm";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
{ lib, ... }:
|
{ lib, ... }:
|
||||||
{
|
{
|
||||||
# defaults
|
# defaults
|
||||||
config.clanCore.state.HOME.folders = [
|
config.clanCore.state.HOME.folders = [ "/home" ];
|
||||||
"/home"
|
|
||||||
];
|
|
||||||
|
|
||||||
# interface
|
# interface
|
||||||
options.clanCore.state = lib.mkOption {
|
options.clanCore.state = lib.mkOption {
|
||||||
default = { };
|
default = { };
|
||||||
type = lib.types.attrsOf
|
type = lib.types.attrsOf (
|
||||||
(lib.types.submodule ({ ... }: {
|
lib.types.submodule (
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
options = {
|
options = {
|
||||||
folders = lib.mkOption {
|
folders = lib.mkOption {
|
||||||
type = lib.types.listOf lib.types.str;
|
type = lib.types.listOf lib.types.str;
|
||||||
@@ -36,6 +36,8 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}));
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
{ lib, config, pkgs, options, extendModules, modulesPath, ... }:
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
options,
|
||||||
|
extendModules,
|
||||||
|
modulesPath,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
# Flatten the list of state folders into a single list
|
# Flatten the list of state folders into a single list
|
||||||
stateFolders = lib.flatten (
|
stateFolders = lib.flatten (lib.mapAttrsToList (_item: attrs: attrs.folders) config.clanCore.state);
|
||||||
lib.mapAttrsToList
|
|
||||||
(_item: attrs: attrs.folders)
|
|
||||||
config.clanCore.state
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
vmModule = {
|
vmModule = {
|
||||||
imports = [
|
imports = [
|
||||||
@@ -32,7 +35,10 @@ let
|
|||||||
# currently needed for system.etc.overlay.enable
|
# currently needed for system.etc.overlay.enable
|
||||||
boot.kernelPackages = pkgs.linuxPackages_latest;
|
boot.kernelPackages = pkgs.linuxPackages_latest;
|
||||||
|
|
||||||
boot.initrd.systemd.storePaths = [ pkgs.util-linux pkgs.e2fsprogs ];
|
boot.initrd.systemd.storePaths = [
|
||||||
|
pkgs.util-linux
|
||||||
|
pkgs.e2fsprogs
|
||||||
|
];
|
||||||
boot.initrd.systemd.emergencyAccess = true;
|
boot.initrd.systemd.emergencyAccess = true;
|
||||||
|
|
||||||
# sysusers is faster than nixos's perl scripts
|
# sysusers is faster than nixos's perl scripts
|
||||||
@@ -43,22 +49,39 @@ let
|
|||||||
|
|
||||||
boot.initrd.kernelModules = [ "virtiofs" ];
|
boot.initrd.kernelModules = [ "virtiofs" ];
|
||||||
virtualisation.writableStore = false;
|
virtualisation.writableStore = false;
|
||||||
virtualisation.fileSystems = lib.mkForce ({
|
virtualisation.fileSystems = lib.mkForce (
|
||||||
|
{
|
||||||
"/nix/store" = {
|
"/nix/store" = {
|
||||||
device = "nix-store";
|
device = "nix-store";
|
||||||
options = [ "x-systemd.requires=systemd-modules-load.service" "ro" ];
|
options = [
|
||||||
|
"x-systemd.requires=systemd-modules-load.service"
|
||||||
|
"ro"
|
||||||
|
];
|
||||||
fsType = "virtiofs";
|
fsType = "virtiofs";
|
||||||
};
|
};
|
||||||
|
|
||||||
"/" = {
|
"/" = {
|
||||||
device = "/dev/vda";
|
device = "/dev/vda";
|
||||||
fsType = "ext4";
|
fsType = "ext4";
|
||||||
options = [ "defaults" "x-systemd.makefs" "nobarrier" "noatime" "nodiratime" "data=writeback" "discard" ];
|
options = [
|
||||||
|
"defaults"
|
||||||
|
"x-systemd.makefs"
|
||||||
|
"nobarrier"
|
||||||
|
"noatime"
|
||||||
|
"nodiratime"
|
||||||
|
"data=writeback"
|
||||||
|
"discard"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
"/vmstate" = {
|
"/vmstate" = {
|
||||||
device = "/dev/vdb";
|
device = "/dev/vdb";
|
||||||
options = [ "x-systemd.makefs" "noatime" "nodiratime" "discard" ];
|
options = [
|
||||||
|
"x-systemd.makefs"
|
||||||
|
"noatime"
|
||||||
|
"nodiratime"
|
||||||
|
"discard"
|
||||||
|
];
|
||||||
noCheck = true;
|
noCheck = true;
|
||||||
fsType = "ext4";
|
fsType = "ext4";
|
||||||
};
|
};
|
||||||
@@ -67,26 +90,31 @@ let
|
|||||||
device = "secrets";
|
device = "secrets";
|
||||||
fsType = "9p";
|
fsType = "9p";
|
||||||
neededForBoot = true;
|
neededForBoot = true;
|
||||||
options = [ "trans=virtio" "version=9p2000.L" "cache=loose" ];
|
options = [
|
||||||
|
"trans=virtio"
|
||||||
|
"version=9p2000.L"
|
||||||
|
"cache=loose"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
}
|
||||||
} // lib.listToAttrs (map
|
// lib.listToAttrs (
|
||||||
(folder:
|
map (
|
||||||
|
folder:
|
||||||
lib.nameValuePair folder {
|
lib.nameValuePair folder {
|
||||||
device = "/vmstate${folder}";
|
device = "/vmstate${folder}";
|
||||||
fsType = "none";
|
fsType = "none";
|
||||||
options = [ "bind" ];
|
options = [ "bind" ];
|
||||||
})
|
}
|
||||||
stateFolders));
|
) stateFolders
|
||||||
|
)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
# We cannot simply merge the VM config into the current system config, because
|
# We cannot simply merge the VM config into the current system config, because
|
||||||
# it is not necessarily a VM.
|
# it is not necessarily a VM.
|
||||||
# Instead we use extendModules to create a second instance of the current
|
# Instead we use extendModules to create a second instance of the current
|
||||||
# system configuration, and then merge the VM config into that.
|
# system configuration, and then merge the VM config into that.
|
||||||
vmConfig = extendModules {
|
vmConfig = extendModules { modules = [ vmModule ]; };
|
||||||
modules = [ vmModule ];
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
@@ -210,12 +238,14 @@ in
|
|||||||
};
|
};
|
||||||
# for clan vm create
|
# for clan vm create
|
||||||
system.clan.vm = {
|
system.clan.vm = {
|
||||||
create = pkgs.writeText "vm.json" (builtins.toJSON {
|
create = pkgs.writeText "vm.json" (
|
||||||
|
builtins.toJSON {
|
||||||
initrd = "${vmConfig.config.system.build.initialRamdisk}/${vmConfig.config.system.boot.loader.initrdFile}";
|
initrd = "${vmConfig.config.system.build.initialRamdisk}/${vmConfig.config.system.boot.loader.initrdFile}";
|
||||||
toplevel = vmConfig.config.system.build.toplevel;
|
toplevel = vmConfig.config.system.build.toplevel;
|
||||||
regInfo = (pkgs.closureInfo { rootPaths = vmConfig.config.virtualisation.additionalPaths; });
|
regInfo = (pkgs.closureInfo { rootPaths = vmConfig.config.virtualisation.additionalPaths; });
|
||||||
inherit (config.clan.virtualisation) memorySize cores graphics;
|
inherit (config.clan.virtualisation) memorySize cores graphics;
|
||||||
});
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
virtualisation = lib.optionalAttrs (options.virtualisation ? cores) {
|
virtualisation = lib.optionalAttrs (options.virtualisation ? cores) {
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
{ pkgs, config, lib, ... }:
|
{
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
# maybe upstream this?
|
# maybe upstream this?
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
cfg = config.clan.networking.zerotier;
|
cfg = config.clan.networking.zerotier;
|
||||||
facts = config.clanCore.secrets.zerotier.facts or { };
|
facts = config.clanCore.secrets.zerotier.facts or { };
|
||||||
@@ -76,16 +81,18 @@ in
|
|||||||
};
|
};
|
||||||
settings = lib.mkOption {
|
settings = lib.mkOption {
|
||||||
description = lib.mdDoc "override the network config in /var/lib/zerotier/bla/$network.json";
|
description = lib.mdDoc "override the network config in /var/lib/zerotier/bla/$network.json";
|
||||||
type = lib.types.submodule {
|
type = lib.types.submodule { freeformType = (pkgs.formats.json { }).type; };
|
||||||
freeformType = (pkgs.formats.json { }).type;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
({
|
({
|
||||||
# Override license so that we can build zerotierone without
|
# Override license so that we can build zerotierone without
|
||||||
# having to re-import nixpkgs.
|
# having to re-import nixpkgs.
|
||||||
services.zerotierone.package = lib.mkDefault (pkgs.zerotierone.overrideAttrs (_old: { meta = { }; }));
|
services.zerotierone.package = lib.mkDefault (
|
||||||
|
pkgs.zerotierone.overrideAttrs (_old: {
|
||||||
|
meta = { };
|
||||||
|
})
|
||||||
|
);
|
||||||
})
|
})
|
||||||
(lib.mkIf ((facts.zerotier-ip.value or null) != null) {
|
(lib.mkIf ((facts.zerotier-ip.value or null) != null) {
|
||||||
environment.etc."zerotier/ip".text = facts.zerotier-ip.value;
|
environment.etc."zerotier/ip".text = facts.zerotier-ip.value;
|
||||||
@@ -111,7 +118,7 @@ in
|
|||||||
mkdir -p /var/lib/zerotier-one/controller.d/network
|
mkdir -p /var/lib/zerotier-one/controller.d/network
|
||||||
ln -sfT ${pkgs.writeText "net.json" (builtins.toJSON cfg.settings)} /var/lib/zerotier-one/controller.d/network/${cfg.networkId}.json
|
ln -sfT ${pkgs.writeText "net.json" (builtins.toJSON cfg.settings)} /var/lib/zerotier-one/controller.d/network/${cfg.networkId}.json
|
||||||
''}
|
''}
|
||||||
${lib.optionalString (cfg.moon.stableEndpoints != []) ''
|
${lib.optionalString (cfg.moon.stableEndpoints != [ ]) ''
|
||||||
if [[ ! -f /var/lib/zerotier-one/moon.json ]]; then
|
if [[ ! -f /var/lib/zerotier-one/moon.json ]]; then
|
||||||
zerotier-idtool initmoon /var/lib/zerotier-one/identity.public > /var/lib/zerotier-one/moon.json
|
zerotier-idtool initmoon /var/lib/zerotier-one/identity.public > /var/lib/zerotier-one/moon.json
|
||||||
fi
|
fi
|
||||||
@@ -123,7 +130,11 @@ in
|
|||||||
find /var/lib/zerotier-one/networks.d \
|
find /var/lib/zerotier-one/networks.d \
|
||||||
-type f \
|
-type f \
|
||||||
-name "*.conf" \
|
-name "*.conf" \
|
||||||
-not \( ${lib.concatMapStringsSep " -o " (netId: ''-name "${netId}.conf"'') config.services.zerotierone.joinNetworks} \) \
|
-not \( ${
|
||||||
|
lib.concatMapStringsSep " -o " (
|
||||||
|
netId: ''-name "${netId}.conf"''
|
||||||
|
) config.services.zerotierone.joinNetworks
|
||||||
|
} \) \
|
||||||
-delete
|
-delete
|
||||||
fi
|
fi
|
||||||
''}"
|
''}"
|
||||||
@@ -172,7 +183,11 @@ in
|
|||||||
facts.zerotier-ip = { };
|
facts.zerotier-ip = { };
|
||||||
facts.zerotier-network-id = { };
|
facts.zerotier-network-id = { };
|
||||||
secrets.zerotier-identity-secret = { };
|
secrets.zerotier-identity-secret = { };
|
||||||
generator.path = [ config.services.zerotierone.package pkgs.fakeroot pkgs.python3 ];
|
generator.path = [
|
||||||
|
config.services.zerotierone.package
|
||||||
|
pkgs.fakeroot
|
||||||
|
pkgs.python3
|
||||||
|
];
|
||||||
generator.script = ''
|
generator.script = ''
|
||||||
python3 ${./generate.py} --mode network \
|
python3 ${./generate.py} --mode network \
|
||||||
--ip "$facts/zerotier-ip" \
|
--ip "$facts/zerotier-ip" \
|
||||||
@@ -188,7 +203,10 @@ in
|
|||||||
clanCore.secrets.zerotier = {
|
clanCore.secrets.zerotier = {
|
||||||
facts.zerotier-ip = { };
|
facts.zerotier-ip = { };
|
||||||
secrets.zerotier-identity-secret = { };
|
secrets.zerotier-identity-secret = { };
|
||||||
generator.path = [ config.services.zerotierone.package pkgs.python3 ];
|
generator.path = [
|
||||||
|
config.services.zerotierone.package
|
||||||
|
pkgs.python3
|
||||||
|
];
|
||||||
generator.script = ''
|
generator.script = ''
|
||||||
python3 ${./generate.py} --mode identity \
|
python3 ${./generate.py} --mode identity \
|
||||||
--ip "$facts/zerotier-ip" \
|
--ip "$facts/zerotier-ip" \
|
||||||
@@ -200,9 +218,7 @@ in
|
|||||||
(lib.mkIf (cfg.controller.enable && (facts.zerotier-network-id.value or null) != null) {
|
(lib.mkIf (cfg.controller.enable && (facts.zerotier-network-id.value or null) != null) {
|
||||||
clan.networking.zerotier.networkId = facts.zerotier-network-id.value;
|
clan.networking.zerotier.networkId = facts.zerotier-network-id.value;
|
||||||
clan.networking.zerotier.settings = {
|
clan.networking.zerotier.settings = {
|
||||||
authTokens = [
|
authTokens = [ null ];
|
||||||
null
|
|
||||||
];
|
|
||||||
authorizationEndpoint = "";
|
authorizationEndpoint = "";
|
||||||
capabilities = [ ];
|
capabilities = [ ];
|
||||||
clientId = "";
|
clientId = "";
|
||||||
@@ -242,7 +258,9 @@ in
|
|||||||
environment.etc."zerotier/network-id".text = facts.zerotier-network-id.value;
|
environment.etc."zerotier/network-id".text = facts.zerotier-network-id.value;
|
||||||
systemd.services.zerotierone.serviceConfig.ExecStartPost = [
|
systemd.services.zerotierone.serviceConfig.ExecStartPost = [
|
||||||
"+${pkgs.writeShellScript "whitelist-controller" ''
|
"+${pkgs.writeShellScript "whitelist-controller" ''
|
||||||
${config.clanCore.clanPkgs.zerotier-members}/bin/zerotier-members allow ${builtins.substring 0 10 cfg.networkId}
|
${config.clanCore.clanPkgs.zerotier-members}/bin/zerotier-members allow ${
|
||||||
|
builtins.substring 0 10 cfg.networkId
|
||||||
|
}
|
||||||
''}"
|
''}"
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{ inputs, self, ... }: {
|
{ inputs, self, ... }:
|
||||||
|
{
|
||||||
flake.nixosModules = {
|
flake.nixosModules = {
|
||||||
hidden-ssh-announce.imports = [ ./hidden-ssh-announce.nix ];
|
hidden-ssh-announce.imports = [ ./hidden-ssh-announce.nix ];
|
||||||
installer.imports = [
|
installer.imports = [
|
||||||
@@ -10,9 +11,12 @@
|
|||||||
inputs.sops-nix.nixosModules.sops
|
inputs.sops-nix.nixosModules.sops
|
||||||
./clanCore
|
./clanCore
|
||||||
./iso
|
./iso
|
||||||
({ pkgs, lib, ... }: {
|
(
|
||||||
|
{ pkgs, lib, ... }:
|
||||||
|
{
|
||||||
clanCore.clanPkgs = lib.mkDefault self.packages.${pkgs.hostPlatform.system};
|
clanCore.clanPkgs = lib.mkDefault self.packages.${pkgs.hostPlatform.system};
|
||||||
})
|
}
|
||||||
|
)
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
{ config
|
{
|
||||||
, lib
|
config,
|
||||||
, pkgs
|
lib,
|
||||||
, ...
|
pkgs,
|
||||||
}: {
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
options.hidden-ssh-announce = {
|
options.hidden-ssh-announce = {
|
||||||
enable = lib.mkEnableOption "hidden-ssh-announce";
|
enable = lib.mkEnableOption "hidden-ssh-announce";
|
||||||
script = lib.mkOption {
|
script = lib.mkOption {
|
||||||
@@ -32,8 +34,14 @@
|
|||||||
};
|
};
|
||||||
systemd.services.hidden-ssh-announce = {
|
systemd.services.hidden-ssh-announce = {
|
||||||
description = "announce hidden ssh";
|
description = "announce hidden ssh";
|
||||||
after = [ "tor.service" "network-online.target" ];
|
after = [
|
||||||
wants = [ "tor.service" "network-online.target" ];
|
"tor.service"
|
||||||
|
"network-online.target"
|
||||||
|
];
|
||||||
|
wants = [
|
||||||
|
"tor.service"
|
||||||
|
"network-online.target"
|
||||||
|
];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
# ${pkgs.tor}/bin/torify
|
# ${pkgs.tor}/bin/torify
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{ lib
|
{
|
||||||
, pkgs
|
lib,
|
||||||
, modulesPath
|
pkgs,
|
||||||
, ...
|
modulesPath,
|
||||||
}: {
|
...
|
||||||
systemd.tmpfiles.rules = [
|
}:
|
||||||
"d /var/shared 0777 root root - -"
|
{
|
||||||
];
|
systemd.tmpfiles.rules = [ "d /var/shared 0777 root root - -" ];
|
||||||
imports = [
|
imports = [
|
||||||
(modulesPath + "/profiles/installation-device.nix")
|
(modulesPath + "/profiles/installation-device.nix")
|
||||||
(modulesPath + "/profiles/all-hardware.nix")
|
(modulesPath + "/profiles/all-hardware.nix")
|
||||||
@@ -21,7 +21,17 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
script = pkgs.writeShellScript "write-hostname" ''
|
script = pkgs.writeShellScript "write-hostname" ''
|
||||||
set -efu
|
set -efu
|
||||||
export PATH=${lib.makeBinPath (with pkgs; [ iproute2 coreutils jq qrencode ])}
|
export PATH=${
|
||||||
|
lib.makeBinPath (
|
||||||
|
with pkgs;
|
||||||
|
[
|
||||||
|
iproute2
|
||||||
|
coreutils
|
||||||
|
jq
|
||||||
|
qrencode
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
mkdir -p /var/shared
|
mkdir -p /var/shared
|
||||||
echo "$1" > /var/shared/onion-hostname
|
echo "$1" > /var/shared/onion-hostname
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
{ config, extendModules, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
extendModules,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
# Generates a fileSystems entry for bind mounting a given state folder path
|
# Generates a fileSystems entry for bind mounting a given state folder path
|
||||||
# It binds directories from /var/clanstate/{some-path} to /{some-path}.
|
# It binds directories from /var/clanstate/{some-path} to /{some-path}.
|
||||||
@@ -13,27 +19,19 @@ let
|
|||||||
};
|
};
|
||||||
|
|
||||||
# Flatten the list of state folders into a single list
|
# Flatten the list of state folders into a single list
|
||||||
stateFolders = lib.flatten (
|
stateFolders = lib.flatten (lib.mapAttrsToList (_item: attrs: attrs.folders) config.clanCore.state);
|
||||||
lib.mapAttrsToList
|
|
||||||
(_item: attrs: attrs.folders)
|
|
||||||
config.clanCore.state
|
|
||||||
);
|
|
||||||
|
|
||||||
# A module setting up bind mounts for all state folders
|
# A module setting up bind mounts for all state folders
|
||||||
stateMounts = {
|
stateMounts = {
|
||||||
fileSystems =
|
fileSystems = lib.listToAttrs (map mkBindMount stateFolders);
|
||||||
lib.listToAttrs
|
|
||||||
(map mkBindMount stateFolders);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
isoModule = { config, ... }: {
|
isoModule =
|
||||||
imports = [
|
{ config, ... }:
|
||||||
stateMounts
|
{
|
||||||
];
|
imports = [ stateMounts ];
|
||||||
options.clan.iso.disko = lib.mkOption {
|
options.clan.iso.disko = lib.mkOption {
|
||||||
type = lib.types.submodule {
|
type = lib.types.submodule { freeformType = (pkgs.formats.json { }).type; };
|
||||||
freeformType = (pkgs.formats.json { }).type;
|
|
||||||
};
|
|
||||||
default = {
|
default = {
|
||||||
disk = {
|
disk = {
|
||||||
iso = {
|
iso = {
|
||||||
@@ -78,9 +76,7 @@ let
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
isoConfig = extendModules {
|
isoConfig = extendModules { modules = [ isoModule ]; };
|
||||||
modules = [ isoModule ];
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = {
|
config = {
|
||||||
|
|||||||
@@ -1,36 +1,37 @@
|
|||||||
{ age
|
{
|
||||||
, lib
|
age,
|
||||||
, argcomplete
|
lib,
|
||||||
, installShellFiles
|
argcomplete,
|
||||||
, nix
|
installShellFiles,
|
||||||
, openssh
|
nix,
|
||||||
, pytest
|
openssh,
|
||||||
, pytest-cov
|
pytest,
|
||||||
, pytest-xdist
|
pytest-cov,
|
||||||
, pytest-subprocess
|
pytest-xdist,
|
||||||
, pytest-timeout
|
pytest-subprocess,
|
||||||
, remote-pdb
|
pytest-timeout,
|
||||||
, ipdb
|
remote-pdb,
|
||||||
, python3
|
ipdb,
|
||||||
, runCommand
|
python3,
|
||||||
, setuptools
|
runCommand,
|
||||||
, sops
|
setuptools,
|
||||||
, stdenv
|
sops,
|
||||||
, wheel
|
stdenv,
|
||||||
, fakeroot
|
wheel,
|
||||||
, rsync
|
fakeroot,
|
||||||
, bash
|
rsync,
|
||||||
, sshpass
|
bash,
|
||||||
, zbar
|
sshpass,
|
||||||
, tor
|
zbar,
|
||||||
, git
|
tor,
|
||||||
, nixpkgs
|
git,
|
||||||
, qemu
|
nixpkgs,
|
||||||
, gnupg
|
qemu,
|
||||||
, e2fsprogs
|
gnupg,
|
||||||
, mypy
|
e2fsprogs,
|
||||||
, rope
|
mypy,
|
||||||
, clan-core-path
|
rope,
|
||||||
|
clan-core-path,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
|
|
||||||
@@ -38,7 +39,10 @@ let
|
|||||||
argcomplete # optional dependency: if not enabled, shell completion will not work
|
argcomplete # optional dependency: if not enabled, shell completion will not work
|
||||||
];
|
];
|
||||||
|
|
||||||
pytestDependencies = runtimeDependencies ++ dependencies ++ [
|
pytestDependencies =
|
||||||
|
runtimeDependencies
|
||||||
|
++ dependencies
|
||||||
|
++ [
|
||||||
pytest
|
pytest
|
||||||
pytest-cov
|
pytest-cov
|
||||||
pytest-subprocess
|
pytest-subprocess
|
||||||
@@ -70,7 +74,9 @@ let
|
|||||||
e2fsprogs
|
e2fsprogs
|
||||||
];
|
];
|
||||||
|
|
||||||
runtimeDependenciesAsSet = builtins.listToAttrs (builtins.map (p: lib.nameValuePair (lib.getName p.name) p) runtimeDependencies);
|
runtimeDependenciesAsSet = builtins.listToAttrs (
|
||||||
|
builtins.map (p: lib.nameValuePair (lib.getName p.name) p) runtimeDependencies
|
||||||
|
);
|
||||||
|
|
||||||
checkPython = python3.withPackages (_ps: pytestDependencies);
|
checkPython = python3.withPackages (_ps: pytestDependencies);
|
||||||
|
|
||||||
@@ -121,8 +127,12 @@ python3.pkgs.buildPythonApplication {
|
|||||||
propagatedBuildInputs = dependencies;
|
propagatedBuildInputs = dependencies;
|
||||||
|
|
||||||
# also re-expose dependencies so we test them in CI
|
# also re-expose dependencies so we test them in CI
|
||||||
passthru.tests = (lib.mapAttrs' (n: lib.nameValuePair "clan-dep-${n}") runtimeDependenciesAsSet) // rec {
|
passthru.tests =
|
||||||
clan-pytest-without-core = runCommand "clan-pytest-without-core" { nativeBuildInputs = [ checkPython ] ++ pytestDependencies; } ''
|
(lib.mapAttrs' (n: lib.nameValuePair "clan-dep-${n}") runtimeDependenciesAsSet)
|
||||||
|
// rec {
|
||||||
|
clan-pytest-without-core =
|
||||||
|
runCommand "clan-pytest-without-core" { nativeBuildInputs = [ checkPython ] ++ pytestDependencies; }
|
||||||
|
''
|
||||||
cp -r ${source} ./src
|
cp -r ${source} ./src
|
||||||
chmod +w -R ./src
|
chmod +w -R ./src
|
||||||
cd ./src
|
cd ./src
|
||||||
@@ -132,7 +142,9 @@ python3.pkgs.buildPythonApplication {
|
|||||||
touch $out
|
touch $out
|
||||||
'';
|
'';
|
||||||
# separate the tests that can never be cached
|
# separate the tests that can never be cached
|
||||||
clan-pytest-with-core = runCommand "clan-pytest-with-core" { nativeBuildInputs = [ checkPython ] ++ pytestDependencies; } ''
|
clan-pytest-with-core =
|
||||||
|
runCommand "clan-pytest-with-core" { nativeBuildInputs = [ checkPython ] ++ pytestDependencies; }
|
||||||
|
''
|
||||||
cp -r ${source} ./src
|
cp -r ${source} ./src
|
||||||
chmod +w -R ./src
|
chmod +w -R ./src
|
||||||
cd ./src
|
cd ./src
|
||||||
|
|||||||
@@ -1,37 +1,44 @@
|
|||||||
{ inputs, self, lib, ... }:
|
|
||||||
{
|
{
|
||||||
perSystem = { self', pkgs, ... }:
|
inputs,
|
||||||
|
self,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
perSystem =
|
||||||
|
{ self', pkgs, ... }:
|
||||||
let
|
let
|
||||||
flakeLock = lib.importJSON (self + /flake.lock);
|
flakeLock = lib.importJSON (self + /flake.lock);
|
||||||
flakeInputs = (builtins.removeAttrs inputs [ "self" ]);
|
flakeInputs = (builtins.removeAttrs inputs [ "self" ]);
|
||||||
flakeLockVendoredDeps = flakeLock // {
|
flakeLockVendoredDeps = flakeLock // {
|
||||||
nodes = flakeLock.nodes // (
|
nodes =
|
||||||
lib.flip lib.mapAttrs flakeInputs (name: _: flakeLock.nodes.${name} // {
|
flakeLock.nodes
|
||||||
|
// (lib.flip lib.mapAttrs flakeInputs (
|
||||||
|
name: _:
|
||||||
|
flakeLock.nodes.${name}
|
||||||
|
// {
|
||||||
locked = {
|
locked = {
|
||||||
inherit (flakeLock.nodes.${name}.locked) narHash;
|
inherit (flakeLock.nodes.${name}.locked) narHash;
|
||||||
lastModified =
|
lastModified =
|
||||||
# lol, nixpkgs has a different timestamp on the fs???
|
# lol, nixpkgs has a different timestamp on the fs???
|
||||||
if name == "nixpkgs"
|
if name == "nixpkgs" then 0 else 1;
|
||||||
then 0
|
|
||||||
else 1;
|
|
||||||
path = "${inputs.${name}}";
|
path = "${inputs.${name}}";
|
||||||
type = "path";
|
type = "path";
|
||||||
};
|
};
|
||||||
})
|
}
|
||||||
);
|
));
|
||||||
};
|
};
|
||||||
flakeLockFile = builtins.toFile "clan-core-flake.lock"
|
flakeLockFile = builtins.toFile "clan-core-flake.lock" (builtins.toJSON flakeLockVendoredDeps);
|
||||||
(builtins.toJSON flakeLockVendoredDeps);
|
clanCoreWithVendoredDeps =
|
||||||
clanCoreWithVendoredDeps = lib.trace flakeLockFile pkgs.runCommand "clan-core-with-vendored-deps" { } ''
|
lib.trace flakeLockFile pkgs.runCommand "clan-core-with-vendored-deps" { }
|
||||||
|
''
|
||||||
cp -r ${self} $out
|
cp -r ${self} $out
|
||||||
chmod +w -R $out
|
chmod +w -R $out
|
||||||
cp ${flakeLockFile} $out/flake.lock
|
cp ${flakeLockFile} $out/flake.lock
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
devShells.clan-cli = pkgs.callPackage ./shell.nix {
|
devShells.clan-cli = pkgs.callPackage ./shell.nix { inherit (self'.packages) clan-cli; };
|
||||||
inherit (self'.packages) clan-cli;
|
|
||||||
};
|
|
||||||
packages = {
|
packages = {
|
||||||
clan-cli = pkgs.python3.pkgs.callPackage ./default.nix {
|
clan-cli = pkgs.python3.pkgs.callPackage ./default.nix {
|
||||||
inherit (inputs) nixpkgs;
|
inherit (inputs) nixpkgs;
|
||||||
@@ -42,5 +49,4 @@
|
|||||||
|
|
||||||
checks = self'.packages.clan-cli.tests;
|
checks = self'.packages.clan-cli.tests;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
{ nix-unit, clan-cli, system, mkShell, writeScriptBin, openssh, ruff, python3 }:
|
{
|
||||||
|
nix-unit,
|
||||||
|
clan-cli,
|
||||||
|
system,
|
||||||
|
mkShell,
|
||||||
|
writeScriptBin,
|
||||||
|
openssh,
|
||||||
|
ruff,
|
||||||
|
python3,
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
checkScript = writeScriptBin "check" ''
|
checkScript = writeScriptBin "check" ''
|
||||||
nix build .#checks.${system}.{treefmt,clan-pytest} -L "$@"
|
nix build .#checks.${system}.{treefmt,clan-pytest} -L "$@"
|
||||||
'';
|
'';
|
||||||
|
|
||||||
pythonWithDeps = python3.withPackages (
|
pythonWithDeps = python3.withPackages (
|
||||||
ps:
|
ps: clan-cli.propagatedBuildInputs ++ clan-cli.devDependencies ++ [ ps.pip ]
|
||||||
clan-cli.propagatedBuildInputs
|
|
||||||
++ clan-cli.devDependencies
|
|
||||||
++ [
|
|
||||||
ps.pip
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
in
|
in
|
||||||
mkShell {
|
mkShell {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{ lib, ... }: {
|
{ lib, ... }:
|
||||||
|
{
|
||||||
clan.networking.targetHost = "__CLAN_TARGET_ADDRESS__";
|
clan.networking.targetHost = "__CLAN_TARGET_ADDRESS__";
|
||||||
system.stateVersion = lib.version;
|
system.stateVersion = lib.version;
|
||||||
sops.age.keyFile = "__CLAN_SOPS_KEY_PATH__";
|
sops.age.keyFile = "__CLAN_SOPS_KEY_PATH__";
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{ lib, ... }: {
|
{ lib, ... }:
|
||||||
|
{
|
||||||
clan.networking.targetHost = "__CLAN_TARGET_ADDRESS__";
|
clan.networking.targetHost = "__CLAN_TARGET_ADDRESS__";
|
||||||
system.stateVersion = lib.version;
|
system.stateVersion = lib.version;
|
||||||
sops.age.keyFile = "__CLAN_SOPS_KEY_PATH__";
|
sops.age.keyFile = "__CLAN_SOPS_KEY_PATH__";
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{ lib, ... }: {
|
{ lib, ... }:
|
||||||
|
{
|
||||||
clan.networking.targetHost = "__CLAN_TARGET_ADDRESS__";
|
clan.networking.targetHost = "__CLAN_TARGET_ADDRESS__";
|
||||||
system.stateVersion = lib.version;
|
system.stateVersion = lib.version;
|
||||||
clan.virtualisation.graphics = false;
|
clan.virtualisation.graphics = false;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{ lib
|
{ lib, ... }:
|
||||||
, ...
|
{
|
||||||
}: {
|
|
||||||
options.clan.fake-module.fake-flag = lib.mkOption {
|
options.clan.fake-module.fake-flag = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
|
|||||||
@@ -2,32 +2,41 @@
|
|||||||
# this placeholder is replaced by the path to nixpkgs
|
# this placeholder is replaced by the path to nixpkgs
|
||||||
inputs.nixpkgs.url = "__NIXPKGS__";
|
inputs.nixpkgs.url = "__NIXPKGS__";
|
||||||
|
|
||||||
outputs = inputs':
|
outputs =
|
||||||
|
inputs':
|
||||||
let
|
let
|
||||||
# fake clan-core input
|
# fake clan-core input
|
||||||
fake-clan-core = {
|
fake-clan-core = {
|
||||||
clanModules.fake-module = ./fake-module.nix;
|
clanModules.fake-module = ./fake-module.nix;
|
||||||
};
|
};
|
||||||
inputs = inputs' // { clan-core = fake-clan-core; };
|
inputs = inputs' // {
|
||||||
|
clan-core = fake-clan-core;
|
||||||
|
};
|
||||||
machineSettings = (
|
machineSettings = (
|
||||||
if builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE" != ""
|
if builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE" != "" then
|
||||||
then builtins.fromJSON (builtins.readFile (builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE"))
|
builtins.fromJSON (builtins.readFile (builtins.getEnv "CLAN_MACHINE_SETTINGS_FILE"))
|
||||||
else if builtins.pathExists ./machines/machine1/settings.json
|
else if builtins.pathExists ./machines/machine1/settings.json then
|
||||||
then builtins.fromJSON (builtins.readFile ./machines/machine1/settings.json)
|
builtins.fromJSON (builtins.readFile ./machines/machine1/settings.json)
|
||||||
else { }
|
else
|
||||||
|
{ }
|
||||||
|
);
|
||||||
|
machineImports = map (module: fake-clan-core.clanModules.${module}) (
|
||||||
|
machineSettings.clanImports or [ ]
|
||||||
);
|
);
|
||||||
machineImports =
|
|
||||||
map
|
|
||||||
(module: fake-clan-core.clanModules.${module})
|
|
||||||
(machineSettings.clanImports or [ ]);
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
nixosConfigurations.machine1 = inputs.nixpkgs.lib.nixosSystem {
|
nixosConfigurations.machine1 = inputs.nixpkgs.lib.nixosSystem {
|
||||||
modules =
|
modules = machineImports ++ [
|
||||||
machineImports ++ [
|
|
||||||
./nixosModules/machine1.nix
|
./nixosModules/machine1.nix
|
||||||
machineSettings
|
machineSettings
|
||||||
({ lib, options, pkgs, ... }: {
|
(
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
options,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
config = {
|
config = {
|
||||||
nixpkgs.hostPlatform = "x86_64-linux";
|
nixpkgs.hostPlatform = "x86_64-linux";
|
||||||
# speed up by not instantiating nixpkgs twice and disable documentation
|
# speed up by not instantiating nixpkgs twice and disable documentation
|
||||||
@@ -51,7 +60,8 @@
|
|||||||
The buildClan function will automatically import these modules for the current machine.
|
The buildClan function will automatically import these modules for the current machine.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
})
|
}
|
||||||
|
)
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{ lib, ... }: {
|
{ lib, ... }:
|
||||||
|
{
|
||||||
options.clan.jitsi.enable = lib.mkOption {
|
options.clan.jitsi.enable = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
|
|||||||
@@ -5,13 +5,16 @@
|
|||||||
# this placeholder is replaced by the path to nixpkgs
|
# this placeholder is replaced by the path to nixpkgs
|
||||||
inputs.clan-core.url = "__CLAN_CORE__";
|
inputs.clan-core.url = "__CLAN_CORE__";
|
||||||
|
|
||||||
outputs = { self, clan-core }:
|
outputs =
|
||||||
|
{ self, clan-core }:
|
||||||
let
|
let
|
||||||
clan = clan-core.lib.buildClan {
|
clan = clan-core.lib.buildClan {
|
||||||
directory = self;
|
directory = self;
|
||||||
clanName = "test_flake_with_core";
|
clanName = "test_flake_with_core";
|
||||||
machines = {
|
machines = {
|
||||||
vm1 = { lib, ... }: {
|
vm1 =
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
clan.networking.targetHost = "__CLAN_TARGET_ADDRESS__";
|
clan.networking.targetHost = "__CLAN_TARGET_ADDRESS__";
|
||||||
system.stateVersion = lib.version;
|
system.stateVersion = lib.version;
|
||||||
sops.age.keyFile = "__CLAN_SOPS_KEY_PATH__";
|
sops.age.keyFile = "__CLAN_SOPS_KEY_PATH__";
|
||||||
@@ -32,7 +35,9 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
vm2 = { lib, ... }: {
|
vm2 =
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
clan.networking.targetHost = "__CLAN_TARGET_ADDRESS__";
|
clan.networking.targetHost = "__CLAN_TARGET_ADDRESS__";
|
||||||
system.stateVersion = lib.version;
|
system.stateVersion = lib.version;
|
||||||
sops.age.keyFile = "__CLAN_SOPS_KEY_PATH__";
|
sops.age.keyFile = "__CLAN_SOPS_KEY_PATH__";
|
||||||
|
|||||||
@@ -5,13 +5,16 @@
|
|||||||
# this placeholder is replaced by the path to clan-core
|
# this placeholder is replaced by the path to clan-core
|
||||||
inputs.clan-core.url = "__CLAN_CORE__";
|
inputs.clan-core.url = "__CLAN_CORE__";
|
||||||
|
|
||||||
outputs = { self, clan-core }:
|
outputs =
|
||||||
|
{ self, clan-core }:
|
||||||
let
|
let
|
||||||
clan = clan-core.lib.buildClan {
|
clan = clan-core.lib.buildClan {
|
||||||
directory = self;
|
directory = self;
|
||||||
clanName = "test_flake_with_core_and_pass";
|
clanName = "test_flake_with_core_and_pass";
|
||||||
machines = {
|
machines = {
|
||||||
vm1 = { lib, ... }: {
|
vm1 =
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
clan.networking.targetHost = "__CLAN_TARGET_ADDRESS__";
|
clan.networking.targetHost = "__CLAN_TARGET_ADDRESS__";
|
||||||
system.stateVersion = lib.version;
|
system.stateVersion = lib.version;
|
||||||
clanCore.secretStore = "password-store";
|
clanCore.secretStore = "password-store";
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
# this placeholder is replaced by the path to nixpkgs
|
# this placeholder is replaced by the path to nixpkgs
|
||||||
inputs.clan-core.url = "__CLAN_CORE__";
|
inputs.clan-core.url = "__CLAN_CORE__";
|
||||||
|
|
||||||
outputs = { self, clan-core }:
|
outputs =
|
||||||
|
{ self, clan-core }:
|
||||||
let
|
let
|
||||||
clan = clan-core.lib.buildClan {
|
clan = clan-core.lib.buildClan {
|
||||||
directory = self;
|
directory = self;
|
||||||
@@ -14,9 +15,7 @@
|
|||||||
let
|
let
|
||||||
machineModules = builtins.readDir (self + "/machines");
|
machineModules = builtins.readDir (self + "/machines");
|
||||||
in
|
in
|
||||||
builtins.mapAttrs
|
builtins.mapAttrs (name: _type: import (self + "/machines/${name}")) machineModules;
|
||||||
(name: _type: import (self + "/machines/${name}"))
|
|
||||||
machineModules;
|
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
{ python3
|
{
|
||||||
, runCommand
|
python3,
|
||||||
, setuptools
|
runCommand,
|
||||||
, copyDesktopItems
|
setuptools,
|
||||||
, pygobject3
|
copyDesktopItems,
|
||||||
, wrapGAppsHook
|
pygobject3,
|
||||||
, gtk4
|
wrapGAppsHook,
|
||||||
, gnome
|
gtk4,
|
||||||
, pygobject-stubs
|
gnome,
|
||||||
, gobject-introspection
|
pygobject-stubs,
|
||||||
, clan-cli
|
gobject-introspection,
|
||||||
, makeDesktopItem
|
clan-cli,
|
||||||
, libadwaita
|
makeDesktopItem,
|
||||||
|
libadwaita,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
source = ./.;
|
source = ./.;
|
||||||
@@ -41,7 +42,11 @@ python3.pkgs.buildPythonApplication {
|
|||||||
gobject-introspection
|
gobject-introspection
|
||||||
];
|
];
|
||||||
|
|
||||||
buildInputs = [ gtk4 libadwaita gnome.adwaita-icon-theme ];
|
buildInputs = [
|
||||||
|
gtk4
|
||||||
|
libadwaita
|
||||||
|
gnome.adwaita-icon-theme
|
||||||
|
];
|
||||||
|
|
||||||
# We need to propagate the build inputs to nix fmt / treefmt
|
# We need to propagate the build inputs to nix fmt / treefmt
|
||||||
propagatedBuildInputs = [
|
propagatedBuildInputs = [
|
||||||
@@ -73,7 +78,5 @@ python3.pkgs.buildPythonApplication {
|
|||||||
checkPhase = ''
|
checkPhase = ''
|
||||||
PYTHONPATH= $out/bin/clan-vm-manager --help
|
PYTHONPATH= $out/bin/clan-vm-manager --help
|
||||||
'';
|
'';
|
||||||
desktopItems = [
|
desktopItems = [ desktop-file ];
|
||||||
desktop-file
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
{ ... }: {
|
{ ... }:
|
||||||
perSystem = { config, pkgs, ... }: {
|
{
|
||||||
|
perSystem =
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
devShells.clan-vm-manager = pkgs.callPackage ./shell.nix {
|
devShells.clan-vm-manager = pkgs.callPackage ./shell.nix {
|
||||||
inherit (config.packages) clan-cli clan-vm-manager;
|
inherit (config.packages) clan-cli clan-vm-manager;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,33 @@
|
|||||||
{ lib, runCommand, makeWrapper, stdenv, clan-vm-manager, gdb, gtk4, libadwaita, clan-cli, mkShell, ruff, desktop-file-utils, xdg-utils, mypy, python3, python3Packages }:
|
{
|
||||||
|
lib,
|
||||||
|
runCommand,
|
||||||
|
makeWrapper,
|
||||||
|
stdenv,
|
||||||
|
clan-vm-manager,
|
||||||
|
gdb,
|
||||||
|
gtk4,
|
||||||
|
libadwaita,
|
||||||
|
clan-cli,
|
||||||
|
mkShell,
|
||||||
|
ruff,
|
||||||
|
desktop-file-utils,
|
||||||
|
xdg-utils,
|
||||||
|
mypy,
|
||||||
|
python3,
|
||||||
|
python3Packages,
|
||||||
|
}:
|
||||||
mkShell (
|
mkShell (
|
||||||
let
|
let
|
||||||
pygdb = runCommand "pygdb" { buildInputs = [ gdb python3 makeWrapper ]; } ''
|
pygdb =
|
||||||
|
runCommand "pygdb"
|
||||||
|
{
|
||||||
|
buildInputs = [
|
||||||
|
gdb
|
||||||
|
python3
|
||||||
|
makeWrapper
|
||||||
|
];
|
||||||
|
}
|
||||||
|
''
|
||||||
mkdir -p "$out/bin"
|
mkdir -p "$out/bin"
|
||||||
makeWrapper "${gdb}/bin/gdb" "$out/bin/pygdb" \
|
makeWrapper "${gdb}/bin/gdb" "$out/bin/pygdb" \
|
||||||
--add-flags '-ex "source ${python3}/share/gdb/libpython.py"'
|
--add-flags '-ex "source ${python3}/share/gdb/libpython.py"'
|
||||||
@@ -15,7 +41,6 @@ mkShell (
|
|||||||
pygdb
|
pygdb
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
# To debug clan-vm-manger execute pygdb --args python ./bin/clan-vm-manager
|
# To debug clan-vm-manger execute pygdb --args python ./bin/clan-vm-manager
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
ruff
|
ruff
|
||||||
|
|||||||
@@ -1,23 +1,30 @@
|
|||||||
{ ... }: {
|
{ ... }:
|
||||||
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./clan-cli/flake-module.nix
|
./clan-cli/flake-module.nix
|
||||||
./clan-vm-manager/flake-module.nix
|
./clan-vm-manager/flake-module.nix
|
||||||
./installer/flake-module.nix
|
./installer/flake-module.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
perSystem = { pkgs, config, lib, ... }: {
|
perSystem =
|
||||||
packages = {
|
{
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
packages =
|
||||||
|
{
|
||||||
tea-create-pr = pkgs.callPackage ./tea-create-pr { };
|
tea-create-pr = pkgs.callPackage ./tea-create-pr { };
|
||||||
zerotier-members = pkgs.callPackage ./zerotier-members { };
|
zerotier-members = pkgs.callPackage ./zerotier-members { };
|
||||||
zt-tcp-relay = pkgs.callPackage ./zt-tcp-relay { };
|
zt-tcp-relay = pkgs.callPackage ./zt-tcp-relay { };
|
||||||
merge-after-ci = pkgs.callPackage ./merge-after-ci {
|
merge-after-ci = pkgs.callPackage ./merge-after-ci { inherit (config.packages) tea-create-pr; };
|
||||||
inherit (config.packages) tea-create-pr;
|
|
||||||
};
|
|
||||||
pending-reviews = pkgs.callPackage ./pending-reviews { };
|
pending-reviews = pkgs.callPackage ./pending-reviews { };
|
||||||
} // lib.optionalAttrs pkgs.stdenv.isLinux {
|
}
|
||||||
|
// lib.optionalAttrs pkgs.stdenv.isLinux {
|
||||||
wayland-proxy-virtwl = pkgs.callPackage ./wayland-proxy-virtwl { };
|
wayland-proxy-virtwl = pkgs.callPackage ./wayland-proxy-virtwl { };
|
||||||
waypipe = pkgs.waypipe.overrideAttrs
|
waypipe = pkgs.waypipe.overrideAttrs (_old: {
|
||||||
(_old: {
|
|
||||||
# https://gitlab.freedesktop.org/mstoeckl/waypipe
|
# https://gitlab.freedesktop.org/mstoeckl/waypipe
|
||||||
src = pkgs.fetchFromGitLab {
|
src = pkgs.fetchFromGitLab {
|
||||||
domain = "gitlab.freedesktop.org";
|
domain = "gitlab.freedesktop.org";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{ lib
|
{
|
||||||
, buildGoModule
|
lib,
|
||||||
, fetchFromGitHub
|
buildGoModule,
|
||||||
,
|
fetchFromGitHub,
|
||||||
}:
|
}:
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "go-ssb";
|
pname = "go-ssb";
|
||||||
@@ -17,7 +17,10 @@ buildGoModule rec {
|
|||||||
|
|
||||||
vendorHash = "sha256-ZytuWFre7Cz6Qt01tLQoPEuNzDIyoC938OkdIrU8nZo=";
|
vendorHash = "sha256-ZytuWFre7Cz6Qt01tLQoPEuNzDIyoC938OkdIrU8nZo=";
|
||||||
|
|
||||||
ldflags = [ "-s" "-w" ];
|
ldflags = [
|
||||||
|
"-s"
|
||||||
|
"-w"
|
||||||
|
];
|
||||||
|
|
||||||
# take very long
|
# take very long
|
||||||
doCheck = false;
|
doCheck = false;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
{ self, lib, ... }:
|
{ self, lib, ... }:
|
||||||
let
|
let
|
||||||
installerModule = { config, pkgs, ... }: {
|
installerModule =
|
||||||
|
{ config, pkgs, ... }:
|
||||||
|
{
|
||||||
imports = [
|
imports = [
|
||||||
self.nixosModules.installer
|
self.nixosModules.installer
|
||||||
self.inputs.nixos-generators.nixosModules.all-formats
|
self.inputs.nixos-generators.nixosModules.all-formats
|
||||||
@@ -27,7 +29,9 @@ in
|
|||||||
flake.packages.x86_64-linux.install-iso = self.inputs.disko.lib.makeDiskImages {
|
flake.packages.x86_64-linux.install-iso = self.inputs.disko.lib.makeDiskImages {
|
||||||
nixosConfig = installer;
|
nixosConfig = installer;
|
||||||
};
|
};
|
||||||
flake.nixosConfigurations = { inherit (clan.nixosConfigurations) installer; };
|
flake.nixosConfigurations = {
|
||||||
|
inherit (clan.nixosConfigurations) installer;
|
||||||
|
};
|
||||||
flake.clanInternals = clan.clanInternals;
|
flake.clanInternals = clan.clanInternals;
|
||||||
flake.apps.x86_64-linux.install-vm.program = installer.config.formats.vm.outPath;
|
flake.apps.x86_64-linux.install-vm.program = installer.config.formats.vm.outPath;
|
||||||
flake.apps.x86_64-linux.install-vm-nogui.program = installer.config.formats.vm-nogui.outPath;
|
flake.apps.x86_64-linux.install-vm-nogui.program = installer.config.formats.vm-nogui.outPath;
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
{ bash
|
{
|
||||||
, callPackage
|
bash,
|
||||||
, coreutils
|
callPackage,
|
||||||
, git
|
coreutils,
|
||||||
, lib
|
git,
|
||||||
, nix
|
lib,
|
||||||
, openssh
|
nix,
|
||||||
, tea
|
openssh,
|
||||||
, tea-create-pr
|
tea,
|
||||||
, ...
|
tea-create-pr,
|
||||||
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
writers = callPackage ../builders/script-writers.nix { };
|
writers = callPackage ../builders/script-writers.nix { };
|
||||||
in
|
in
|
||||||
writers.writePython3Bin "merge-after-ci"
|
writers.writePython3Bin "merge-after-ci" {
|
||||||
{
|
|
||||||
makeWrapperArgs = [
|
makeWrapperArgs = [
|
||||||
"--prefix"
|
"--prefix"
|
||||||
"PATH"
|
"PATH"
|
||||||
@@ -28,6 +28,4 @@ writers.writePython3Bin "merge-after-ci"
|
|||||||
tea-create-pr
|
tea-create-pr
|
||||||
])
|
])
|
||||||
];
|
];
|
||||||
}
|
} ./merge-after-ci.py
|
||||||
./merge-after-ci.py
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{ writeShellApplication
|
{
|
||||||
, bash
|
writeShellApplication,
|
||||||
, curl
|
bash,
|
||||||
|
curl,
|
||||||
}:
|
}:
|
||||||
writeShellApplication {
|
writeShellApplication {
|
||||||
name = "pending-reviews";
|
name = "pending-reviews";
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
{ writeShellApplication
|
{
|
||||||
, bash
|
writeShellApplication,
|
||||||
, coreutils
|
bash,
|
||||||
, git
|
coreutils,
|
||||||
, tea
|
git,
|
||||||
, openssh
|
tea,
|
||||||
|
openssh,
|
||||||
}:
|
}:
|
||||||
writeShellApplication {
|
writeShellApplication {
|
||||||
name = "tea-create-pr";
|
name = "tea-create-pr";
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
{ wayland-proxy-virtwl, fetchFromGitHub, libdrm, ocaml-ng }:
|
{
|
||||||
|
wayland-proxy-virtwl,
|
||||||
|
fetchFromGitHub,
|
||||||
|
libdrm,
|
||||||
|
ocaml-ng,
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
ocaml-wayland = ocaml-ng.ocamlPackages_5_0.wayland.overrideAttrs (_old: {
|
ocaml-wayland = ocaml-ng.ocamlPackages_5_0.wayland.overrideAttrs (_old: {
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
@@ -16,7 +21,9 @@ wayland-proxy-virtwl.overrideAttrs (_old: {
|
|||||||
rev = "652fca9d4e006a2bdeba920dfaf53190c5373a7d";
|
rev = "652fca9d4e006a2bdeba920dfaf53190c5373a7d";
|
||||||
hash = "sha256-VgpqxjHgueK9eQSX987PF0KvscpzkScOzFkW3haYCOw=";
|
hash = "sha256-VgpqxjHgueK9eQSX987PF0KvscpzkScOzFkW3haYCOw=";
|
||||||
};
|
};
|
||||||
buildInputs = [ libdrm ] ++ (with ocaml-ng.ocamlPackages_5_0; [
|
buildInputs =
|
||||||
|
[ libdrm ]
|
||||||
|
++ (with ocaml-ng.ocamlPackages_5_0; [
|
||||||
ocaml-wayland
|
ocaml-wayland
|
||||||
dune-configurator
|
dune-configurator
|
||||||
eio_main
|
eio_main
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
{ stdenv, python3, lib }:
|
{
|
||||||
|
stdenv,
|
||||||
|
python3,
|
||||||
|
lib,
|
||||||
|
}:
|
||||||
|
|
||||||
stdenv.mkDerivation {
|
stdenv.mkDerivation {
|
||||||
name = "zerotier-members";
|
name = "zerotier-members";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{ lib
|
{
|
||||||
, rustPlatform
|
lib,
|
||||||
, fetchFromGitHub
|
rustPlatform,
|
||||||
|
fetchFromGitHub,
|
||||||
}:
|
}:
|
||||||
|
|
||||||
rustPlatform.buildRustPackage {
|
rustPlatform.buildRustPackage {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{ self, ... }: {
|
{ self, ... }:
|
||||||
|
{
|
||||||
flake.templates = {
|
flake.templates = {
|
||||||
new-clan = {
|
new-clan = {
|
||||||
description = "Initialize a new clan flake";
|
description = "Initialize a new clan flake";
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
inputs.clan-core.url = "git+https://git.clan.lol/clan/clan-core";
|
inputs.clan-core.url = "git+https://git.clan.lol/clan/clan-core";
|
||||||
|
|
||||||
outputs = { self, clan-core, ... }:
|
outputs =
|
||||||
|
{ self, clan-core, ... }:
|
||||||
let
|
let
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
pkgs = clan-core.inputs.nixpkgs.legacyPackages.${system};
|
pkgs = clan-core.inputs.nixpkgs.legacyPackages.${system};
|
||||||
@@ -17,9 +18,7 @@
|
|||||||
inherit (clan) nixosConfigurations clanInternals;
|
inherit (clan) nixosConfigurations clanInternals;
|
||||||
# add the cLAN cli tool to the dev shell
|
# add the cLAN cli tool to the dev shell
|
||||||
devShells.${system}.default = pkgs.mkShell {
|
devShells.${system}.default = pkgs.mkShell {
|
||||||
packages = [
|
packages = [ clan-core.packages.${system}.clan-cli ];
|
||||||
clan-core.packages.${system}.clan-cli
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user