forked from Fediversity/Fediversity
Compare commits
21 commits
Author | SHA1 | Date | |
---|---|---|---|
0ca360a36e | |||
7f96e57787 | |||
3988b83d35 | |||
3806713383 | |||
be37cdda43 | |||
79dad72315 | |||
dd072d4001 | |||
23e9ca696a | |||
a139d3b4db | |||
e42f165ca9 | |||
23393f4cef | |||
21c4cab1e0 | |||
a34ebc8a34 | |||
8135d3e1b8 | |||
1f01f088d8 | |||
913d513718 | |||
52ee811b05 | |||
7dc2bbde2d | |||
402327eae2 | |||
43f1246ed7 | |||
1019ac15b0 |
42 changed files with 1240 additions and 494 deletions
|
@ -31,4 +31,10 @@ jobs:
|
||||||
runs-on: native
|
runs-on: native
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- run: nix build .#checks.x86_64-linux.deployment-basic -L
|
- run: cd deployment && nix-build -A tests
|
||||||
|
|
||||||
|
check-launch:
|
||||||
|
runs-on: native
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- run: cd launch && nix-build -A tests
|
||||||
|
|
45
deployment/check/basic/basic.tfvars
Normal file
45
deployment/check/basic/basic.tfvars
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
garage = {
|
||||||
|
target = "target"
|
||||||
|
nix_module = <<-EOF
|
||||||
|
{
|
||||||
|
fediversityVm = {
|
||||||
|
# vmId = 7014;
|
||||||
|
proxmox = "fediversity";
|
||||||
|
# hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub;
|
||||||
|
# unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key;
|
||||||
|
domain = "test.example";
|
||||||
|
ipv4 = {
|
||||||
|
address = "";
|
||||||
|
gateway = "";
|
||||||
|
};
|
||||||
|
ipv6 = {
|
||||||
|
address = "";
|
||||||
|
gateway = "";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
# mastodon = {
|
||||||
|
# enable = true
|
||||||
|
# target = "target"
|
||||||
|
# nix_module = <<-EOF
|
||||||
|
# {
|
||||||
|
# fediversityVm = {
|
||||||
|
# # vmId = 7014;
|
||||||
|
# proxmox = "fediversity";
|
||||||
|
# # hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub;
|
||||||
|
# # unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key;
|
||||||
|
# domain = "test.example";
|
||||||
|
# ipv4 = {
|
||||||
|
# address = "";
|
||||||
|
# gateway = "";
|
||||||
|
# };
|
||||||
|
# ipv6 = {
|
||||||
|
# address = "";
|
||||||
|
# gateway = "";
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# }
|
||||||
|
# EOF
|
||||||
|
# }
|
|
@ -1,32 +1,13 @@
|
||||||
{
|
{
|
||||||
inputs,
|
pkgs,
|
||||||
lib,
|
lib,
|
||||||
providers,
|
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
|
||||||
{
|
{
|
||||||
providers.local = inputs.nixops4.modules.nixops4Provider.local;
|
|
||||||
|
|
||||||
resources.target = {
|
|
||||||
type = providers.local.exec;
|
|
||||||
imports = [ inputs.nixops4-nixos.modules.nixops4Resource.nixos ];
|
|
||||||
|
|
||||||
ssh = {
|
|
||||||
host = "target";
|
|
||||||
hostPublicKey = builtins.readFile ./target_host_key.pub;
|
|
||||||
};
|
|
||||||
|
|
||||||
nixpkgs = inputs.nixpkgs;
|
|
||||||
nixos.module =
|
|
||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
imports = [
|
||||||
./minimalTarget.nix
|
./minimalTarget.nix
|
||||||
(lib.modules.importJSON ./target-network.json)
|
(lib.modules.importJSON ./target-network.json)
|
||||||
];
|
];
|
||||||
nixpkgs.hostPlatform = "x86_64-linux";
|
nixpkgs.hostPlatform = "x86_64-linux";
|
||||||
environment.systemPackages = [ pkgs.cowsay ];
|
environment.systemPackages = [ pkgs.cowsay ];
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
{ inputs, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
nixops4Deployments.check-deployment-basic =
|
|
||||||
{ ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./deployment.nix
|
|
||||||
];
|
|
||||||
_module.args.inputs = inputs;
|
|
||||||
};
|
|
||||||
|
|
||||||
perSystem =
|
|
||||||
{ inputs', pkgs, ... }:
|
|
||||||
{
|
|
||||||
checks.deployment-basic = pkgs.callPackage ./nixosTest.nix {
|
|
||||||
nixops4-flake-in-a-bottle = inputs'.nixops4.packages.flake-in-a-bottle;
|
|
||||||
inherit inputs;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,15 +1,30 @@
|
||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
modulesPath,
|
modulesPath,
|
||||||
|
pkgs,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
let
|
||||||
|
tf = pkgs.callPackage ../../../launch/tf.nix { };
|
||||||
|
tfEnv = pkgs.callPackage ../../../launch/tf-env.nix { };
|
||||||
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
(modulesPath + "/profiles/qemu-guest.nix")
|
(modulesPath + "/profiles/qemu-guest.nix")
|
||||||
(modulesPath + "/../lib/testing/nixos-test-base.nix")
|
(modulesPath + "/../lib/testing/nixos-test-base.nix")
|
||||||
];
|
];
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
tf
|
||||||
|
tfEnv
|
||||||
|
pkgs.bash
|
||||||
|
pkgs.acl
|
||||||
|
pkgs.attr
|
||||||
|
pkgs.autoconf
|
||||||
|
pkgs.automake
|
||||||
|
pkgs.python3
|
||||||
|
];
|
||||||
|
|
||||||
## Test framework disables switching by default. That might be OK by itself,
|
## Test framework disables switching by default. That might be OK by itself,
|
||||||
## but we also use this config for getting the dependencies in
|
## but we also use this config for getting the dependencies in
|
||||||
## `deployer.system.extraDependencies`.
|
## `deployer.system.extraDependencies`.
|
||||||
|
|
|
@ -1,65 +1,114 @@
|
||||||
{
|
{
|
||||||
testers,
|
testers,
|
||||||
inputs,
|
|
||||||
runCommandNoCC,
|
|
||||||
nixops4-flake-in-a-bottle,
|
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
|
||||||
testers.runNixOSTest (
|
testers.runNixOSTest (
|
||||||
{
|
{
|
||||||
lib,
|
|
||||||
config,
|
config,
|
||||||
hostPkgs,
|
hostPkgs,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
vmSystem = config.node.pkgs.hostPlatform.system;
|
sources = import ../../../npins;
|
||||||
|
pkgs = hostPkgs;
|
||||||
pathToRoot = ../../..;
|
# dummyFile = hostPkgs.writeText "dummy" "";
|
||||||
pathFromRoot = "deployment/check/basic";
|
tf = pkgs.callPackage ../../../launch/tf.nix { };
|
||||||
deploymentName = "check-deployment-basic";
|
tfEnv = pkgs.callPackage ../../../launch/tf-env.nix { };
|
||||||
|
inherit (pkgs) lib;
|
||||||
## TODO: sanity check the existence of (pathToRoot + "/flake.nix")
|
inherit (import ../../../panel/env.nix { inherit lib pkgs; }) BIN_PATH;
|
||||||
## TODO: sanity check that (pathToRoot + "/${pathFromRoot}" == ./.)
|
tfVars = builtins.path {
|
||||||
|
name = "basic.tfvars";
|
||||||
## The whole repository, with the flake at its root.
|
path = ./basic.tfvars;
|
||||||
src = lib.fileset.toSource {
|
|
||||||
fileset = pathToRoot;
|
|
||||||
root = pathToRoot;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
## We will need to override some inputs by the empty flake, so we make one.
|
fakeMachine = pkgs.nixos [
|
||||||
emptyFlake = runCommandNoCC "empty-flake" { } ''
|
../basic/minimalTarget.nix
|
||||||
mkdir $out
|
../../../launch/options.nix
|
||||||
echo "{ outputs = { self }: {}; }" > $out/flake.nix
|
../../../launch/shared.nix
|
||||||
'';
|
../../../launch/garage.nix
|
||||||
|
../../../launch/mastodon.nix
|
||||||
|
# prevent issue about multiple services on same nginx port: Segmentation fault (core dumped) gixy $out; This can be caused by combining multiple incompatible services on the same hostname.
|
||||||
|
# ../../../launch/pixelfed.nix
|
||||||
|
# ../../../launch/peertube.nix
|
||||||
|
../../../infra/test-machines/test01
|
||||||
|
{
|
||||||
|
nix.nixPath = [ "/dummy/nix/path" ];
|
||||||
|
users.users.root.openssh.authorizedKeys.keys = [ "dummykey" ];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
terraform = {
|
||||||
|
domain = "fediversity.net";
|
||||||
|
hostname = "base";
|
||||||
|
initialUser = {
|
||||||
|
displayName = "Testy McTestface";
|
||||||
|
username = "test";
|
||||||
|
email = "test@test.com";
|
||||||
|
password = "testtest";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
targetNetworkJSON = hostPkgs.writeText "target-network.json" (
|
extraDependenciesFromMachine =
|
||||||
builtins.toJSON config.nodes.target.system.build.networkConfig
|
machine:
|
||||||
|
[
|
||||||
|
machine.system.build.toplevel.inputDerivation
|
||||||
|
machine.system.build.etc.inputDerivation
|
||||||
|
machine.system.build.etcBasedir.inputDerivation
|
||||||
|
machine.system.build.etcMetadataImage.inputDerivation
|
||||||
|
machine.system.build.extraUtils.inputDerivation
|
||||||
|
machine.system.path.inputDerivation
|
||||||
|
machine.system.build.setEnvironment.inputDerivation
|
||||||
|
machine.system.build.vm.inputDerivation
|
||||||
|
# machine.system.build.vmWithBootLoader.inputDerivation # The option `nodes.hello.virtualisation.vmVariantWithBootLoader._module.args.name' is defined multiple times while it's expected to be unique.
|
||||||
|
machine.system.build.bootStage1.inputDerivation
|
||||||
|
machine.system.build.bootStage2.inputDerivation
|
||||||
|
machine.system.modulesTree.inputDerivation
|
||||||
|
machine.system.build.binsh.inputDerivation
|
||||||
|
machine.system.build.initialRamdisk.inputDerivation
|
||||||
|
machine.system.build.initialRamdiskSecretAppender.inputDerivation
|
||||||
|
machine.system.build.installBootLoader.inputDerivation
|
||||||
|
machine.system.build.kernel.inputDerivation
|
||||||
|
machine.system.build.nixos-enter.inputDerivation
|
||||||
|
machine.system.build.nixos-generate-config.inputDerivation
|
||||||
|
machine.system.build.nixos-install.inputDerivation
|
||||||
|
machine.system.build.nixos-option.inputDerivation
|
||||||
|
machine.system.build.nixos-rebuild.inputDerivation
|
||||||
|
machine.system.build.separateActivationScript.inputDerivation
|
||||||
|
machine.system.build.uki.inputDerivation
|
||||||
|
# machine.system.outPath
|
||||||
|
]
|
||||||
|
++ machine.environment.systemPackages
|
||||||
|
++ lib.concatLists (
|
||||||
|
lib.mapAttrsToList (
|
||||||
|
_k: v: if v ? source.inputDerivation then [ v.source.inputDerivation ] else [ ]
|
||||||
|
) machine.environment.etc
|
||||||
);
|
);
|
||||||
|
inherit (config) targetMachines pathToRoot pathFromRoot;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
name = "deployment-basic";
|
name = "deployment-basic";
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
inputs.nixops4-nixos.modules.nixosTest.static
|
(import ../common/nixosTest.nix { inherit config lib hostPkgs; })
|
||||||
];
|
];
|
||||||
|
|
||||||
nodes = {
|
targetMachines = [
|
||||||
|
"hello"
|
||||||
|
"cowsay"
|
||||||
|
];
|
||||||
|
pathToRoot = ../../..;
|
||||||
|
pathFromRoot = "deployment/check/basic";
|
||||||
|
|
||||||
|
nodes =
|
||||||
|
{
|
||||||
deployer =
|
deployer =
|
||||||
{ pkgs, nodes, ... }:
|
{ pkgs, nodes, ... }:
|
||||||
{
|
{
|
||||||
environment.systemPackages = [
|
|
||||||
inputs.nixops4.packages.${vmSystem}.default
|
|
||||||
];
|
|
||||||
|
|
||||||
virtualisation = {
|
virtualisation = {
|
||||||
## Memory use is expected to be dominated by the NixOS evaluation,
|
memorySize = 32 * 1024; # FIXME: trim down - maybe make it an option
|
||||||
## which happens on the deployer.
|
diskSize = 50 * 1024; # FIXME: trim down - maybe make it an option
|
||||||
memorySize = 4096;
|
cores = 8; # FIXME: trim down - maybe make it an option
|
||||||
diskSize = 10 * 1024;
|
|
||||||
cores = 2;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
nix.settings = {
|
nix.settings = {
|
||||||
|
@ -68,94 +117,103 @@ testers.runNixOSTest (
|
||||||
connect-timeout = 1;
|
connect-timeout = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
system.extraDependencies =
|
system.extraDependencies = [
|
||||||
[
|
(pkgs.closureInfo {
|
||||||
"${inputs.flake-parts}"
|
rootPaths = (
|
||||||
"${inputs.flake-parts.inputs.nixpkgs-lib}"
|
lib.attrValues sources
|
||||||
"${inputs.nixops4}"
|
++ [
|
||||||
"${inputs.nixops4-nixos}"
|
|
||||||
"${inputs.nixpkgs}"
|
|
||||||
|
|
||||||
pkgs.stdenv
|
pkgs.stdenv
|
||||||
pkgs.stdenvNoCC
|
pkgs.stdenvNoCC
|
||||||
|
# pkgs
|
||||||
pkgs.cowsay
|
tf
|
||||||
pkgs.cowsay.inputDerivation # NOTE: Crucial!!!
|
tf.inputDerivation
|
||||||
|
tfEnv
|
||||||
## Some derivations will be different compared to target's initial
|
tfEnv.inputDerivation
|
||||||
## state, so we'll need to be able to build something similar.
|
tfVars
|
||||||
## Generally the derivation inputs aren't that different, so we
|
pkgs.bash
|
||||||
## use the initial state of the target as a base.
|
pkgs.bash.inputDerivation
|
||||||
nodes.target.system.build.toplevel.inputDerivation
|
pkgs.acl
|
||||||
nodes.target.system.build.etc.inputDerivation
|
pkgs.acl.inputDerivation
|
||||||
nodes.target.system.path.inputDerivation
|
pkgs.attr
|
||||||
nodes.target.system.build.bootStage1.inputDerivation
|
pkgs.attr.inputDerivation
|
||||||
nodes.target.system.build.bootStage2.inputDerivation
|
pkgs.autoconf
|
||||||
|
pkgs.autoconf.inputDerivation
|
||||||
|
pkgs.automake
|
||||||
|
pkgs.automake.inputDerivation
|
||||||
|
pkgs.python3
|
||||||
|
pkgs.python3.inputDerivation
|
||||||
|
pkgs.python3Packages.mdit-py-plugins
|
||||||
|
pkgs.python3Packages.mdit-py-plugins.inputDerivation
|
||||||
|
pkgs.python3Packages.markdown-it-py
|
||||||
|
pkgs.python3Packages.markdown-it-py.inputDerivation
|
||||||
|
pkgs.peertube
|
||||||
|
pkgs.peertube.inputDerivation
|
||||||
|
pkgs.gixy
|
||||||
|
pkgs.gixy.inputDerivation
|
||||||
|
pkgs.postgresql_15
|
||||||
|
pkgs.mtools
|
||||||
|
pkgs.mtools.inputDerivation
|
||||||
|
pkgs.lkl
|
||||||
|
pkgs.lkl.inputDerivation
|
||||||
|
pkgs.nftables
|
||||||
|
pkgs.nftables.inputDerivation
|
||||||
|
pkgs.musl
|
||||||
|
pkgs.musl.inputDerivation
|
||||||
|
pkgs.w3m # why in the world?!
|
||||||
|
pkgs.w3m.inputDerivation
|
||||||
|
pkgs.byacc
|
||||||
|
pkgs.byacc.inputDerivation
|
||||||
|
pkgs.openssh
|
||||||
|
pkgs.openssh.inputDerivation
|
||||||
|
pkgs.curl
|
||||||
|
pkgs.curl.inputDerivation
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.coreutils.inputDerivation
|
||||||
|
pkgs.krb5
|
||||||
|
pkgs.krb5.inputDerivation
|
||||||
|
pkgs.libssh2
|
||||||
|
pkgs.libssh2.inputDerivation
|
||||||
|
pkgs.nghttp2
|
||||||
|
pkgs.nghttp2.inputDerivation
|
||||||
|
pkgs.openssl
|
||||||
|
pkgs.openssl.inputDerivation
|
||||||
]
|
]
|
||||||
++ lib.concatLists (
|
++ lib.concatLists (
|
||||||
lib.mapAttrsToList (
|
map extraDependenciesFromMachine (map (tm: nodes.${tm}) targetMachines ++ [ fakeMachine.config ])
|
||||||
_k: v: if v ? source.inputDerivation then [ v.source.inputDerivation ] else [ ]
|
)
|
||||||
) nodes.target.environment.etc
|
|
||||||
);
|
);
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
environment.systemPackages = [
|
||||||
|
tf
|
||||||
|
tfEnv
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
target.imports = [ ./minimalTarget.nix ];
|
}
|
||||||
};
|
// lib.genAttrs targetMachines (_: {
|
||||||
|
imports = [ ../basic/minimalTarget.nix ];
|
||||||
testScript = ''
|
users.users.root.openssh.authorizedKeys.keyFiles = [
|
||||||
start_all()
|
(pathToRoot + "/${pathFromRoot}/deployer.pub")
|
||||||
|
];
|
||||||
target.wait_for_unit("multi-user.target")
|
});
|
||||||
deployer.wait_for_unit("multi-user.target")
|
|
||||||
|
|
||||||
with subtest("Unpacking"):
|
|
||||||
deployer.succeed("cp -r --no-preserve=mode ${src} work")
|
|
||||||
|
|
||||||
with subtest("Configure the network"):
|
|
||||||
deployer.copy_from_host("${targetNetworkJSON}", "/root/target-network.json")
|
|
||||||
deployer.succeed("mv /root/target-network.json work/${pathFromRoot}/target-network.json")
|
|
||||||
|
|
||||||
with subtest("Configure the deployer key"):
|
|
||||||
deployer.succeed("""mkdir -p ~/.ssh && ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa""")
|
|
||||||
deployer_key = deployer.succeed("cat ~/.ssh/id_rsa.pub").strip()
|
|
||||||
deployer.succeed(f"echo '{deployer_key}' > work/${pathFromRoot}/deployer.pub")
|
|
||||||
target.succeed(f"mkdir -p /root/.ssh && echo '{deployer_key}' >> /root/.ssh/authorized_keys")
|
|
||||||
|
|
||||||
with subtest("Configure the target host key"):
|
|
||||||
target_host_key = target.succeed("ssh-keyscan target | grep -v '^#' | cut -f 2- -d ' ' | head -n 1")
|
|
||||||
deployer.succeed(f"echo '{target_host_key}' > work/${pathFromRoot}/target_host_key.pub")
|
|
||||||
|
|
||||||
## NOTE: This is super slow. It could probably be optimised in Nix, for
|
|
||||||
## instance by allowing to grab things directly from the host's store.
|
|
||||||
with subtest("Override the lock"):
|
|
||||||
deployer.succeed("""
|
|
||||||
cd work
|
|
||||||
nix flake lock --extra-experimental-features 'flakes nix-command' \
|
|
||||||
--offline -v \
|
|
||||||
--override-input flake-parts ${inputs.flake-parts} \
|
|
||||||
--override-input nixops4 ${nixops4-flake-in-a-bottle} \
|
|
||||||
\
|
|
||||||
--override-input nixops4-nixos ${inputs.nixops4-nixos} \
|
|
||||||
--override-input nixops4-nixos/flake-parts ${inputs.nixops4-nixos.inputs.flake-parts} \
|
|
||||||
--override-input nixops4-nixos/flake-parts/nixpkgs-lib ${inputs.nixops4-nixos.inputs.flake-parts.inputs.nixpkgs-lib} \
|
|
||||||
--override-input nixops4-nixos/nixops4-nixos ${emptyFlake} \
|
|
||||||
--override-input nixops4-nixos/nixpkgs ${inputs.nixops4-nixos.inputs.nixpkgs} \
|
|
||||||
--override-input nixops4-nixos/nixops4 ${nixops4-flake-in-a-bottle} \
|
|
||||||
--override-input nixops4-nixos/git-hooks-nix ${emptyFlake} \
|
|
||||||
\
|
|
||||||
--override-input nixpkgs ${inputs.nixpkgs} \
|
|
||||||
--override-input git-hooks ${inputs.git-hooks} \
|
|
||||||
;
|
|
||||||
""")
|
|
||||||
|
|
||||||
|
extraTestScript = ''
|
||||||
with subtest("Check the status before deployment"):
|
with subtest("Check the status before deployment"):
|
||||||
target.fail("cowsay hi 1>&2")
|
hello.fail("hello 1>&2")
|
||||||
|
cowsay.fail("cowsay 1>&2")
|
||||||
|
|
||||||
|
with subtest("Validate config"):
|
||||||
|
deployer.wait_for_unit("multi-user.target")
|
||||||
|
deployer.succeed("${lib.getExe tf} -chdir='${tfEnv}/launch' validate")
|
||||||
|
|
||||||
with subtest("Run the deployment"):
|
with subtest("Run the deployment"):
|
||||||
deployer.succeed("cd work && nixops4 apply ${deploymentName} --show-trace --no-interactive")
|
deployer.succeed("PATH=${BIN_PATH} ${lib.getExe tf} -chdir='${tfEnv}/launch' apply --auto-approve -lock=false -parallelism=1 -var-file='${tfVars}' >&2")
|
||||||
|
|
||||||
with subtest("Check the deployment"):
|
with subtest("Check the deployment"):
|
||||||
target.succeed("cowsay hi 1>&2")
|
hello.succeed("hello 1>&2")
|
||||||
|
cowsay.succeed("cowsay hi 1>&2")
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
163
deployment/check/common/nixosTest.nix
Normal file
163
deployment/check/common/nixosTest.nix
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
hostPkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
sources = import ../../../npins;
|
||||||
|
inherit (builtins)
|
||||||
|
filter
|
||||||
|
;
|
||||||
|
inherit (lib)
|
||||||
|
fileset
|
||||||
|
mkOption
|
||||||
|
genAttrs
|
||||||
|
concatLists
|
||||||
|
attrNames
|
||||||
|
;
|
||||||
|
|
||||||
|
## Helpers to map over target machines and produce an attrset, a list, or a
|
||||||
|
## multiline string suitable for use in a Python script.
|
||||||
|
# forAllTargetMachines = lib.genAttrs config.targetMachines;
|
||||||
|
# forAllTargetMachines' = f: map f config.targetMachines;
|
||||||
|
forConcat = xs: f: builtins.concatStringsSep "\n" (map f xs);
|
||||||
|
|
||||||
|
inherit (config) targetMachines pathToRoot pathFromRoot;
|
||||||
|
|
||||||
|
## The whole repository.
|
||||||
|
## FIXME: We could probably have fileset be the union of ./. with flake.nix
|
||||||
|
## and flake.lock - I doubt we need anything else.
|
||||||
|
src = fileset.toSource {
|
||||||
|
fileset = config.pathToRoot;
|
||||||
|
root = config.pathToRoot;
|
||||||
|
};
|
||||||
|
|
||||||
|
## Some derivations will be different compared to target's initial state, so
|
||||||
|
## we'll need to be able to build something similar. Generally the derivation
|
||||||
|
## inputs aren't that different, so we use the initial state of the target as
|
||||||
|
## a base.
|
||||||
|
extraDependenciesFromMachine =
|
||||||
|
machine:
|
||||||
|
[
|
||||||
|
machine.system.build.toplevel.inputDerivation
|
||||||
|
machine.system.build.etc.inputDerivation
|
||||||
|
machine.system.build.etcBasedir.inputDerivation
|
||||||
|
machine.system.build.etcMetadataImage.inputDerivation
|
||||||
|
machine.system.build.extraUtils.inputDerivation
|
||||||
|
machine.system.path.inputDerivation
|
||||||
|
machine.system.build.setEnvironment.inputDerivation
|
||||||
|
machine.system.build.vm.inputDerivation
|
||||||
|
# machine.system.build.vmWithBootLoader.inputDerivation
|
||||||
|
machine.system.build.bootStage1.inputDerivation
|
||||||
|
machine.system.build.bootStage2.inputDerivation
|
||||||
|
]
|
||||||
|
++ concatLists (
|
||||||
|
lib.mapAttrsToList (
|
||||||
|
_k: v: if v ? source.inputDerivation then [ v.source.inputDerivation ] else [ ]
|
||||||
|
) machine.environment.etc
|
||||||
|
);
|
||||||
|
|
||||||
|
allNodesButFake = filter (m: m != "fake") (attrNames config.nodes);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
targetMachines = mkOption { };
|
||||||
|
|
||||||
|
pathToRoot = mkOption { };
|
||||||
|
## TODO: sanity check that (pathToRoot + "/${pathFromRoot}" == ./.)
|
||||||
|
pathFromRoot = mkOption { };
|
||||||
|
|
||||||
|
## FIXME: I wish I could just use `testScript` but with something like
|
||||||
|
## `mkOrder` to put this module's string before something else.
|
||||||
|
extraTestScript = mkOption { };
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
nodes =
|
||||||
|
{
|
||||||
|
deployer =
|
||||||
|
{ pkgs, nodes, ... }:
|
||||||
|
{
|
||||||
|
virtualisation = {
|
||||||
|
## Memory use is expected to be dominated by the NixOS evaluation,
|
||||||
|
## which happens on the deployer.
|
||||||
|
memorySize = 32 * 1024; # FIXME: trim down - maybe make it an option
|
||||||
|
diskSize = 50 * 1024; # FIXME: trim down - maybe make it an option
|
||||||
|
cores = 8; # FIXME: trim down - maybe make it an option
|
||||||
|
};
|
||||||
|
|
||||||
|
nix.settings = {
|
||||||
|
substituters = lib.mkForce [ ];
|
||||||
|
hashed-mirrors = null;
|
||||||
|
connect-timeout = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
system.extraDependencies =
|
||||||
|
lib.attrValues sources
|
||||||
|
++ [
|
||||||
|
# pkgs
|
||||||
|
pkgs.stdenv
|
||||||
|
pkgs.stdenvNoCC
|
||||||
|
]
|
||||||
|
++ concatLists (map (tm: extraDependenciesFromMachine nodes.${tm}) (targetMachines ++ [ "fake" ]));
|
||||||
|
};
|
||||||
|
|
||||||
|
## A “fake” node that can will not be started or used in the test, but
|
||||||
|
## whose configuration will be dumped in the deployer's extra
|
||||||
|
## dependencies. This is an indirect (and more pleasant) way of giving
|
||||||
|
## the deployer the right derivations to build the desired services.
|
||||||
|
fake.imports = [ ../basic/minimalTarget.nix ];
|
||||||
|
}
|
||||||
|
// genAttrs targetMachines (_: {
|
||||||
|
imports = [ ../basic/minimalTarget.nix ];
|
||||||
|
users.users.root.openssh.authorizedKeys.keyFiles = [
|
||||||
|
(pathToRoot + "/${pathFromRoot}/deployer.pub")
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
${forConcat allNodesButFake (n: ''
|
||||||
|
${n}.start()
|
||||||
|
'')}
|
||||||
|
|
||||||
|
${forConcat allNodesButFake (n: ''
|
||||||
|
${n}.wait_for_unit("multi-user.target")
|
||||||
|
'')}
|
||||||
|
|
||||||
|
with subtest("Unpacking"):
|
||||||
|
deployer.succeed("cp -r --no-preserve=mode ${src} work")
|
||||||
|
|
||||||
|
with subtest("Configure the network"):
|
||||||
|
${forConcat targetMachines (
|
||||||
|
tm:
|
||||||
|
let
|
||||||
|
targetNetworkJSON = hostPkgs.writeText "target-network.json" (
|
||||||
|
builtins.toJSON config.nodes.${tm}.system.build.networkConfig
|
||||||
|
);
|
||||||
|
in
|
||||||
|
''
|
||||||
|
deployer.copy_from_host("${targetNetworkJSON}", "/root/target-network.json")
|
||||||
|
deployer.succeed("mv /root/target-network.json work/${pathFromRoot}/${tm}-network.json")
|
||||||
|
''
|
||||||
|
)}
|
||||||
|
|
||||||
|
with subtest("Configure the deployer key"):
|
||||||
|
deployer.succeed("""mkdir -p ~/.ssh && ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa""")
|
||||||
|
deployer_key = deployer.succeed("cat ~/.ssh/id_rsa.pub").strip()
|
||||||
|
deployer.succeed(f"echo '{deployer_key}' > work/${pathFromRoot}/deployer.pub")
|
||||||
|
${forConcat targetMachines (tm: ''
|
||||||
|
${tm}.succeed(f"mkdir -p /root/.ssh && echo '{deployer_key}' >> /root/.ssh/authorized_keys")
|
||||||
|
'')}
|
||||||
|
|
||||||
|
with subtest("Configure the target host key"):
|
||||||
|
${forConcat targetMachines (tm: ''
|
||||||
|
host_key = ${tm}.succeed("ssh-keyscan ${tm} | grep -v '^#' | cut -f 2- -d ' ' | head -n 1")
|
||||||
|
deployer.succeed(f"echo '{host_key}' > work/${pathFromRoot}/${tm}_host_key.pub")
|
||||||
|
'')}
|
||||||
|
|
||||||
|
${config.extraTestScript}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
7
deployment/check/default.nix
Normal file
7
deployment/check/default.nix
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
basic = pkgs.callPackage ./basic/nixosTest.nix { };
|
||||||
|
}
|
|
@ -1,194 +1,16 @@
|
||||||
## `makeMakeDeployment` -- Function to help hosting providers make a
|
|
||||||
## `makeDeployment` function.
|
|
||||||
##
|
|
||||||
## https://factoryfactoryfactory.net/
|
|
||||||
|
|
||||||
## Generic utilities used in this function, eg. nixpkgs, NixOps4 providers, etc.
|
|
||||||
## REVIEW: We should maybe be more specific than just `inputs`.
|
|
||||||
{
|
{
|
||||||
lib,
|
system ? builtins.currentSystem,
|
||||||
nixops4,
|
sources ? import ../npins,
|
||||||
nixops4-nixos,
|
pkgs ? import sources.nixpkgs { inherit system; },
|
||||||
fediversity,
|
|
||||||
}:
|
}:
|
||||||
|
|
||||||
## Information on the hosting provider's infrastructure. This is where we inform
|
|
||||||
## this function of where it can find eg. Proxmox.
|
|
||||||
{
|
{
|
||||||
## Four NixOS configuration resource modules for four services. Those are VMs
|
tests = import ./check { inherit pkgs; };
|
||||||
## that are already deployed and on which we will push our configurations.
|
|
||||||
##
|
|
||||||
## - Ultimately, we just want a pool of VMs, or even just a Proxmox.
|
|
||||||
## - Each machine is flagged for a certain use case until we control DNS.
|
|
||||||
garageConfigurationResource,
|
|
||||||
mastodonConfigurationResource,
|
|
||||||
peertubeConfigurationResource,
|
|
||||||
pixelfedConfigurationResource,
|
|
||||||
}:
|
|
||||||
|
|
||||||
## From the hosting provider's perspective, the function is meant to be
|
# re-export inputs so they can be overridden granularly
|
||||||
## partially applied only until here.
|
# (they can't be accessed from the outside any other way)
|
||||||
|
inherit
|
||||||
## Information on the specific deployment that we request. This is the
|
sources
|
||||||
## information coming from the FediPanel.
|
system
|
||||||
##
|
pkgs
|
||||||
## FIXME: lock step the interface with the definitions in the FediPanel
|
;
|
||||||
panelConfig:
|
|
||||||
|
|
||||||
let
|
|
||||||
inherit (lib) mkIf;
|
|
||||||
|
|
||||||
in
|
|
||||||
|
|
||||||
## Regular arguments of a NixOps4 deployment module.
|
|
||||||
{ providers, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
options = {
|
|
||||||
deployment = lib.mkOption {
|
|
||||||
description = ''
|
|
||||||
Configuration to be deployed
|
|
||||||
'';
|
|
||||||
# XXX(@fricklerhandwerk):
|
|
||||||
# misusing this will produce obscure errors that will be truncated by NixOps4
|
|
||||||
type = lib.types.submodule ./options.nix;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
providers = { inherit (nixops4.modules.nixops4Provider) local; };
|
|
||||||
|
|
||||||
resources =
|
|
||||||
let
|
|
||||||
## NOTE: All of these secrets are publicly available in this source file
|
|
||||||
## and will end up in the Nix store. We don't care as they are only ever
|
|
||||||
## used for testing anyway.
|
|
||||||
##
|
|
||||||
## FIXME: Generate and store in NixOps4's state.
|
|
||||||
mastodonS3KeyConfig =
|
|
||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GK3515373e4c851ebaad366558";
|
|
||||||
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "7d37d093435a41f2aab8f13c19ba067d9776c90215f56614adad6ece597dbb34";
|
|
||||||
};
|
|
||||||
peertubeS3KeyConfig =
|
|
||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GK1f9feea9960f6f95ff404c9b";
|
|
||||||
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "7295c4201966a02c2c3d25b5cea4a5ff782966a2415e3a196f91924631191395";
|
|
||||||
};
|
|
||||||
pixelfedS3KeyConfig =
|
|
||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GKb5615457d44214411e673b7b";
|
|
||||||
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "5be6799a88ca9b9d813d1a806b64f15efa49482dbe15339ddfaf7f19cf434987";
|
|
||||||
};
|
|
||||||
|
|
||||||
makeConfigurationResource = resourceModule: config: {
|
|
||||||
type = providers.local.exec;
|
|
||||||
imports = [
|
|
||||||
nixops4-nixos.modules.nixops4Resource.nixos
|
|
||||||
resourceModule
|
|
||||||
|
|
||||||
{
|
|
||||||
## NOTE: With NixOps4, there are several levels and all of them live
|
|
||||||
## in the NixOS module system:
|
|
||||||
##
|
|
||||||
## 1. Each NixOps4 deployment is a module.
|
|
||||||
## 2. Each NixOps4 resource is a module. This very comment is
|
|
||||||
## inside an attrset imported as a module in a resource.
|
|
||||||
## 3. Each NixOps4 'configuration' resource contains an attribute
|
|
||||||
## 'nixos.module', itself a NixOS configuration module.
|
|
||||||
nixos.module =
|
|
||||||
{ ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
config
|
|
||||||
fediversity
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
in
|
|
||||||
|
|
||||||
{
|
|
||||||
garage-configuration = makeConfigurationResource garageConfigurationResource (
|
|
||||||
{ pkgs, ... }:
|
|
||||||
mkIf (panelConfig.mastodon.enable || panelConfig.peertube.enable || panelConfig.pixelfed.enable) {
|
|
||||||
fediversity = {
|
|
||||||
inherit (panelConfig) domain;
|
|
||||||
garage.enable = true;
|
|
||||||
pixelfed = pixelfedS3KeyConfig { inherit pkgs; };
|
|
||||||
mastodon = mastodonS3KeyConfig { inherit pkgs; };
|
|
||||||
peertube = peertubeS3KeyConfig { inherit pkgs; };
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
mastodon-configuration = makeConfigurationResource mastodonConfigurationResource (
|
|
||||||
{ pkgs, ... }:
|
|
||||||
mkIf panelConfig.mastodon.enable {
|
|
||||||
fediversity = {
|
|
||||||
inherit (panelConfig) domain;
|
|
||||||
temp.initialUser = {
|
|
||||||
inherit (panelConfig.initialUser) username email displayName;
|
|
||||||
# FIXME: disgusting, but nvm, this is going to be replaced by
|
|
||||||
# proper central authentication at some point
|
|
||||||
passwordFile = pkgs.writeText "password" panelConfig.initialUser.password;
|
|
||||||
};
|
|
||||||
|
|
||||||
mastodon = mastodonS3KeyConfig { inherit pkgs; } // {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
temp.cores = 1; # FIXME: should come from NixOps4 eventually
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
peertube-configuration = makeConfigurationResource peertubeConfigurationResource (
|
|
||||||
{ pkgs, ... }:
|
|
||||||
mkIf panelConfig.peertube.enable {
|
|
||||||
fediversity = {
|
|
||||||
inherit (panelConfig) domain;
|
|
||||||
temp.initialUser = {
|
|
||||||
inherit (panelConfig.initialUser) username email displayName;
|
|
||||||
# FIXME: disgusting, but nvm, this is going to be replaced by
|
|
||||||
# proper central authentication at some point
|
|
||||||
passwordFile = pkgs.writeText "password" panelConfig.initialUser.password;
|
|
||||||
};
|
|
||||||
|
|
||||||
peertube = peertubeS3KeyConfig { inherit pkgs; } // {
|
|
||||||
enable = true;
|
|
||||||
## NOTE: Only ever used for testing anyway.
|
|
||||||
##
|
|
||||||
## FIXME: Generate and store in NixOps4's state.
|
|
||||||
secretsFile = pkgs.writeText "secret" "574e093907d1157ac0f8e760a6deb1035402003af5763135bae9cbd6abe32b24";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
pixelfed-configuration = makeConfigurationResource pixelfedConfigurationResource (
|
|
||||||
{ pkgs, ... }:
|
|
||||||
mkIf panelConfig.pixelfed.enable {
|
|
||||||
fediversity = {
|
|
||||||
inherit (panelConfig) domain;
|
|
||||||
temp.initialUser = {
|
|
||||||
inherit (panelConfig.initialUser) username email displayName;
|
|
||||||
# FIXME: disgusting, but nvm, this is going to be replaced by
|
|
||||||
# proper central authentication at some point
|
|
||||||
passwordFile = pkgs.writeText "password" panelConfig.initialUser.password;
|
|
||||||
};
|
|
||||||
|
|
||||||
pixelfed = pixelfedS3KeyConfig { inherit pkgs; } // {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
84
flake.lock
generated
84
flake.lock
generated
|
@ -201,6 +201,24 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flake-utils_2": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems_3"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1710146030,
|
||||||
|
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"git-hooks": {
|
"git-hooks": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
|
@ -323,6 +341,47 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"home-manager": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"agenix",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1703113217,
|
||||||
|
"narHash": "sha256-7ulcXOk63TIT2lVDSExj7XzFx09LpdSAPtvgtM7yQPE=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"rev": "3bfaacf46133c037bb356193bd2f1765d9dc82c1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"home-manager_2": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1743860185,
|
||||||
|
"narHash": "sha256-TkhfJ+vH+iGxLQL6RJLObMmldAQpysVJ+p1WnnKyIeQ=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"rev": "b5e29565131802cc8adee7dccede794226da8614",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"mk-naked-shell": {
|
"mk-naked-shell": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
|
@ -341,9 +400,9 @@
|
||||||
},
|
},
|
||||||
"nix": {
|
"nix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat_3",
|
"flake-compat": "flake-compat_2",
|
||||||
"flake-parts": "flake-parts_4",
|
"flake-parts": "flake-parts_3",
|
||||||
"git-hooks-nix": "git-hooks-nix_2",
|
"git-hooks-nix": "git-hooks-nix",
|
||||||
"nixfmt": "nixfmt",
|
"nixfmt": "nixfmt",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixops4-nixos",
|
"nixops4-nixos",
|
||||||
|
@ -414,6 +473,24 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixfmt_2": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1736283758,
|
||||||
|
"narHash": "sha256-hrKhUp2V2fk/dvzTTHFqvtOg000G1e+jyIam+D4XqhA=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixfmt",
|
||||||
|
"rev": "8d4bd690c247004d90d8554f0b746b1231fe2436",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixfmt",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixops4": {
|
"nixops4": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-parts": "flake-parts_3",
|
"flake-parts": "flake-parts_3",
|
||||||
|
@ -682,6 +759,7 @@
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts",
|
||||||
"git-hooks": "git-hooks",
|
"git-hooks": "git-hooks",
|
||||||
|
"home-manager": "home-manager_2",
|
||||||
"nixops4": [
|
"nixops4": [
|
||||||
"nixops4-nixos",
|
"nixops4-nixos",
|
||||||
"nixops4"
|
"nixops4"
|
||||||
|
|
|
@ -42,7 +42,10 @@
|
||||||
pre-commit.settings.hooks =
|
pre-commit.settings.hooks =
|
||||||
let
|
let
|
||||||
## Add a directory here if pre-commit hooks shouldn't apply to it.
|
## Add a directory here if pre-commit hooks shouldn't apply to it.
|
||||||
optout = [ "npins" ];
|
optout = [
|
||||||
|
"npins"
|
||||||
|
"launch/.terraform"
|
||||||
|
];
|
||||||
excludes = map (dir: "^${dir}/") optout;
|
excludes = map (dir: "^${dir}/") optout;
|
||||||
addExcludes = lib.mapAttrs (_: c: c // { inherit excludes; });
|
addExcludes = lib.mapAttrs (_: c: c // { inherit excludes; });
|
||||||
in
|
in
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) mkDefault;
|
inherit (lib) mkDefault;
|
||||||
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
|
|
|
@ -37,11 +37,11 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
defaultGateway = {
|
defaultGateway = lib.mkIf (config.fediversityVm ? ipv4) {
|
||||||
address = config.fediversityVm.ipv4.gateway;
|
address = config.fediversityVm.ipv4.gateway;
|
||||||
interface = "eth0";
|
interface = "eth0";
|
||||||
};
|
};
|
||||||
defaultGateway6 = {
|
defaultGateway6 = lib.mkIf (config.fediversityVm ? ipv6) {
|
||||||
address = config.fediversityVm.ipv6.gateway;
|
address = config.fediversityVm.ipv6.gateway;
|
||||||
interface = "eth0";
|
interface = "eth0";
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,12 @@ let
|
||||||
inherit (lib.attrsets) concatMapAttrs optionalAttrs;
|
inherit (lib.attrsets) concatMapAttrs optionalAttrs;
|
||||||
inherit (lib.strings) removeSuffix;
|
inherit (lib.strings) removeSuffix;
|
||||||
sources = import ../../npins;
|
sources = import ../../npins;
|
||||||
inherit (sources) nixpkgs agenix disko;
|
inherit (sources)
|
||||||
|
nixpkgs
|
||||||
|
agenix
|
||||||
|
disko
|
||||||
|
home-manager
|
||||||
|
;
|
||||||
|
|
||||||
secretsPrefix = ../../secrets;
|
secretsPrefix = ../../secrets;
|
||||||
secrets = import (secretsPrefix + "/secrets.nix");
|
secrets = import (secretsPrefix + "/secrets.nix");
|
||||||
|
@ -33,8 +38,9 @@ in
|
||||||
## should go into the `./nixos` subdirectory.
|
## should go into the `./nixos` subdirectory.
|
||||||
nixos.module = {
|
nixos.module = {
|
||||||
imports = [
|
imports = [
|
||||||
(import "${agenix}/modules/age.nix")
|
"${agenix}/modules/age.nix"
|
||||||
(import "${disko}/module.nix")
|
"${disko}/module.nix"
|
||||||
|
"${home-manager}/nixos"
|
||||||
./options.nix
|
./options.nix
|
||||||
./nixos
|
./nixos
|
||||||
];
|
];
|
||||||
|
@ -48,9 +54,9 @@ in
|
||||||
## as `age.secrets.<name>.file`.
|
## as `age.secrets.<name>.file`.
|
||||||
age.secrets = concatMapAttrs (
|
age.secrets = concatMapAttrs (
|
||||||
name: secret:
|
name: secret:
|
||||||
optionalAttrs (elem config.fediversityVm.hostPublicKey secret.publicKeys) ({
|
optionalAttrs (elem config.fediversityVm.hostPublicKey secret.publicKeys) {
|
||||||
${removeSuffix ".age" name}.file = secretsPrefix + "/${name}";
|
${removeSuffix ".age" name}.file = secretsPrefix + "/${name}";
|
||||||
})
|
}
|
||||||
) secrets;
|
) secrets;
|
||||||
|
|
||||||
## FIXME: Remove direct root authentication once the NixOps4 NixOS provider
|
## FIXME: Remove direct root authentication once the NixOps4 NixOS provider
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
}:
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (builtins) readDir readFile fromJSON;
|
inherit (builtins) readDir;
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
attrNames
|
attrNames
|
||||||
mkOption
|
mkOption
|
||||||
|
@ -15,32 +15,16 @@ let
|
||||||
inherit (lib.attrsets) genAttrs;
|
inherit (lib.attrsets) genAttrs;
|
||||||
sources = import ../../npins;
|
sources = import ../../npins;
|
||||||
|
|
||||||
## Given a machine's name and whether it is a test VM, make a resource module,
|
## Given a machine's name, make a resource module,
|
||||||
## except for its missing provider. (Depending on the use of that resource, we
|
## except for its missing provider. (Depending on the use of that resource, we
|
||||||
## will provide a different one.)
|
## will provide a different one.)
|
||||||
makeResourceModule =
|
makeResourceModule =
|
||||||
{ vmName, isTestVm }:
|
{ vmName }:
|
||||||
{
|
{
|
||||||
imports =
|
imports = [
|
||||||
[
|
|
||||||
./common/resource.nix
|
./common/resource.nix
|
||||||
]
|
|
||||||
++ (
|
|
||||||
if isTestVm then
|
|
||||||
[
|
|
||||||
./test-machines/${vmName}
|
|
||||||
{
|
|
||||||
nixos.module.users.users.root.openssh.authorizedKeys.keys = [
|
|
||||||
# allow our panel vm access to the test machines
|
|
||||||
(import ../keys).panel
|
|
||||||
];
|
|
||||||
}
|
|
||||||
]
|
|
||||||
else
|
|
||||||
[
|
|
||||||
./machines/${vmName}
|
./machines/${vmName}
|
||||||
]
|
];
|
||||||
);
|
|
||||||
fediversityVm.name = vmName;
|
fediversityVm.name = vmName;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,42 +41,12 @@ let
|
||||||
inputs.nixops4-nixos.modules.nixops4Resource.nixos
|
inputs.nixops4-nixos.modules.nixops4Resource.nixos
|
||||||
(makeResourceModule {
|
(makeResourceModule {
|
||||||
inherit vmName;
|
inherit vmName;
|
||||||
isTestVm = false;
|
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
makeDeployment' = vmName: makeDeployment [ vmName ];
|
makeDeployment' = vmName: makeDeployment [ vmName ];
|
||||||
|
|
||||||
## Given an attrset of test configurations (key = test machine name, value =
|
|
||||||
## NixOS configuration module), make a deployment with those machines'
|
|
||||||
## configurations as resources.
|
|
||||||
makeTestDeployment =
|
|
||||||
(import ../deployment)
|
|
||||||
{
|
|
||||||
inherit lib;
|
|
||||||
inherit (inputs) nixops4 nixops4-nixos;
|
|
||||||
fediversity = import ../services/fediversity;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
garageConfigurationResource = makeResourceModule {
|
|
||||||
vmName = "test01";
|
|
||||||
isTestVm = true;
|
|
||||||
};
|
|
||||||
mastodonConfigurationResource = makeResourceModule {
|
|
||||||
vmName = "test06"; # somehow `test02` has a problem - use test06 instead
|
|
||||||
isTestVm = true;
|
|
||||||
};
|
|
||||||
peertubeConfigurationResource = makeResourceModule {
|
|
||||||
vmName = "test05";
|
|
||||||
isTestVm = true;
|
|
||||||
};
|
|
||||||
pixelfedConfigurationResource = makeResourceModule {
|
|
||||||
vmName = "test04";
|
|
||||||
isTestVm = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
nixops4ResourceNixosMockOptions = {
|
nixops4ResourceNixosMockOptions = {
|
||||||
## NOTE: We allow the use of a few options from
|
## NOTE: We allow the use of a few options from
|
||||||
## `nixops4-nixos.modules.nixops4Resource.nixos` such that we can
|
## `nixops4-nixos.modules.nixops4Resource.nixos` such that we can
|
||||||
|
@ -119,18 +73,18 @@ let
|
||||||
|
|
||||||
## Given a VM name, make a NixOS configuration for this machine.
|
## Given a VM name, make a NixOS configuration for this machine.
|
||||||
makeConfiguration =
|
makeConfiguration =
|
||||||
isTestVm: vmName:
|
vmName:
|
||||||
let
|
let
|
||||||
inherit (sources) nixpkgs;
|
inherit (sources) nixpkgs;
|
||||||
in
|
in
|
||||||
import "${nixpkgs}/nixos" {
|
import "${nixpkgs}/nixos" {
|
||||||
modules = [
|
modules = [
|
||||||
(makeResourceConfig { inherit vmName isTestVm; }).nixos.module
|
(makeResourceConfig { inherit vmName; }).nixos.module
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
makeVmOptions = isTestVm: vmName: {
|
makeVmOptions = vmName: {
|
||||||
inherit ((makeResourceConfig { inherit vmName isTestVm; }).fediversityVm)
|
inherit ((makeResourceConfig { inherit vmName; }).fediversityVm)
|
||||||
proxmox
|
proxmox
|
||||||
vmId
|
vmId
|
||||||
description
|
description
|
||||||
|
@ -148,33 +102,16 @@ let
|
||||||
listSubdirectories = path: attrNames (filterAttrs (_: type: type == "directory") (readDir path));
|
listSubdirectories = path: attrNames (filterAttrs (_: type: type == "directory") (readDir path));
|
||||||
|
|
||||||
machines = listSubdirectories ./machines;
|
machines = listSubdirectories ./machines;
|
||||||
testMachines = listSubdirectories ./test-machines;
|
|
||||||
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
## - Each normal or test machine gets a NixOS configuration.
|
## - Each machine gets a NixOS configuration.
|
||||||
## - Each normal or test machine gets a VM options entry.
|
## - Each machine gets a VM options entry.
|
||||||
## - Each normal machine gets a deployment.
|
## - Each machine gets a deployment.
|
||||||
## - We add a “default” deployment with all normal machines.
|
## - We add a “default” deployment with all infra machines.
|
||||||
## - We add a “test” deployment with all test machines.
|
|
||||||
nixops4Deployments = genAttrs machines makeDeployment' // {
|
nixops4Deployments = genAttrs machines makeDeployment' // {
|
||||||
default = makeDeployment machines;
|
default = makeDeployment machines;
|
||||||
test = makeTestDeployment (
|
|
||||||
fromJSON (
|
|
||||||
let
|
|
||||||
env = builtins.getEnv "DEPLOYMENT";
|
|
||||||
in
|
|
||||||
if env != "" then
|
|
||||||
env
|
|
||||||
else
|
|
||||||
builtins.trace "env var DEPLOYMENT not set, falling back to ./test-machines/configuration.json!" (readFile ./test-machines/configuration.json)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
flake.nixosConfigurations =
|
flake.nixosConfigurations = genAttrs machines makeConfiguration;
|
||||||
genAttrs machines (makeConfiguration false)
|
flake.vmOptions = genAttrs machines makeVmOptions;
|
||||||
// genAttrs testMachines (makeConfiguration true);
|
|
||||||
flake.vmOptions =
|
|
||||||
genAttrs machines (makeVmOptions false)
|
|
||||||
// genAttrs testMachines (makeVmOptions true);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,24 @@ in
|
||||||
enable = true;
|
enable = true;
|
||||||
production = true;
|
production = true;
|
||||||
domain = "demo.fediversity.eu";
|
domain = "demo.fediversity.eu";
|
||||||
|
# FIXME: make it work without this duplication
|
||||||
|
settings =
|
||||||
|
let
|
||||||
|
cfg = config.services.${name};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
STATIC_ROOT = "/var/lib/${name}/static";
|
||||||
|
DEBUG = false;
|
||||||
|
ALLOWED_HOSTS = [
|
||||||
|
cfg.domain
|
||||||
|
cfg.host
|
||||||
|
"localhost"
|
||||||
|
"[::1]"
|
||||||
|
];
|
||||||
|
CSRF_TRUSTED_ORIGINS = [ "https://${cfg.domain}" ];
|
||||||
|
COMPRESS_OFFLINE = true;
|
||||||
|
LIBSASS_OUTPUT_STYLE = "compressed";
|
||||||
|
};
|
||||||
secrets = {
|
secrets = {
|
||||||
SECRET_KEY = config.age.secrets.panel-secret-key.path;
|
SECRET_KEY = config.age.secrets.panel-secret-key.path;
|
||||||
};
|
};
|
||||||
|
|
10
launch/.envrc
Normal file
10
launch/.envrc
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# the shebang is ignored, but nice for editors
|
||||||
|
|
||||||
|
# shellcheck shell=bash
|
||||||
|
if type -P lorri &>/dev/null; then
|
||||||
|
eval "$(lorri direnv --flake .)"
|
||||||
|
else
|
||||||
|
echo 'while direnv evaluated .envrc, could not find the command "lorri" [https://github.com/nix-community/lorri]'
|
||||||
|
use flake
|
||||||
|
fi
|
7
launch/.gitignore
vendored
Normal file
7
launch/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# generated
|
||||||
|
.auto.tfvars.json
|
||||||
|
.npins.json
|
||||||
|
.terraform/
|
||||||
|
.terraform.lock.hcl
|
||||||
|
.terraform.tfstate.lock.info
|
||||||
|
terraform.tfstate*
|
28
launch/README.md
Normal file
28
launch/README.md
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# service deployment
|
||||||
|
|
||||||
|
deploys [NixOS](https://nixos.org/) templates using [OpenTofu](https://opentofu.org/).
|
||||||
|
|
||||||
|
## requirements
|
||||||
|
|
||||||
|
- [nix](https://nix.dev/)
|
||||||
|
|
||||||
|
## usage
|
||||||
|
|
||||||
|
### development
|
||||||
|
|
||||||
|
before using other commands, if not using direnv:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
nix-shell
|
||||||
|
```
|
||||||
|
|
||||||
|
then to initialize, or after updating pins or TF providers:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
setup
|
||||||
|
```
|
||||||
|
|
||||||
|
## implementing
|
||||||
|
|
||||||
|
proper documentation TODO.
|
||||||
|
until then, a reference implementation may be found in [`panel/`](https://git.fediversity.eu/Fediversity/Fediversity/src/branch/main/panel).
|
41
launch/default.nix
Normal file
41
launch/default.nix
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
system ? builtins.currentSystem,
|
||||||
|
sources ? import ../npins,
|
||||||
|
# match the same versions we deploy locally
|
||||||
|
inputs ? import sources.flake-inputs {
|
||||||
|
root = ../.;
|
||||||
|
},
|
||||||
|
# match the same version of opentofu that is deployed by the root flake
|
||||||
|
pkgs ? import inputs.nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
},
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (pkgs) lib;
|
||||||
|
setup = pkgs.writeScriptBin "setup" ''
|
||||||
|
echo '${lib.strings.toJSON sources}' > .npins.json
|
||||||
|
rm -f .terraform.lock.hcl
|
||||||
|
rm -rf .terraform/
|
||||||
|
tofu init
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# shell for testing TF directly
|
||||||
|
shell = pkgs.mkShellNoCC {
|
||||||
|
packages = [
|
||||||
|
(import ./tf.nix { inherit lib pkgs; })
|
||||||
|
pkgs.jaq
|
||||||
|
setup
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
tests = pkgs.callPackage ./tests.nix { };
|
||||||
|
|
||||||
|
# re-export inputs so they can be overridden granularly
|
||||||
|
# (they can't be accessed from the outside any other way)
|
||||||
|
inherit
|
||||||
|
sources
|
||||||
|
system
|
||||||
|
pkgs
|
||||||
|
;
|
||||||
|
}
|
34
launch/garage.nix
Normal file
34
launch/garage.nix
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
## NOTE: All of these secrets are publicly available in this source file
|
||||||
|
## and will end up in the Nix store. We don't care as they are only ever
|
||||||
|
## used for testing anyway.
|
||||||
|
##
|
||||||
|
## FIXME: Generate and store in NixOps4's state.
|
||||||
|
mastodonS3KeyConfig =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GK3515373e4c851ebaad366558";
|
||||||
|
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "7d37d093435a41f2aab8f13c19ba067d9776c90215f56614adad6ece597dbb34";
|
||||||
|
};
|
||||||
|
peertubeS3KeyConfig =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GK1f9feea9960f6f95ff404c9b";
|
||||||
|
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "7295c4201966a02c2c3d25b5cea4a5ff782966a2415e3a196f91924631191395";
|
||||||
|
};
|
||||||
|
pixelfedS3KeyConfig =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GKb5615457d44214411e673b7b";
|
||||||
|
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "5be6799a88ca9b9d813d1a806b64f15efa49482dbe15339ddfaf7f19cf434987";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
fediversity = {
|
||||||
|
garage.enable = true;
|
||||||
|
pixelfed = pixelfedS3KeyConfig { inherit pkgs; };
|
||||||
|
mastodon = mastodonS3KeyConfig { inherit pkgs; };
|
||||||
|
peertube = peertubeS3KeyConfig { inherit pkgs; };
|
||||||
|
};
|
||||||
|
}
|
145
launch/main.tf
Normal file
145
launch/main.tf
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
locals {
|
||||||
|
system = "x86_64-linux"
|
||||||
|
# dependency paths pre-calculated from npins
|
||||||
|
pins = jsondecode(file("${path.root}/.npins.json"))
|
||||||
|
# nix path: expose pins, use nixpkgs in flake commands (`nix run`)
|
||||||
|
nix_path = "${join(":", [for name, path in local.pins : "${name}=${path}"])}:flake=${local.pins["nixpkgs"]}:flake"
|
||||||
|
# user-facing applications
|
||||||
|
application_configs = {
|
||||||
|
# FIXME: wrap applications at the interface to grab them in one go?
|
||||||
|
mastodon = var.mastodon
|
||||||
|
pixelfed = var.pixelfed
|
||||||
|
peertube = var.peertube
|
||||||
|
}
|
||||||
|
# services shared between applications
|
||||||
|
peripherals = { for name, inst in {
|
||||||
|
garage = var.garage
|
||||||
|
} : name => merge(inst, {
|
||||||
|
# enable if any user applications are enabled
|
||||||
|
enable = true
|
||||||
|
# enable = anytrue([for _, app in local.application_configs: try(app.enable, false)])
|
||||||
|
}) }
|
||||||
|
}
|
||||||
|
|
||||||
|
# hash of our code directory, used in dev to trigger re-deploy
|
||||||
|
# FIXME settle for pwd when in /nix/store?
|
||||||
|
# FIXME calculate separately to reduce false positives
|
||||||
|
data "external" "hash" {
|
||||||
|
program = ["sh", "-c", "echo \"{\\\"hash\\\":\\\"$(nix-hash ..)\\\"}\""]
|
||||||
|
}
|
||||||
|
|
||||||
|
# TF resource to build and deploy NixOS instances.
|
||||||
|
resource "terraform_data" "nixos" {
|
||||||
|
|
||||||
|
for_each = {for name, inst in merge(
|
||||||
|
local.peripherals,
|
||||||
|
local.application_configs,
|
||||||
|
) : name => inst if try(inst.enable, false)}
|
||||||
|
|
||||||
|
# trigger rebuild/deploy if (FIXME?) any potentially used config/code changed,
|
||||||
|
# preventing these (20+s, build being bottleneck) when nothing changed.
|
||||||
|
# terraform-nixos separates these to only deploy if instantiate changed,
|
||||||
|
# yet building even then - which may be not as bad using deploy on remote.
|
||||||
|
# having build/deploy one resource reflects wanting to prevent no-op rebuilds
|
||||||
|
# over preventing (with less false positives) no-op deployments,
|
||||||
|
# as i could not find a way to do prevent no-op rebuilds without merging them:
|
||||||
|
# - generic resources cannot have outputs, while we want info from the instantiation (unless built on host?).
|
||||||
|
# - `data` always runs, which is slow for deploy and especially build.
|
||||||
|
triggers_replace = [
|
||||||
|
data.external.hash.result,
|
||||||
|
var.domain,
|
||||||
|
var.initialUser,
|
||||||
|
local.system,
|
||||||
|
each.key,
|
||||||
|
each.value,
|
||||||
|
]
|
||||||
|
|
||||||
|
provisioner "local-exec" {
|
||||||
|
# directory to run the script from. we use the TF project root dir,
|
||||||
|
# here as a path relative from where TF is run from.
|
||||||
|
# note that absolute paths can cause false positives in triggers,
|
||||||
|
# so are generally discouraged in TF.
|
||||||
|
working_dir = path.root
|
||||||
|
# TODO: refactor back to command="ignoreme" interpreter=concat([]) to protect sensitive data from error logs?
|
||||||
|
# TODO: build on target?
|
||||||
|
command = <<-EOF
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# INSTANTIATE
|
||||||
|
command=(
|
||||||
|
nix-instantiate
|
||||||
|
--show-trace
|
||||||
|
--expr
|
||||||
|
'let
|
||||||
|
sources = import ../npins;
|
||||||
|
os = import "$${sources.nixpkgs}/nixos" {
|
||||||
|
system = "${local.system}";
|
||||||
|
configuration = {
|
||||||
|
# note interpolations here TF ones
|
||||||
|
imports = [
|
||||||
|
# shared NixOS config
|
||||||
|
${path.root}/shared.nix
|
||||||
|
# FIXME: separate template options by service
|
||||||
|
${path.root}/options.nix
|
||||||
|
# for service `mastodon` import `mastodon.nix`
|
||||||
|
${path.root}/${each.key}.nix
|
||||||
|
# FIXME: get VM details from TF
|
||||||
|
${each.value.nix_module}
|
||||||
|
];
|
||||||
|
# nix path for debugging
|
||||||
|
nix.nixPath = [ "${local.nix_path}" ];
|
||||||
|
## FIXME: switch root authentication to users with password-less sudo, see #24
|
||||||
|
users.users.root.openssh.authorizedKeys.keys = let
|
||||||
|
keys = import ../keys;
|
||||||
|
in builtins.attrValues keys.contributors ++ [
|
||||||
|
# allow our panel vm access to the test machines
|
||||||
|
keys.panel
|
||||||
|
];
|
||||||
|
} //
|
||||||
|
# template parameters passed in from TF thru json
|
||||||
|
builtins.fromJSON "${replace(jsonencode({
|
||||||
|
terraform = {
|
||||||
|
domain = var.domain
|
||||||
|
hostname = each.key
|
||||||
|
initialUser = var.initialUser
|
||||||
|
}
|
||||||
|
}), "\"", "\\\"")}";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
# info we want to get back out
|
||||||
|
{
|
||||||
|
substituters = builtins.concatStringsSep " " os.config.nix.settings.substituters;
|
||||||
|
trusted_public_keys = builtins.concatStringsSep " " os.config.nix.settings.trusted-public-keys;
|
||||||
|
drv_path = os.config.system.build.toplevel.drvPath;
|
||||||
|
out_path = os.config.system.build.toplevel;
|
||||||
|
}'
|
||||||
|
)
|
||||||
|
# instantiate the config in /nix/store
|
||||||
|
"$${command[@]}" -A out_path
|
||||||
|
# get the other info
|
||||||
|
json="$("$${command[@]}" --eval --strict --json)"
|
||||||
|
|
||||||
|
# DEPLOY
|
||||||
|
declare substituters trusted_public_keys drv_path
|
||||||
|
# set our variables using the json object
|
||||||
|
eval "export $(echo $json | jaq -r 'to_entries | map("\(.key)=\(.value)") | @sh')"
|
||||||
|
# FIXME: de-hardcode domain
|
||||||
|
host="root@${each.value.target}" # FIXME: #24
|
||||||
|
buildArgs=(
|
||||||
|
--option extra-binary-caches https://cache.nixos.org/
|
||||||
|
--option substituters $substituters
|
||||||
|
--option trusted-public-keys $trusted_public_keys
|
||||||
|
)
|
||||||
|
sshOpts=(
|
||||||
|
-o BatchMode=yes
|
||||||
|
-o StrictHostKeyChecking=no
|
||||||
|
)
|
||||||
|
# get the realized derivation to deploy
|
||||||
|
outPath=$(nix-store --realize "$drv_path" "$${buildArgs[@]}")
|
||||||
|
# deploy the config by nix-copy-closure
|
||||||
|
NIX_SSHOPTS="$${sshOpts[*]}" nix-copy-closure --to "$host" "$outPath" --gzip --use-substitutes
|
||||||
|
# switch the remote host to the config
|
||||||
|
ssh "$${sshOpts[@]}" "$host" "nix-env --profile /nix/var/nix/profiles/system --set $outPath; $outPath/bin/switch-to-configuration switch"
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
}
|
17
launch/mastodon.nix
Normal file
17
launch/mastodon.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
mastodonS3KeyConfig =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GK3515373e4c851ebaad366558";
|
||||||
|
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "7d37d093435a41f2aab8f13c19ba067d9776c90215f56614adad6ece597dbb34";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
fediversity = {
|
||||||
|
mastodon = mastodonS3KeyConfig { inherit pkgs; } // {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
temp.cores = 1; # FIXME: should come from NixOps4 eventually
|
||||||
|
};
|
||||||
|
}
|
55
launch/options.nix
Normal file
55
launch/options.nix
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# interface between the nix module and TF
|
||||||
|
# TODO: could (part of) this be generated somehow? c.f #275
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) types mkOption;
|
||||||
|
inherit (types) str enum submodule;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.terraform = {
|
||||||
|
domain = mkOption {
|
||||||
|
type = enum [
|
||||||
|
"fediversity.net"
|
||||||
|
];
|
||||||
|
description = ''
|
||||||
|
Apex domain under which the services will be deployed.
|
||||||
|
'';
|
||||||
|
default = "fediversity.net";
|
||||||
|
};
|
||||||
|
hostname = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = ''
|
||||||
|
Internal name of the host, e.g. test01
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
initialUser = mkOption {
|
||||||
|
description = ''
|
||||||
|
Some services require an initial user to access them.
|
||||||
|
This option sets the credentials for such an initial user.
|
||||||
|
'';
|
||||||
|
type = submodule {
|
||||||
|
options = {
|
||||||
|
displayName = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Display name of the user";
|
||||||
|
};
|
||||||
|
username = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Username for login";
|
||||||
|
};
|
||||||
|
email = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "User's email address";
|
||||||
|
};
|
||||||
|
password = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "Password for login";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
20
launch/peertube.nix
Normal file
20
launch/peertube.nix
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
peertubeS3KeyConfig =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GK1f9feea9960f6f95ff404c9b";
|
||||||
|
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "7295c4201966a02c2c3d25b5cea4a5ff782966a2415e3a196f91924631191395";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
fediversity = {
|
||||||
|
peertube = peertubeS3KeyConfig { inherit pkgs; } // {
|
||||||
|
enable = true;
|
||||||
|
## NOTE: Only ever used for testing anyway.
|
||||||
|
##
|
||||||
|
## FIXME: Generate and store in NixOps4's state.
|
||||||
|
secretsFile = pkgs.writeText "secret" "574e093907d1157ac0f8e760a6deb1035402003af5763135bae9cbd6abe32b24";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
16
launch/pixelfed.nix
Normal file
16
launch/pixelfed.nix
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
|
pixelfedS3KeyConfig =
|
||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GKb5615457d44214411e673b7b";
|
||||||
|
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "5be6799a88ca9b9d813d1a806b64f15efa49482dbe15339ddfaf7f19cf434987";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
fediversity = {
|
||||||
|
pixelfed = pixelfedS3KeyConfig { inherit pkgs; } // {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
43
launch/resource.nix
Normal file
43
launch/resource.nix
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib) attrValues elem;
|
||||||
|
inherit (lib.attrsets) concatMapAttrs optionalAttrs;
|
||||||
|
inherit (lib.strings) removeSuffix;
|
||||||
|
|
||||||
|
secretsPrefix = ../secrets;
|
||||||
|
secrets = import (secretsPrefix + "/secrets.nix");
|
||||||
|
keys = import ../keys;
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# fediversityVm.hostPublicKey = mkDefault keys.systems.${config.fediversityVm.name};
|
||||||
|
|
||||||
|
## The configuration of the machine. We strive to keep in this file only the
|
||||||
|
## options that really need to be injected from the resource. Everything else
|
||||||
|
## should go into the `./nixos` subdirectory.
|
||||||
|
imports = [
|
||||||
|
../infra/common/options.nix
|
||||||
|
../infra/common/nixos
|
||||||
|
];
|
||||||
|
|
||||||
|
## Read all the secrets, filter the ones that are supposed to be readable
|
||||||
|
## with this host's public key, and add them correctly to the configuration
|
||||||
|
## as `age.secrets.<name>.file`.
|
||||||
|
age.secrets = concatMapAttrs (
|
||||||
|
name: secret:
|
||||||
|
optionalAttrs (elem config.fediversityVm.name secret.publicKeys) {
|
||||||
|
${removeSuffix ".age" name}.file = secretsPrefix + "/${name}";
|
||||||
|
}
|
||||||
|
) secrets;
|
||||||
|
|
||||||
|
## FIXME: switch root authentication to users with password-less sudo, see #24
|
||||||
|
users.users.root.openssh.authorizedKeys.keys = attrValues keys.contributors ++ [
|
||||||
|
# allow our panel vm access to the test machines
|
||||||
|
keys.panel
|
||||||
|
];
|
||||||
|
}
|
27
launch/shared.nix
Normal file
27
launch/shared.nix
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (config.terraform) hostname domain initialUser;
|
||||||
|
sources = import ../npins;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = with sources; [
|
||||||
|
"${disko}/module.nix"
|
||||||
|
"${agenix}/modules/age.nix"
|
||||||
|
../services/fediversity
|
||||||
|
./resource.nix
|
||||||
|
];
|
||||||
|
fediversityVm.name = hostname;
|
||||||
|
fediversity = {
|
||||||
|
inherit domain;
|
||||||
|
temp.initialUser = {
|
||||||
|
inherit (initialUser) username email displayName;
|
||||||
|
# FIXME: disgusting, but nvm, this is going to be replaced by
|
||||||
|
# proper central authentication at some point
|
||||||
|
passwordFile = pkgs.writeText "password" initialUser.password;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
1
launch/shell.nix
Normal file
1
launch/shell.nix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
(import ./. { }).shell
|
26
launch/tests.nix
Normal file
26
launch/tests.nix
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{ lib, pkgs }:
|
||||||
|
let
|
||||||
|
defaults = {
|
||||||
|
virtualisation = {
|
||||||
|
memorySize = 2048;
|
||||||
|
cores = 2;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
tf = pkgs.callPackage ./tf.nix { };
|
||||||
|
tfEnv = pkgs.callPackage ./tf-env.nix { };
|
||||||
|
in
|
||||||
|
lib.mapAttrs (name: test: pkgs.testers.runNixOSTest (test // { inherit name; })) {
|
||||||
|
tf-validate = {
|
||||||
|
inherit defaults;
|
||||||
|
nodes.server = {
|
||||||
|
environment.systemPackages = [
|
||||||
|
tf
|
||||||
|
tfEnv
|
||||||
|
];
|
||||||
|
};
|
||||||
|
testScript = ''
|
||||||
|
server.wait_for_unit("multi-user.target")
|
||||||
|
server.succeed("${lib.getExe tf} -chdir='${tfEnv}/launch' validate")
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
34
launch/tf-env.nix
Normal file
34
launch/tf-env.nix
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
sources ? import ../npins,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
pkgs.stdenv.mkDerivation {
|
||||||
|
name = "tf-repo";
|
||||||
|
src =
|
||||||
|
with lib.fileset;
|
||||||
|
toSource {
|
||||||
|
root = ../.;
|
||||||
|
# don't copy ignored files
|
||||||
|
fileset = intersection (gitTracked ../.) ../.;
|
||||||
|
};
|
||||||
|
buildInputs = [
|
||||||
|
(import ./tf.nix { inherit lib pkgs; })
|
||||||
|
];
|
||||||
|
buildPhase = ''
|
||||||
|
runHook preBuild
|
||||||
|
pushd launch/
|
||||||
|
# calculated pins
|
||||||
|
echo '${lib.strings.toJSON sources}' > .npins.json
|
||||||
|
# generate TF lock for nix's TF providers
|
||||||
|
tofu init -input=false
|
||||||
|
popd
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
cp -r . $out
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
}
|
24
launch/tf.nix
Normal file
24
launch/tf.nix
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# FIXME: use overlays so this gets imported just once?
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
tofuProvider =
|
||||||
|
provider:
|
||||||
|
provider.override (oldArgs: {
|
||||||
|
provider-source-address =
|
||||||
|
lib.replaceStrings [ "https://registry.terraform.io/providers" ] [ "registry.opentofu.org" ]
|
||||||
|
oldArgs.homepage;
|
||||||
|
});
|
||||||
|
tf = pkgs.opentofu;
|
||||||
|
tfPlugins = (
|
||||||
|
p: [
|
||||||
|
p.external
|
||||||
|
]
|
||||||
|
);
|
||||||
|
in
|
||||||
|
# tf.withPlugins tfPlugins
|
||||||
|
# https://github.com/NixOS/nixpkgs/pull/358522
|
||||||
|
tf.withPlugins (p: pkgs.lib.lists.map tofuProvider (tfPlugins p))
|
60
launch/variables.tf
Normal file
60
launch/variables.tf
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
# interface between the TF module and the caller
|
||||||
|
# TODO: (partially) generate, say from nix modules, c.f. #275
|
||||||
|
|
||||||
|
variable "domain" {
|
||||||
|
type = string
|
||||||
|
default = "fediversity.net"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "garage" {
|
||||||
|
type = object({
|
||||||
|
target = optional(string, "test01.abundos.eu")
|
||||||
|
nix_module = optional(string, "../infra/test-machines/test01")
|
||||||
|
})
|
||||||
|
default = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "mastodon" {
|
||||||
|
type = object({
|
||||||
|
enable = optional(bool, false)
|
||||||
|
target = optional(string, "test06.abundos.eu")
|
||||||
|
nix_module = optional(string, "../infra/test-machines/test06")
|
||||||
|
})
|
||||||
|
default = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "pixelfed" {
|
||||||
|
type = object({
|
||||||
|
enable = optional(bool, false)
|
||||||
|
target = optional(string, "test04.abundos.eu")
|
||||||
|
nix_module = optional(string, "../infra/test-machines/test04")
|
||||||
|
})
|
||||||
|
default = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "peertube" {
|
||||||
|
type = object({
|
||||||
|
enable = optional(bool, false)
|
||||||
|
target = optional(string, "test05.abundos.eu")
|
||||||
|
nix_module = optional(string, "../infra/test-machines/test05")
|
||||||
|
})
|
||||||
|
default = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "initialUser" {
|
||||||
|
type = object({
|
||||||
|
displayName = string
|
||||||
|
username = string
|
||||||
|
email = string
|
||||||
|
# TODO: mark (nested) credentials as sensitive
|
||||||
|
# https://discuss.hashicorp.com/t/is-it-possible-to-mark-an-attribute-of-an-object-as-sensitive/24649/2
|
||||||
|
password = string
|
||||||
|
})
|
||||||
|
# FIXME: remove default when the form provides this value, see #285
|
||||||
|
default = {
|
||||||
|
displayName = "Testy McTestface"
|
||||||
|
username = "test"
|
||||||
|
email = "test@test.com"
|
||||||
|
password = "testtest"
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,6 +25,32 @@
|
||||||
"url": null,
|
"url": null,
|
||||||
"hash": "1w2gsy6qwxa5abkv8clb435237iifndcxq0s79wihqw11a5yb938"
|
"hash": "1w2gsy6qwxa5abkv8clb435237iifndcxq0s79wihqw11a5yb938"
|
||||||
},
|
},
|
||||||
|
"disko": {
|
||||||
|
"type": "Git",
|
||||||
|
"repository": {
|
||||||
|
"type": "GitHub",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "disko"
|
||||||
|
},
|
||||||
|
"branch": "master",
|
||||||
|
"submodules": false,
|
||||||
|
"revision": "b5d1320ebc2f34dbea4655f95167f55e2130cdb3",
|
||||||
|
"url": "https://github.com/nix-community/disko/archive/b5d1320ebc2f34dbea4655f95167f55e2130cdb3.tar.gz",
|
||||||
|
"hash": "1dcakwcvbqapvd6c321kdrhki30dn1pbnffvzhdb0ab4gman9fcq"
|
||||||
|
},
|
||||||
|
"flake-inputs": {
|
||||||
|
"type": "Git",
|
||||||
|
"repository": {
|
||||||
|
"type": "GitHub",
|
||||||
|
"owner": "fricklerhandwerk",
|
||||||
|
"repo": "flake-inputs"
|
||||||
|
},
|
||||||
|
"branch": "main",
|
||||||
|
"submodules": false,
|
||||||
|
"revision": "559574c9cbb8af262f3944b67d60fbf0f6ad03c3",
|
||||||
|
"url": "https://github.com/fricklerhandwerk/flake-inputs/archive/559574c9cbb8af262f3944b67d60fbf0f6ad03c3.tar.gz",
|
||||||
|
"hash": "0gbhmp6x2vdzvfnsvqzal3g8f8hx2ia6r73aibc78kazf78m67x6"
|
||||||
|
},
|
||||||
"flake-parts": {
|
"flake-parts": {
|
||||||
"type": "Git",
|
"type": "Git",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -21,10 +21,17 @@ in
|
||||||
pkgs.npins
|
pkgs.npins
|
||||||
manage
|
manage
|
||||||
];
|
];
|
||||||
env = import ./env.nix { inherit lib pkgs; } // {
|
env =
|
||||||
|
let
|
||||||
|
inherit (builtins) toString;
|
||||||
|
in
|
||||||
|
import ./env.nix { inherit lib pkgs; }
|
||||||
|
// {
|
||||||
NPINS_DIRECTORY = toString ../npins;
|
NPINS_DIRECTORY = toString ../npins;
|
||||||
CREDENTIALS_DIRECTORY = toString ./.credentials;
|
CREDENTIALS_DIRECTORY = toString ./.credentials;
|
||||||
DATABASE_URL = "sqlite:///${toString ./src}/db.sqlite3";
|
DATABASE_URL = "sqlite:///${toString ./src}/db.sqlite3";
|
||||||
|
# locally: use a fixed relative reference, so we can use our newest files without copying to the store
|
||||||
|
REPO_DIR = toString ../.;
|
||||||
};
|
};
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
${lib.concatStringsSep "\n" (
|
${lib.concatStringsSep "\n" (
|
||||||
|
|
|
@ -3,16 +3,14 @@
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
|
||||||
inherit (builtins) toString;
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
REPO_DIR = toString ../.;
|
|
||||||
# explicitly use nix, as e.g. lix does not have configurable-impure-env
|
|
||||||
BIN_PATH = lib.makeBinPath [
|
BIN_PATH = lib.makeBinPath [
|
||||||
# explicitly use nix, as e.g. lix does not have configurable-impure-env
|
pkgs.lix
|
||||||
pkgs.nix
|
pkgs.bash
|
||||||
# nixops error maybe due to our flake git hook: executing 'git': No such file or directory
|
pkgs.coreutils
|
||||||
|
pkgs.openssh
|
||||||
pkgs.git
|
pkgs.git
|
||||||
|
pkgs.jaq # tf
|
||||||
|
(import ../launch/tf.nix { inherit lib pkgs; })
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ let
|
||||||
((pkgs.formats.pythonVars { }).generate "settings.py" cfg.settings)
|
((pkgs.formats.pythonVars { }).generate "settings.py" cfg.settings)
|
||||||
(builtins.toFile "extra-settings.py" cfg.extra-settings)
|
(builtins.toFile "extra-settings.py" cfg.extra-settings)
|
||||||
];
|
];
|
||||||
|
REPO_DIR = import ../../launch/tf-env.nix { inherit lib pkgs; };
|
||||||
};
|
};
|
||||||
|
|
||||||
python-environment = pkgs.python3.withPackages (
|
python-environment = pkgs.python3.withPackages (
|
||||||
|
@ -157,9 +158,7 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users.${name} = {
|
users.users.${name}.isNormalUser = true;
|
||||||
isNormalUser = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
users.groups.${name} = { };
|
users.groups.${name} = { };
|
||||||
systemd.services.${name} = {
|
systemd.services.${name} = {
|
||||||
|
@ -167,6 +166,7 @@ in
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
path = [
|
path = [
|
||||||
|
pkgs.openssh
|
||||||
python-environment
|
python-environment
|
||||||
manage-service
|
manage-service
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
|
pkgs,
|
||||||
sqlite,
|
sqlite,
|
||||||
python3,
|
python3,
|
||||||
python3Packages,
|
python3Packages,
|
||||||
|
@ -14,7 +15,7 @@ let
|
||||||
root = ../src;
|
root = ../src;
|
||||||
fileset = intersection (gitTracked ../../.) ../src;
|
fileset = intersection (gitTracked ../../.) ../src;
|
||||||
};
|
};
|
||||||
pyproject = with lib; fromTOML pyproject-toml;
|
pyproject = fromTOML pyproject-toml;
|
||||||
# TODO: define this globally
|
# TODO: define this globally
|
||||||
name = "panel";
|
name = "panel";
|
||||||
# TODO: we may want this in a file so it's easier to read statically
|
# TODO: we may want this in a file so it's easier to read statically
|
||||||
|
@ -89,7 +90,9 @@ python3.pkgs.buildPythonPackage {
|
||||||
mkdir -p $out/bin
|
mkdir -p $out/bin
|
||||||
cp -v ${src}/manage.py $out/bin/manage.py
|
cp -v ${src}/manage.py $out/bin/manage.py
|
||||||
chmod +x $out/bin/manage.py
|
chmod +x $out/bin/manage.py
|
||||||
wrapProgram $out/bin/manage.py --prefix PYTHONPATH : "$PYTHONPATH"
|
wrapProgram $out/bin/manage.py \
|
||||||
|
--set REPO_DIR "${import ../../launch/tf-env.nix { inherit lib pkgs; }}" \
|
||||||
|
--prefix PYTHONPATH : "$PYTHONPATH"
|
||||||
${lib.concatStringsSep "\n" (
|
${lib.concatStringsSep "\n" (
|
||||||
map (file: "cp ${file.from} $out/${python3.sitePackages}/${file.to}") generated
|
map (file: "cp ${file.from} $out/${python3.sitePackages}/${file.to}") generated
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# TODO upstream, see #248
|
||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
buildPythonPackage,
|
buildPythonPackage,
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
{% for service_name, service_meta in services.items %}
|
{% for service_name, service_meta in services.items %}
|
||||||
{% if service_meta.enable %}
|
{% if service_meta.enable %}
|
||||||
<li>
|
<li>
|
||||||
✓ <a target="_blank" href={{ service_meta.url }}>{{ service_name }}</a>
|
✓ <a target="_blank" href="https://{{ service_name }}.{{ services.domain }}">{{ service_name }}</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
import json
|
import json
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
|
@ -19,6 +20,8 @@ from pydantic import BaseModel
|
||||||
from panel import models, settings
|
from panel import models, settings
|
||||||
from panel.configuration import schema
|
from panel.configuration import schema
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Index(TemplateView):
|
class Index(TemplateView):
|
||||||
template_name = 'index.html'
|
template_name = 'index.html'
|
||||||
|
|
||||||
|
@ -106,22 +109,24 @@ class DeploymentStatus(ConfigurationForm):
|
||||||
}
|
}
|
||||||
env = {
|
env = {
|
||||||
"PATH": settings.bin_path,
|
"PATH": settings.bin_path,
|
||||||
|
"TF_LOG": "info",
|
||||||
|
"TF_LOG_CORE": "info",
|
||||||
|
} | {
|
||||||
# pass in form info to our deployment
|
# pass in form info to our deployment
|
||||||
"DEPLOYMENT": config.json()
|
# FIXME: ensure sensitive info is protected
|
||||||
|
f"TF_VAR_{k}": v if isinstance(v, str) else json.dumps(v) for k, v in json.loads(config.model_dump_json()).items()
|
||||||
}
|
}
|
||||||
|
logger.info("env: %s", env)
|
||||||
|
cwd = f"{settings.repo_dir}/launch"
|
||||||
cmd = [
|
cmd = [
|
||||||
"nix",
|
"tofu",
|
||||||
"develop",
|
# f"-chdir={cwd}",
|
||||||
"--extra-experimental-features",
|
|
||||||
"configurable-impure-env",
|
|
||||||
"--command",
|
|
||||||
"nixops4",
|
|
||||||
"apply",
|
"apply",
|
||||||
"test",
|
f"-state={cwd}/terraform.tfstate", # FIXME: separate users' state
|
||||||
|
"--auto-approve",
|
||||||
|
"-lock=false",
|
||||||
|
"-parallelism=1" # limit OOM risk
|
||||||
]
|
]
|
||||||
deployment_result = subprocess.run(
|
deployment_result = subprocess.run(cmd, cwd=cwd, env=env)
|
||||||
cmd,
|
logger.debug("deployment_result: %s", deployment_result)
|
||||||
cwd=settings.repo_dir,
|
|
||||||
env=env,
|
|
||||||
)
|
|
||||||
return deployment_result, config
|
return deployment_result, config
|
||||||
|
|
|
@ -59,9 +59,10 @@ in
|
||||||
## NOTE: Pixelfed as packaged in nixpkgs has a permission issue that prevents Nginx
|
## NOTE: Pixelfed as packaged in nixpkgs has a permission issue that prevents Nginx
|
||||||
## from being able to serving the images. We fix it here, but this should be
|
## from being able to serving the images. We fix it here, but this should be
|
||||||
## upstreamed. See https://github.com/NixOS/nixpkgs/issues/235147
|
## upstreamed. See https://github.com/NixOS/nixpkgs/issues/235147
|
||||||
services.pixelfed.package = pkgs.pixelfed.overrideAttrs (old: {
|
# patching failed
|
||||||
patches = (old.patches or [ ]) ++ [ ./group-permissions.patch ];
|
# services.pixelfed.package = pkgs.pixelfed.overrideAttrs (old: {
|
||||||
});
|
# patches = (old.patches or [ ]) ++ [ ./group-permissions.patch ];
|
||||||
|
# });
|
||||||
users.users.nginx.extraGroups = [ "pixelfed" ];
|
users.users.nginx.extraGroups = [ "pixelfed" ];
|
||||||
|
|
||||||
services.pixelfed = {
|
services.pixelfed = {
|
||||||
|
|
Loading…
Add table
Reference in a new issue