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