infra tf-validate tests working

This commit is contained in:
Kiara Grouwstra 2025-04-21 20:31:10 +02:00
parent 46f34d1188
commit a1f068a1db
Signed by: kiara
SSH key fingerprint: SHA256:COspvLoLJ5WC5rFb9ZDe5urVCkK4LJZOsjfF4duRJFU
22 changed files with 106 additions and 75 deletions

4
.envrc
View file

@ -3,8 +3,8 @@
# shellcheck shell=bash # shellcheck shell=bash
if type -P lorri &>/dev/null; then if type -P lorri &>/dev/null; then
eval "$(lorri direnv --flake .)" eval "$(lorri direnv)"
else else
echo 'while direnv evaluated .envrc, could not find the command "lorri" [https://github.com/nix-community/lorri]' echo 'while direnv evaluated .envrc, could not find the command "lorri" [https://github.com/nix-community/lorri]'
use flake use_nix
fi fi

View file

@ -27,12 +27,6 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: cd panel && nix-build -A tests - run: cd panel && nix-build -A tests
check-launch:
runs-on: native
steps:
- uses: actions/checkout@v4
- run: cd launch && nix-build -A tests
check-infra: check-infra:
runs-on: native runs-on: native
steps: steps:

View file

@ -3,8 +3,8 @@
# shellcheck shell=bash # shellcheck shell=bash
if type -P lorri &>/dev/null; then if type -P lorri &>/dev/null; then
eval "$(lorri direnv --flake .)" eval "$(lorri direnv)"
else else
echo 'while direnv evaluated .envrc, could not find the command "lorri" [https://github.com/nix-community/lorri]' echo 'while direnv evaluated .envrc, could not find the command "lorri" [https://github.com/nix-community/lorri]'
use flake use_nix
fi fi

View file

@ -22,7 +22,7 @@ then to initialize, or after updating pins or TF providers:
setup setup
``` ```
then, one can use the `tofu` CLI. then, one can use the `tofu` CLI in the sub-folders.
## implementing ## implementing

View file

@ -1,17 +0,0 @@
refactor:
- account for moves of
- machines
- proxmox
- launch
- own dir with:
- TF config
- TF state
- TF lock
- `setup` process (document running per project)
- abstract out common TF logic to a separate TF module
- symlink thru nix
test:
- services tests
- secret shell
- ci

View file

