Compare commits

...

13 commits

Author SHA1 Message Date
2ed7f3ebe5
get TF in prod to the same 'installable ... does not correspond to a Nix language value' for non-flakes
seemingly gets further when a similar command is tried from terminal.
as per https://github.com/NixOS/nix/issues/8752#issuecomment-1694714693,
this may have to do with aligning the current working directory.
2025-03-28 21:08:55 +01:00
66c0425e1c
document updating TF module 2025-03-27 16:18:10 +01:00
7e35b1244e
update 2025-03-27 16:18:10 +01:00
ed5853f432
specify XDG_CACHE_HOME, workaround to error writing to /var/empty/.cache 2025-03-27 16:18:10 +01:00
35279d7305
skip tf lock in views.py over read-only nix env 2025-03-27 16:18:09 +01:00
b7833fdb03
move tf init out of python over read-only nix env 2025-03-27 16:18:09 +01:00
d428faa9a3
properly pass repo dir for prod, be it with hard-coded TF init 2025-03-27 16:18:09 +01:00
232c0e8963
use flake-sourced nixos-anywhere in tf, to reproduce modules for nix 2025-03-27 16:18:09 +01:00
3d3804a6ad
switch launch shell to root flake's nixpkgs, see #279 2025-03-27 16:18:09 +01:00
cbd869a6f2
Revert "deduplicate flake inputs"
This reverts commit 95769084ce.
2025-03-27 16:18:09 +01:00
6ef68f3681
make re-exports explicit again 2025-03-27 16:18:09 +01:00
6189ae28fa
deduplicate flake inputs 2025-03-27 16:18:09 +01:00
a6ad9533bb
tf 2025-03-27 16:18:09 +01:00
34 changed files with 945 additions and 34 deletions

View file

@ -43,7 +43,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

View file

@ -19,6 +19,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;
}; };

1
launch/.auto.tfvars.json Normal file
View file

@ -0,0 +1 @@
{"nixos-anywhere": "/nix/store/q68mw6lmjjhrvcrhb0pcm9i0v6m3v7cn-source"}

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

3
launch/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
# .terraform/
.terraform.tfstate.lock.info
terraform.tfstate*

16
launch/.terraform.lock.hcl generated Normal file
View file

@ -0,0 +1,16 @@
# This file is maintained automatically by "tofu init".
# Manual edits may be lost in future updates.
provider "registry.opentofu.org/hashicorp/external" {
version = "2.3.4"
hashes = [
"h1:HfVaWMC7Tz+tRfoWZtGCX2MATcgX3HsexoirWdi/voo=",
]
}
provider "registry.opentofu.org/hashicorp/null" {
version = "3.2.3"
hashes = [
"h1:qTlGDGC3RmXIPLgwsIh4LHG/DrAR6T6L+Wn6egnQnwE=",
]
}

View file

@ -0,0 +1 @@
{"Modules":[{"Key":"","Source":"","Dir":"."},{"Key":"peertube","Source":"./vm","Dir":"vm"},{"Key":"peertube.deploy","Source":"file:///nix/store/q68mw6lmjjhrvcrhb0pcm9i0v6m3v7cn-source//terraform/all-in-one","Dir":".terraform/modules/peertube.deploy/terraform/all-in-one"},{"Key":"peertube.deploy.install","Source":"../install","Dir":"/nix/store/q68mw6lmjjhrvcrhb0pcm9i0v6m3v7cn-source/terraform/install"},{"Key":"peertube.deploy.nixos-rebuild","Source":"../nixos-rebuild","Dir":"/nix/store/q68mw6lmjjhrvcrhb0pcm9i0v6m3v7cn-source/terraform/nixos-rebuild"},{"Key":"peertube.deploy.partitioner-build","Source":"../nix-build","Dir":"/nix/store/q68mw6lmjjhrvcrhb0pcm9i0v6m3v7cn-source/terraform/nix-build"},{"Key":"peertube.deploy.system-build","Source":"../nix-build","Dir":"/nix/store/q68mw6lmjjhrvcrhb0pcm9i0v6m3v7cn-source/terraform/nix-build"}]}

View file

@ -0,0 +1 @@
/nix/store/q68mw6lmjjhrvcrhb0pcm9i0v6m3v7cn-source

View file

@ -0,0 +1,3 @@
[
"/nix/store/mnqkwjg5v6sx86an34b4cn075h0lapz3-opentofu-1.8.7/libexec/terraform-providers"
]

View file

@ -0,0 +1 @@
/nix/store/mnqkwjg5v6sx86an34b4cn075h0lapz3-opentofu-1.8.7/libexec/terraform-providers/registry.opentofu.org/hashicorp/external/2.3.4/linux_amd64

View file

@ -0,0 +1 @@
/nix/store/mnqkwjg5v6sx86an34b4cn075h0lapz3-opentofu-1.8.7/libexec/terraform-providers/registry.opentofu.org/hashicorp/null/3.2.3/linux_amd64

19
launch/README.md Normal file
View file

@ -0,0 +1,19 @@
# service deployment
## usage
### updating TF modules
```sh
$ npins update nixos-anywhere
$ cd launch/
$ echo "{\"nixos-anywhere\": $(nix-instantiate --eval --json -E '(import ../npins).nixos-anywhere.outPath')}" > .auto.tfvars.json
```
### local development
```sh
$ nix-shell
$ rm -rf .terraform/
$ tofu init
```

31
launch/default.nix Normal file
View file

@ -0,0 +1,31 @@
{
system ? builtins.currentSystem,
sources ? import ../npins,
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;
in
{
shell = pkgs.mkShellNoCC {
packages = [
pkgs.npins
pkgs.jq # implicit dep of nixos-anywhere TF: https://github.com/nix-community/nixos-anywhere/issues/416
(import ./tf.nix { inherit lib pkgs; })
];
};
# re-export inputs so they can be overridden granularly
# (they can't be accessed from the outside any other way)
inherit
sources
system
pkgs
;
}

158
launch/flake.lock generated Normal file
View file

@ -0,0 +1,158 @@
{
"nodes": {
"agenix": {
"inputs": {
"darwin": "darwin",
"home-manager": "home-manager",
"nixpkgs": "nixpkgs",
"systems": "systems"
},
"locked": {
"lastModified": 1736955230,
"narHash": "sha256-uenf8fv2eG5bKM8C/UvFaiJMZ4IpUFaQxk9OH5t/1gA=",
"owner": "ryantm",
"repo": "agenix",
"rev": "e600439ec4c273cf11e06fe4d9d906fb98fa097c",
"type": "github"
},
"original": {
"owner": "ryantm",
"repo": "agenix",
"type": "github"
}
},
"darwin": {
"inputs": {
"nixpkgs": [
"agenix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1700795494,
"narHash": "sha256-gzGLZSiOhf155FW7262kdHo2YDeugp3VuIFb4/GGng0=",
"owner": "lnl7",
"repo": "nix-darwin",
"rev": "4b9b83d5a92e8c1fbfd8eb27eda375908c11ec4d",
"type": "github"
},
"original": {
"owner": "lnl7",
"ref": "master",
"repo": "nix-darwin",
"type": "github"
}
},
"disko": {
"inputs": {
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1741786315,
"narHash": "sha256-VT65AE2syHVj6v/DGB496bqBnu1PXrrzwlw07/Zpllc=",
"owner": "nix-community",
"repo": "disko",
"rev": "0d8c6ad4a43906d14abd5c60e0ffe7b587b213de",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "disko",
"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"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1703013332,
"narHash": "sha256-+tFNwMvlXLbJZXiMHqYq77z/RfmpfpiI3yjL6o/Zo9M=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "54aac082a4d9bb5bbc5c4e899603abfb76a3f6d6",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1741402956,
"narHash": "sha256-y2hByvBM03s9T2fpeLjW6iprbxnhV9mJMmSwCHc41ZQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ed0b1881565c1ffef490c10d663d4f542031dad3",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1743046730,
"narHash": "sha256-3ON6kKBQ4pz/IVZylcbw28K/Jm5cym4V/Z+VmPzR9/4=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "67545051fd77a131ebab477fbf2bb4d9473edd35",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "release-24.11",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"agenix": "agenix",
"disko": "disko",
"nixpkgs": "nixpkgs_3"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

125
launch/flake.nix Normal file
View file

@ -0,0 +1,125 @@
{
inputs = {
agenix.url = "github:ryantm/agenix";
disko.url = "github:nix-community/disko";
nixpkgs.url = "github:nixos/nixpkgs/release-24.11";
};
outputs =
inputs@{ nixpkgs, ... }:
let
system = "x86_64-linux";
inherit (nixpkgs) lib;
in
{
nixosConfigurations =
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
lib.mapAttrs
(
_: module:
lib.nixosSystem {
inherit system;
specialArgs = { inherit system inputs; };
modules = [
inputs.disko.nixosModules.default
inputs.agenix.nixosModules.default
../services/fediversity
./resource.nix
module
{
nixpkgs = { inherit system; };
}
(
{ pkgs, terraform, ... }:
let
inherit (terraform) hostname;
in
{
imports = [
# FIXME: get VM details from TF
../infra/test-machines/${hostname}
];
fediversityVm.name = hostname;
fediversity = {
inherit (terraform) domain;
temp.initialUser = {
inherit (terraform.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" terraform.initialUser.password;
};
};
}
)
];
}
)
{
garage =
{ pkgs, ... }:
{
fediversity = {
garage.enable = true;
pixelfed = pixelfedS3KeyConfig { inherit pkgs; };
mastodon = mastodonS3KeyConfig { inherit pkgs; };
peertube = peertubeS3KeyConfig { inherit pkgs; };
};
};
mastodon =
{ pkgs, ... }:
{
fediversity = {
mastodon = mastodonS3KeyConfig { inherit pkgs; } // {
enable = true;
};
temp.cores = 1; # FIXME: should come from NixOps4 eventually
};
};
peertube =
{ pkgs, ... }:
{
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";
};
};
};
pixelfed =
{ pkgs, ... }:
{
fediversity = {
pixelfed = pixelfedS3KeyConfig { inherit pkgs; } // {
enable = true;
};
};
};
};
};
}

37
launch/garage.nix Normal file
View file

@ -0,0 +1,37 @@
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
import ./shared.nix {
module =
{ pkgs, ... }:
{
fediversity = {
garage.enable = true;
pixelfed = pixelfedS3KeyConfig { inherit pkgs; };
mastodon = mastodonS3KeyConfig { inherit pkgs; };
peertube = peertubeS3KeyConfig { inherit pkgs; };
};
};
}

92
launch/main.tf Normal file
View file

@ -0,0 +1,92 @@
variable "nixos-anywhere" {
type = string
}
variable "domain" {
type = string
default = "fediversity.net"
}
variable "mastodon" {
type = object({
enable = bool
})
default = {
enable = false
}
}
variable "pixelfed" {
type = object({
enable = bool
})
default = {
enable = false
}
}
variable "peertube" {
type = object({
enable = bool
})
default = {
enable = false
}
}
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
})
default = {
displayName = "Testy McTestface"
username = "test"
email = "test@test.com"
password = "testtest"
}
}
# module "garage" {
# source = "./vm"
# count = var.mastodon.enable || var.pixelfed.enable || var.peertube.enable ? 1 : 0
# domain = var.domain
# hostname = "test01"
# config = "garage"
# initialUser = var.initialUser
# nixos-anywhere = var.nixos-anywhere
# }
module "mastodon" {
source = "./vm"
count = var.mastodon.enable ? 1 : 0
domain = var.domain
hostname = "test02"
config = "mastodon"
initialUser = var.initialUser
nixos-anywhere = var.nixos-anywhere
}
module "pixelfed" {
source = "./vm"
count = var.pixelfed.enable ? 1 : 0
domain = var.domain
hostname = "test04"
config = "pixelfed"
initialUser = var.initialUser
nixos-anywhere = var.nixos-anywhere
}
module "peertube" {
source = "./vm"
count = var.peertube.enable ? 1 : 0
domain = var.domain
hostname = "test03"
config = "peertube"
initialUser = var.initialUser
nixos-anywhere = var.nixos-anywhere
}