@ -9,9 +9,9 @@ let
inherit (lib.attrsets) concatMapAttrs optionalAttrs; inherit (lib.attrsets) concatMapAttrs optionalAttrs;
inherit (lib.strings) removeSuffix; inherit (lib.strings) removeSuffix;
secretsPrefix = ../secrets; secretsPrefix = ../../secrets;
secrets = import (secretsPrefix + "/secrets.nix"); secrets = import (secretsPrefix + "/secrets.nix");
keys = import ../keys; keys = import ../../keys;
in in
{ {
@ -21,8 +21,8 @@ in
## options that really need to be injected from the resource. Everything else ## options that really need to be injected from the resource. Everything else
## should go into the `./nixos` subdirectory. ## should go into the `./nixos` subdirectory.
imports = [ imports = [
../infra/common/options.nix ./options.nix
../infra/common/nixos ./nixos
]; ];
## Read all the secrets, filter the ones that are supposed to be readable ## Read all the secrets, filter the ones that are supposed to be readable

View file

@ -10,7 +10,7 @@ in
imports = [ imports = [
<disko/module.nix> <disko/module.nix>
<agenix/modules/age.nix> <agenix/modules/age.nix>
../services/fediversity ../../services/fediversity
./resource.nix ./resource.nix
]; ];
fediversityVm.name = hostname; fediversityVm.name = hostname;

View file

@ -5,18 +5,13 @@
}: }:
let let
inherit (pkgs) lib; inherit (pkgs) lib;
setup = pkgs.writeScriptBin "setup" '' setup = import ./setup.nix { inherit lib pkgs sources; };
echo '${lib.strings.toJSON sources}' > module/.npins.json
rm -f .terraform.lock.hcl
rm -rf .terraform/
tofu init
'';
in in
{ {
# shell for testing TF directly # shell for testing TF directly
shell = pkgs.mkShellNoCC { shell = pkgs.mkShellNoCC {
packages = [ packages = [
(import ./../launch/tf.nix { inherit lib pkgs; }) (import ./tf.nix { inherit lib pkgs; })
pkgs.jaq pkgs.jaq
setup setup
]; ];

View file

@ -1,6 +1,11 @@
module "nixos" { locals {
source = "./deploy" vm_domain = "abundos.eu"
}
module "nixos" {
source = "../sync-nix"
vm_domain = local.vm_domain
hostname = each.value.hostname hostname = each.value.hostname
config_nix = each.value.config_nix config_nix = each.value.config_nix
config_tf = each.value.config_nix config_tf = each.value.config_nix
@ -24,16 +29,14 @@ module "nixos" {
# note interpolations here TF ones # note interpolations here TF ones
imports = [ imports = [
# shared NixOS config # shared NixOS config
${path.root}/../launch/shared.nix ${path.root}/../common/shared.nix
# FIXME: separate template options by service # FIXME: separate template options by service
${path.root}/options.nix ${path.root}/options.nix
# for service `forgejo` import `forgejo.nix` # for service `forgejo` import `forgejo.nix`
${path.root}/machines/${inst}/${name}.nix ${path.root}/../../machines/dev/${inst}/${name}.nix
# FIXME: get VM details from TF # FIXME: get VM details from TF
${path.root}/machines/${inst} ${path.root}/../../machines/dev/${inst}
]; ];
# nix path for debugging
nix.nixPath = [ "${local.nix_path}" ];
} }
EOF EOF
} }

View file

@ -1,4 +1,5 @@
locals { locals {
vm_domain = "abundos.eu"
# user-facing applications # user-facing applications
application_configs = { application_configs = {
# FIXME: wrap applications at the interface to grab them in one go? # FIXME: wrap applications at the interface to grab them in one go?
@ -29,8 +30,9 @@ locals {
} }
module "nixos" { module "nixos" {
source = "../infra/deploy" source = "../sync-nix"
vm_domain = local.vm_domain
hostname = each.value.hostname hostname = each.value.hostname
config_nix = each.value.config_nix config_nix = each.value.config_nix
config_tf = each.value.config_nix config_tf = each.value.config_nix
@ -51,16 +53,14 @@ module "nixos" {
# note interpolations here TF ones # note interpolations here TF ones
imports = [ imports = [
# shared NixOS config # shared NixOS config
${path.root}/shared.nix ${path.root}/../common/shared.nix
# FIXME: separate template options by service # FIXME: separate template options by service
${path.root}/options.nix ${path.root}/options.nix
# for service `mastodon` import `mastodon.nix` # for service `mastodon` import `mastodon.nix`
${path.root}/${name}.nix ${path.root}/../../machines/operator/${name}.nix
# FIXME: get VM details from TF # FIXME: get VM details from TF
${path.root}/../infra/test-machines/${inst.hostname} ${path.root}/../../machines/operator/${inst.hostname}
]; ];
# nix path for debugging
nix.nixPath = [ "${local.nix_path}" ];
## FIXME: switch root authentication to users with password-less sudo, see #24 ## FIXME: switch root authentication to users with password-less sudo, see #24
users.users.root.openssh.authorizedKeys.keys = let users.users.root.openssh.authorizedKeys.keys = let
keys = import ../keys; keys = import ../keys;

20
infra/setup.nix Normal file
View file

@ -0,0 +1,20 @@
{
pkgs,
lib,
sources,
...
}:
pkgs.writeScriptBin "setup" ''
# calculated pins
echo '${lib.strings.toJSON sources}' > sync-nix/.npins.json
# generate TF lock for nix's TF providers
for category in dev operator; do
pushd "$category"
rm -rf .terraform/
rm -f .terraform.lock.hcl
# suppress warning on architecture-specific generated lock file:
# `Warning: Incomplete lock file information for providers`.
tofu init -input=false 1>/dev/null
popd
done
''

View file

@ -1,6 +1,5 @@
locals { locals {
system = "x86_64-linux" system = "x86_64-linux"
vm_domain = "abundos.eu"
# dependency paths pre-calculated from npins # dependency paths pre-calculated from npins
pins = jsondecode(file("${path.module}/.npins.json")) pins = jsondecode(file("${path.module}/.npins.json"))
# nix path: expose pins, use nixpkgs in flake commands (`nix run`) # nix path: expose pins, use nixpkgs in flake commands (`nix run`)
@ -82,7 +81,7 @@ resource "terraform_data" "nixos" {
declare substituters trusted_public_keys drv_path declare substituters trusted_public_keys drv_path
# set our variables using the json object # set our variables using the json object
eval "export $(echo $json | jaq -r 'to_entries | map("\(.key)=\(.value)") | @sh')" eval "export $(echo $json | jaq -r 'to_entries | map("\(.key)=\(.value)") | @sh')"
host="root@${var.hostname}.${local.vm_domain}" # FIXME: #24 host="root@${var.hostname}.${var.vm_domain}" # FIXME: #24
buildArgs=( buildArgs=(
--option extra-binary-caches https://cache.nixos.org/ --option extra-binary-caches https://cache.nixos.org/
--option substituters $substituters --option substituters $substituters

View file

@ -1,3 +1,7 @@
variable "vm_domain" {
type = string
}
variable "hostname" { variable "hostname" {
type = string type = string
} }

View file

@ -8,22 +8,30 @@ let
}; };
tf = pkgs.callPackage ./tf.nix { tf = pkgs.callPackage ./tf.nix {
inherit lib pkgs; inherit lib pkgs;
dir = "infra/";
}; };
tfEnv = pkgs.callPackage ./tf-env.nix { }; tfEnv = pkgs.callPackage ./tf-env.nix { };
in nodes = {
lib.mapAttrs (name: test: pkgs.testers.runNixOSTest (test // { inherit name; })) { server = {
tf-validate = {
inherit defaults;
nodes.server = {
environment.systemPackages = [ environment.systemPackages = [
tf tf
tfEnv tfEnv
]; ];
}; };
};
in
lib.mapAttrs (name: test: pkgs.testers.runNixOSTest (test // { inherit name; })) {
tf-validate-dev = {
inherit defaults nodes;
testScript = '' testScript = ''
server.wait_for_unit("multi-user.target") server.wait_for_unit("multi-user.target")
server.succeed("${lib.getExe tf} -chdir='${tfEnv}/infra' validate") server.succeed("${lib.getExe tf} -chdir='${tfEnv}/infra/dev' validate")
'';
};
tf-validate-operator = {
inherit defaults nodes;
testScript = ''
server.wait_for_unit("multi-user.target")
server.succeed("${lib.getExe tf} -chdir='${tfEnv}/infra/operator' validate")
''; '';
}; };
} }

View file

@ -1,7 +1,6 @@
{ {
lib, lib,
pkgs, pkgs,
path,
sources ? import ../npins, sources ? import ../npins,
... ...
}: }:
@ -16,14 +15,12 @@ pkgs.stdenv.mkDerivation {
}; };
buildInputs = [ buildInputs = [
(import ./tf.nix { inherit lib pkgs; }) (import ./tf.nix { inherit lib pkgs; })
(import ./setup.nix { inherit lib pkgs sources; })
]; ];
buildPhase = '' buildPhase = ''
runHook preBuild runHook preBuild
pushd ${path} pushd infra
# calculated pins setup
echo '${lib.strings.toJSON sources}' > ../infra/deploy.npins.json
# generate TF lock for nix's TF providers
tofu init -input=false
popd popd
runHook postBuild runHook postBuild
''; '';

View file

@ -11,7 +11,7 @@
pkgs.openssh pkgs.openssh
pkgs.git pkgs.git
pkgs.jaq # tf pkgs.jaq # tf
(import ../launch/tf.nix { inherit lib pkgs; }) (import ../infra/tf.nix { inherit lib pkgs; })
]; ];
SSH_PRIVATE_KEY_FILE = ""; SSH_PRIVATE_KEY_FILE = "";
} }

View file

@ -29,9 +29,8 @@ 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 { REPO_DIR = import ../../infra/tf-env.nix {
inherit lib pkgs; inherit lib pkgs;
dir = "launch/";
}; };
}; };

View file

@ -71,9 +71,8 @@ python3.pkgs.buildPythonPackage {
chmod +x $out/bin/manage.py chmod +x $out/bin/manage.py
wrapProgram $out/bin/manage.py \ wrapProgram $out/bin/manage.py \
--set REPO_DIR "${ --set REPO_DIR "${
import ../../launch/tf-env.nix { import ../../infra/tf-env.nix {
inherit lib pkgs; inherit lib pkgs;
dir = "launch/";
} }
}" \ }" \
--prefix PYTHONPATH : "$PYTHONPATH" --prefix PYTHONPATH : "$PYTHONPATH"

View file

@ -148,12 +148,12 @@ class DeploymentStatus(ConfigurationForm):
f"TF_VAR_{k}": v if isinstance(v, str) else json.dumps(v) for k, v in deployment_params.items() f"TF_VAR_{k}": v if isinstance(v, str) else json.dumps(v) for k, v in deployment_params.items()
} }
logger.info("env: %s", env) logger.info("env: %s", env)
cwd = f"{settings.repo_dir}/launch" cwd = f"{settings.repo_dir}/infra/operator"
cmd = [ cmd = [
"tofu", "tofu",
# f"-chdir={cwd}", # f"-chdir={cwd}",
"apply", "apply",
f"-state={cwd}/terraform.tfstate", # FIXME: separate users' state f"-state={cwd}/terraform.tfstate", # FIXME: separate users' state, see #313
"--auto-approve", "--auto-approve",
"-lock=false", "-lock=false",
"-parallelism=1" # limit OOM risk "-parallelism=1" # limit OOM risk

10
proxmox/.envrc Normal file
View 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)"
else
echo 'while direnv evaluated .envrc, could not find the command "lorri" [https://github.com/nix-community/lorri]'
use_nix
fi

10
secrets/.envrc Normal file
View 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)"
else
echo 'while direnv evaluated .envrc, could not find the command "lorri" [https://github.com/nix-community/lorri]'
use_nix
fi

10
services/.envrc Normal file
View 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)"
else
echo 'while direnv evaluated .envrc, could not find the command "lorri" [https://github.com/nix-community/lorri]'
use_nix
fi