20
launch/mastodon.nix Normal file
View file

@ -0,0 +1,20 @@
let
mastodonS3KeyConfig =
{ pkgs, ... }:
{
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GK3515373e4c851ebaad366558";
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "7d37d093435a41f2aab8f13c19ba067d9776c90215f56614adad6ece597dbb34";
};
in
import ./shared.nix {
module =
{ pkgs, ... }:
{
fediversity = {
mastodon = mastodonS3KeyConfig { inherit pkgs; } // {
enable = true;
};
temp.cores = 1; # FIXME: should come from NixOps4 eventually
};
};
}

15
launch/pass-ssh-key.sh Executable file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env bash
export host="$host"
mkdir -p etc/ssh
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
for keyname in ssh_host_ed25519_key ssh_host_ed25519_key.pub; do
if [[ $keyname == *.pub ]]; then
umask 0133
else
umask 0177
fi
cp "$SCRIPT_DIR/../infra/test-machines/${host}/${keyname}" ./etc/ssh/${keyname}
done

23
launch/peertube.nix Normal file
View file

@ -0,0 +1,23 @@
let
peertubeS3KeyConfig =
{ pkgs, ... }:
{
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GK1f9feea9960f6f95ff404c9b";
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "7295c4201966a02c2c3d25b5cea4a5ff782966a2415e3a196f91924631191395";
};
in
import ./shared.nix {
module =
{ pkgs, ... }:
{
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";
};
};
};
}

19
launch/pixelfed.nix Normal file
View file

@ -0,0 +1,19 @@
let
pixelfedS3KeyConfig =
{ pkgs, ... }:
{
s3AccessKeyFile = pkgs.writeText "s3AccessKey" "GKb5615457d44214411e673b7b";
s3SecretKeyFile = pkgs.writeText "s3SecretKey" "5be6799a88ca9b9d813d1a806b64f15efa49482dbe15339ddfaf7f19cf434987";
};
in
import ./shared.nix {
module =
{ pkgs, ... }:
{
fediversity = {
pixelfed = pixelfedS3KeyConfig { inherit pkgs; } // {
enable = true;
};
};
};
}

41
launch/resource.nix Normal file
View file

@ -0,0 +1,41 @@
{
lib,
config,
...
}:
let
inherit (lib) attrValues elem mkDefault;
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.hostPublicKey secret.publicKeys) {
${removeSuffix ".age" name}.file = secretsPrefix + "/${name}";
}
) secrets;
## FIXME: Remove direct root authentication once the NixOps4 NixOS provider
## supports users with password-less sudo.
users.users.root.openssh.authorizedKeys.keys = attrValues keys.contributors;
}

45
launch/shared.nix Normal file
View file

@ -0,0 +1,45 @@
{
system ? "x86_64-linux",
sources ? import ../npins,
pkgs ? import sources.nixpkgs {
inherit system;
config = { };
overlays = [ (import ../panel/nix/overlay.nix) ];
},
module,
...
}:
import "${sources.nixpkgs}/nixos/lib/eval-config.nix" {
modules = [
"${sources.disko}/module.nix"
"${sources.agenix}/modules/age.nix"
../services/fediversity
./resource.nix
# FIXME: get VM details from TF
module
(
{
terraform,
...
}:
let
inherit (terraform) hostname;
in
{
imports = [
../infra/test-machines/${hostname}
];
fediversityVm.name = hostname;
fediversity = {
inherit (terraform) domain;
temp.initialUser = {
inherit (terraform.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" terraform.initialUser.password;
};
};
}
)
];
}

1
launch/shell.nix Normal file
View file

@ -0,0 +1 @@
(import ./. { }).shell

36
launch/tf-env.nix Normal file
View file

@ -0,0 +1,36 @@
{
lib,
pkgs,
sources ? import ../npins,
...
}:
pkgs.stdenv.mkDerivation {
name = "tf-repo";
src = ../.;
buildInputs = [
(import ./tf.nix { inherit lib pkgs; })
];
buildPhase = ''
runHook preBuild
pushd launch/
# pass nixos-anywhere path to TF through variable
# when switching TF to nix take this directly from `inputs`
# https://codeberg.org/kiara/e2ed-hetzner/commit/84b2a349d3e48ea2a17340bceff762d834fd4046
# echo "{\"nixos-anywhere\": \"${sources.nixos-anywhere}\"}" > .auto.tfvars.json
# point to the relevant providers
# tofu init -input=false
popd
runHook postBuild
'';
# FIXME: can the above even work without a connection?
installPhase = ''
runHook preInstall
cp -r . $out
runHook postInstall
'';
}

25
launch/tf.nix Normal file
View file

@ -0,0 +1,25 @@
# 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.null
p.external
]
);
in
# tf.withPlugins tfPlugins
# https://github.com/NixOS/nixpkgs/pull/358522
tf.withPlugins (p: pkgs.lib.lists.map tofuProvider (tfPlugins p))

51
launch/vm/main.tf Normal file
View file

@ -0,0 +1,51 @@
variable "nixos-anywhere" {
type = string
}
variable "domain" {
type = string
}
variable "hostname" {
type = string
}
variable "config" {
type = string
}
variable "initialUser" {
type = object({
displayName = string
username = string
password = string
email = string
})
}
module "deploy" {
# source = "github.com/nix-community/nixos-anywhere//terraform/all-in-one"
source = "${var.nixos-anywhere}//terraform/all-in-one"
file = "${path.module}/../${var.config}.nix"
nixos_system_attr = "config.system.build.toplevel"
nixos_partitioner_attr = "config.system.build.diskoScript"
# when instance id changes, it will trigger a reinstall
instance_id = var.hostname
target_user = "kiara"
target_host = "${var.hostname}.abundos.eu"
extra_files_script = "${path.module}/../pass-ssh-key.sh"
extra_environment = {
host = var.hostname
}
special_args = {
terraform = {
domain = var.domain
hostname = var.hostname
initialUser = var.initialUser
}
}
nix_options = {
show-trace = true
}
# build_on_remote = true
}

View file

@ -1,5 +1,44 @@
{ {
"pins": { "pins": {
"agenix": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "ryantm",
"repo": "agenix"
},
"branch": "main",
"revision": "e600439ec4c273cf11e06fe4d9d906fb98fa097c",
"url": "https://github.com/ryantm/agenix/archive/e600439ec4c273cf11e06fe4d9d906fb98fa097c.tar.gz",
"hash": "006ngydiykjgqs85cl19h9klq8kaqm5zs0ng51dnwy7nzgqxzsdr"
},
"disko": {
"type": "GitRelease",
"repository": {
"type": "GitHub",
"owner": "nix-community",
"repo": "disko"
},
"pre_releases": false,
"version_upper_bound": null,
"release_prefix": null,
"version": "v1.11.0",
"revision": "cdf8deded8813edfa6e65544f69fdd3a59fa2bb4",
"url": "https://api.github.com/repos/nix-community/disko/tarball/v1.11.0",
"hash": "13brimg7z7k9y36n4jc1pssqyw94nd8qvgfjv53z66lv4xkhin92"
},
"flake-inputs": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "fricklerhandwerk",
"repo": "flake-inputs"
},
"branch": "main",
"revision": "559574c9cbb8af262f3944b67d60fbf0f6ad03c3",
"url": "https://github.com/fricklerhandwerk/flake-inputs/archive/559574c9cbb8af262f3944b67d60fbf0f6ad03c3.tar.gz",
"hash": "0gbhmp6x2vdzvfnsvqzal3g8f8hx2ia6r73aibc78kazf78m67x6"
},
"htmx": { "htmx": {
"type": "GitRelease", "type": "GitRelease",
"repository": { "repository": {
@ -27,6 +66,18 @@
"url": "https://github.com/nix-community/nix-unit/archive/2071bbb765681ac3d8194ec560c8b27ff2a3b541.tar.gz", "url": "https://github.com/nix-community/nix-unit/archive/2071bbb765681ac3d8194ec560c8b27ff2a3b541.tar.gz",
"hash": "0blz1kcmn9vnr9q3iqp2mv13hv3pdccljmmc54f8j7ybf5v0wgmp" "hash": "0blz1kcmn9vnr9q3iqp2mv13hv3pdccljmmc54f8j7ybf5v0wgmp"
}, },
"nixos-anywhere": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "KiaraGrouwstra",
"repo": "nixos-anywhere"
},
"branch": "special-args-nested-flake-fixed",
"revision": "6986a78788d9b32354ab11b3881edf0caf1ae727",
"url": "https://github.com/KiaraGrouwstra/nixos-anywhere/archive/6986a78788d9b32354ab11b3881edf0caf1ae727.tar.gz",
"hash": "13j1l8dj9w22ch5z3iyzx5z6hrrx6c75m5gnkpa4d4wgiznx90r9"
},
"nixpkgs": { "nixpkgs": {
"type": "Channel", "type": "Channel",
"name": "nixpkgs-unstable", "name": "nixpkgs-unstable",

View file

@ -20,10 +20,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 = ''
ln -sf ${sources.htmx}/dist/htmx.js src/panel/static/htmx.min.js ln -sf ${sources.htmx}/dist/htmx.js src/panel/static/htmx.min.js

View file

@ -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.jq # implicit dep of nixos-anywhere TF: https://github.com/nix-community/nixos-anywhere/issues/416
(import ../launch/tf.nix { inherit lib pkgs; })
]; ];
} }

View file

@ -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 (

View file

@ -1,5 +1,6 @@
{ {
lib, lib,
pkgs,
sqlite, sqlite,
python3, python3,
sources ? import ../../npins, sources ? import ../../npins,
@ -11,7 +12,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
@ -58,7 +59,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"
cp ${sources.htmx}/dist/htmx.min.js* $out/${python3.sitePackages}/panel/static/ cp ${sources.htmx}/dist/htmx.min.js* $out/${python3.sitePackages}/panel/static/
''; '';
} }

View file

@ -10,7 +10,9 @@ For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/ https://docs.djangoproject.com/en/4.2/ref/settings/
""" """
import re
import sys import sys
import subprocess
import os import os
import importlib.util import importlib.util
import dj_database_url import dj_database_url
@ -18,6 +20,8 @@ import dj_database_url
from os import environ as env from os import environ as env
from pathlib import Path from pathlib import Path
STORE_PATTERN = re.compile("^/nix/store/[^/]+$")
# Build paths inside the project like this: BASE_DIR / 'subdir'. # Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent BASE_DIR = Path(__file__).resolve().parent.parent
@ -171,6 +175,54 @@ COMPRESS_PRECOMPILERS = [
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"filters": {
"require_debug_false": {
"()": "django.utils.log.RequireDebugFalse",
},
"require_debug_true": {
"()": "django.utils.log.RequireDebugTrue",
},
},
"formatters": {
"django.server": {
"()": "django.utils.log.ServerFormatter",
"format": "[{server_time}] {message}",
"style": "{",
}
},
"handlers": {
"console": {
"level": "INFO",
# "filters": ["require_debug_true"],
"class": "logging.StreamHandler",
},
"django.server": {
"level": "INFO",
"class": "logging.StreamHandler",
"formatter": "django.server",
},
"mail_admins": {
"level": "ERROR",
"filters": ["require_debug_false"],
"class": "django.utils.log.AdminEmailHandler",
},
},
"loggers": {
"django": {
"handlers": ["console", "mail_admins"],
"level": "INFO",
},
"django.server": {
"handlers": ["django.server"],
"level": "INFO",
"propagate": False,
},
},
}
# Customization via user settings # Customization via user settings
# This must be at the end, as it must be able to override the above # This must be at the end, as it must be able to override the above
# TODO(@fricklerhandwerk): # TODO(@fricklerhandwerk):

View file

@ -1,5 +1,6 @@
from enum import Enum from enum import Enum
import json import json
from os.path import expanduser
import subprocess import subprocess
import os import os
@ -114,25 +115,27 @@ class DeploymentStatus(ConfigurationForm):
}, },
} }
# serialize back and forth now we still need to manually inject the dummy user # serialize back and forth now we still need to manually inject the dummy user
deployment = json.dumps(dummy_user | json.loads(submission)) deployment = dummy_user | json.loads(submission)
env = { env = {
"PATH": settings.bin_path, "PATH": settings.bin_path,
# used in nixos-anywhere for ssh-copy-id
"HOME": expanduser("~"),
"XDG_CACHE_HOME": "/tmp",
} | {
# pass in form info to our deployment # pass in form info to our deployment
"DEPLOYMENT": deployment, # FIXME: ensure sensitive info is protected
f"TF_VAR_{k}": v if isinstance(v, str) else json.dumps(v) for k, v in deployment.items()
} }
cwd = f"{settings.repo_dir}/launch"
# FIXME: move init to packaging phase
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",
] ]
deployment_result = subprocess.run( deployment_result = subprocess.run(cmd, cwd=cwd, env=env)
cmd, print(deployment_result)
cwd=settings.repo_dir,
env=env,
)
return deployment_result return deployment_result