Compare commits

..

10 commits

81 changed files with 786 additions and 1127 deletions

View file

@ -1,25 +0,0 @@
name: cache-build
on:
workflow_dispatch: # allows manual triggering
push:
branches:
# - main
jobs:
deploy:
runs-on: native
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Cache
run: |
nix-shell --run "attic login fediversity https://attic.fediversity.net '${{ secrets.ATTIC_PUSH_KEY }}' && attic use demo"
env
mkdir -p ~/.ssh
echo "${{ secrets.CD_SSH_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
cat ~/.config/attic/config.toml
cat ~/.config/nix/nix.conf
nix-shell --run "attic push demo $(nix-build)"

View file

@ -1,24 +0,0 @@
name: deploy-infra
on:
workflow_dispatch: # allows manual triggering
push:
branches:
- main
jobs:
deploy:
runs-on: native
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up SSH key for age secrets and SSH
run: |
env
mkdir -p ~/.ssh
echo "${{ secrets.CD_SSH_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
- name: Deploy
run: nix-shell --run 'eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_ed25519 && SHELL=$(which bash) nixops4 apply -v default'

View file

@ -21,36 +21,17 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: nix-shell --run 'nix-unit ./deployment/data-model-test.nix' - run: nix-shell --run 'nix-unit ./deployment/data-model-test.nix'
- name: Cache
run: |
nix-shell --run "attic login fediversity https://attic.fediversity.net '${{ secrets.ATTIC_PUSH_KEY }}' && attic use demo"
env
mkdir -p ~/.ssh
echo "${{ secrets.CD_SSH_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
cat ~/.config/attic/config.toml
cat ~/.config/nix/nix.conf
echo "RUNNER_DEBUG: ${{ secrets.RUNNER_DEBUG }}"
echo "GIT_TRACE: ${{ secrets.GIT_TRACE }}"
nix-shell --run "attic push demo $(nix-build)"
check-mastodon:
runs-on: native
steps:
- uses: actions/checkout@v4
- run: nix build .#checks.x86_64-linux.test-mastodon-service -L
check-peertube: check-peertube:
runs-on: native runs-on: native
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: nix build .#checks.x86_64-linux.test-peertube-service -L - run: nix-build services -A tests.peertube
check-panel: check-panel:
runs-on: native runs-on: native
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: nix-build -A tests.panel - run: nix-build panel -A tests
check-deployment-basic: check-deployment-basic:
runs-on: native runs-on: native
@ -69,29 +50,3 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- run: nix build .#checks.x86_64-linux.deployment-panel -L - run: nix build .#checks.x86_64-linux.deployment-panel -L
## NOTE: NixOps4 does not provide a good “dry run” mode, so we instead check
## proxies for resources, namely whether their `.#vmOptions.<machine>` and
## `.#nixosConfigurations.<machine>` outputs evaluate and build correctly, and
## whether we can dry run `infra/proxmox-*.sh` on them. This will not catch
## everything, and in particular not issues in how NixOps4 wires up the
## resources, but that is still something.
check-resources:
runs-on: native
steps:
- uses: actions/checkout@v4
- run: |
set -euC
echo ==================== [ VM Options ] ====================
machines=$(nix eval --impure --raw --expr 'with builtins; toString (attrNames (getFlake (toString ./.)).vmOptions)')
for machine in $machines; do
echo ~~~~~~~~~~~~~~~~~~~~~: $machine :~~~~~~~~~~~~~~~~~~~~~
nix build .#checks.x86_64-linux.vmOptions-$machine
done
echo
echo ==================== [ NixOS Configurations ] ====================
machines=$(nix eval --impure --raw --expr 'with builtins; toString (attrNames (getFlake (toString ./.)).nixosConfigurations)')
for machine in $machines; do
echo ~~~~~~~~~~~~~~~~~~~~~: $machine :~~~~~~~~~~~~~~~~~~~~~
nix build .#checks.x86_64-linux.nixosConfigurations-$machine
done

View file

@ -13,11 +13,10 @@ jobs:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Update pins - name: Update pins
run: nix-shell --run "npins --verbose update" run: nix-shell --run "npins update"
- name: Create PR - name: Create PR
uses: https://github.com/KiaraGrouwstra/gitea-create-pull-request@f9f80aa5134bc5c03c38f5aaa95053492885b397 uses: peter-evans/create-pull-request@v7
with: with:
remote-instance-api-version: v1
token: "${{ secrets.DEPLOY_KEY }}" token: "${{ secrets.DEPLOY_KEY }}"
branch: npins-update branch: npins-update
commit-message: "npins: update sources" commit-message: "npins: update sources"

View file

@ -12,7 +12,6 @@ let
inherit (pkgs) lib; inherit (pkgs) lib;
inherit (import sources.flake-inputs) import-flake; inherit (import sources.flake-inputs) import-flake;
inherit ((import-flake { src = ./.; }).inputs) nixops4; inherit ((import-flake { src = ./.; }).inputs) nixops4;
panel = import ./panel { inherit sources system; };
pre-commit-check = pre-commit-check =
(import "${git-hooks}/nix" { (import "${git-hooks}/nix" {
inherit nixpkgs system; inherit nixpkgs system;
@ -65,7 +64,6 @@ in
pkgs.httpie pkgs.httpie
pkgs.jq pkgs.jq
pkgs.nix-unit pkgs.nix-unit
pkgs.attic-client
test-loop test-loop
nixops4.packages.${system}.default nixops4.packages.${system}.default
]; ];
@ -73,7 +71,6 @@ in
tests = { tests = {
inherit pre-commit-check; inherit pre-commit-check;
panel = panel.tests;
}; };
# re-export inputs so they can be overridden granularly # re-export inputs so they can be overridden granularly

View file

@ -1,8 +0,0 @@
{
targetMachines = [
"hello"
"cowsay"
];
pathToRoot = ../../..;
pathFromRoot = ./.;
}

View file

@ -1,14 +0,0 @@
{
runNixOSTest,
inputs,
sources,
}:
runNixOSTest {
imports = [
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
inherit (import ./constants.nix) targetMachines pathToRoot pathFromRoot;
}

View file

@ -1,36 +0,0 @@
{
inputs,
sources,
lib,
providers,
...
}:
let
inherit (import ./constants.nix) targetMachines pathToRoot pathFromRoot;
in
{
providers = {
inherit (inputs.nixops4.modules.nixops4Provider) local;
};
resources = lib.genAttrs targetMachines (nodeName: {
type = providers.local.exec;
imports = [
inputs.nixops4-nixos.modules.nixops4Resource.nixos
../common/targetResource.nix
];
_module.args = { inherit inputs sources; };
inherit nodeName pathToRoot pathFromRoot;
nixos.module =
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.${nodeName} ];
};
});
}

View file

@ -0,0 +1,57 @@
{
self,
inputs,
lib,
sources,
...
}:
let
inherit (lib) genAttrs;
targetMachines = [
"hello"
"cowsay"
];
pathToRoot = /. + (builtins.unsafeDiscardStringContext self);
pathFromRoot = ./.;
in
{
_class = "flake";
perSystem =
{ pkgs, ... }:
{
checks.deployment-basic = pkgs.testers.runNixOSTest {
imports = [
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
inherit targetMachines pathToRoot pathFromRoot;
};
};
nixops4Deployments.check-deployment-basic =
{ providers, ... }:
{
providers = {
inherit (inputs.nixops4.modules.nixops4Provider) local;
};
resources = genAttrs targetMachines (nodeName: {
type = providers.local.exec;
imports = [
inputs.nixops4-nixos.modules.nixops4Resource.nixos
../common/targetResource.nix
];
_module.args = { inherit inputs sources; };
inherit nodeName pathToRoot pathFromRoot;
nixos.module =
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.${nodeName} ];
};
});
};
}

View file

@ -1,22 +0,0 @@
{
inputs = {
nixops4.follows = "nixops4-nixos/nixops4";
nixops4-nixos.url = "github:nixops4/nixops4-nixos";
};
outputs =
inputs:
import ./mkFlake.nix inputs (
{ inputs, sources, ... }:
{
imports = [
inputs.nixops4.modules.flake.default
];
nixops4Deployments.check-deployment-basic = {
imports = [ ./deployment/check/basic/deployment.nix ];
_module.args = { inherit inputs sources; };
};
}
);
}

View file

@ -1,15 +1,10 @@
{ inputs, lib, ... }: { inputs, ... }:
{ {
_class = "nixosTest"; _class = "nixosTest";
name = "deployment-basic"; name = "deployment-basic";
sourceFileset = lib.fileset.unions [
./constants.nix
./deployment.nix
];
nodes.deployer = nodes.deployer =
{ pkgs, ... }: { pkgs, ... }:
{ {

View file

@ -1,12 +0,0 @@
{
targetMachines = [
"garage"
"mastodon"
"peertube"
"pixelfed"
"attic"
];
pathToRoot = ../../..;
pathFromRoot = ./.;
enableAcme = true;
}

View file

@ -1,19 +0,0 @@
{
runNixOSTest,
inputs,
sources,
}:
runNixOSTest {
imports = [
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
inherit (import ./constants.nix)
targetMachines
pathToRoot
pathFromRoot
enableAcme
;
}

View file

@ -1,59 +0,0 @@
{
inputs,
sources,
lib,
}:
let
inherit (builtins) fromJSON readFile listToAttrs;
inherit (import ./constants.nix)
targetMachines
pathToRoot
pathFromRoot
enableAcme
;
makeTargetResource = nodeName: {
imports = [ ../common/targetResource.nix ];
_module.args = { inherit inputs sources; };
inherit
nodeName
pathToRoot
pathFromRoot
enableAcme
;
};
## The deployment function - what we are here to test!
##
## TODO: Modularise `deployment/default.nix` to get rid of the nested
## function calls.
makeTestDeployment =
args:
(import ../..)
{
inherit lib;
inherit (inputs) nixops4 nixops4-nixos;
fediversity = import ../../../services/fediversity;
}
(listToAttrs (
map (nodeName: {
name = "${nodeName}ConfigurationResource";
value = makeTargetResource nodeName;
}) targetMachines
))
(fromJSON (readFile ../../configuration.sample.json) // args);
in
{
check-deployment-cli-nothing = makeTestDeployment { };
check-deployment-cli-mastodon-pixelfed = makeTestDeployment {
mastodon.enable = true;
pixelfed.enable = true;
};
check-deployment-cli-peertube = makeTestDeployment {
peertube.enable = true;
};
}

View file

@ -0,0 +1,95 @@
{
self,
inputs,
lib,
sources,
...
}:
let
inherit (builtins) fromJSON readFile listToAttrs;
targetMachines = [
"garage"
"mastodon"
"peertube"
"pixelfed"
"attic"
];
pathToRoot = /. + (builtins.unsafeDiscardStringContext self);
pathFromRoot = ./.;
enableAcme = true;
in
{
_class = "flake";
perSystem =
{ pkgs, ... }:
{
checks.deployment-cli = pkgs.testers.runNixOSTest {
imports = [
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
inherit
targetMachines
pathToRoot
pathFromRoot
enableAcme
;
};
};
nixops4Deployments =
let
makeTargetResource = nodeName: {
imports = [ ../common/targetResource.nix ];
_module.args = { inherit inputs sources; };
inherit
nodeName
pathToRoot
pathFromRoot
enableAcme
;
};
## The deployment function - what we are here to test!
##
## TODO: Modularise `deployment/default.nix` to get rid of the nested
## function calls.
makeTestDeployment =
args:
(import ../..)
{
inherit lib;
inherit (inputs) nixops4 nixops4-nixos;
fediversity = import ../../../services/fediversity;
}
(listToAttrs (
map (nodeName: {
name = "${nodeName}ConfigurationResource";
value = makeTargetResource nodeName;
}) targetMachines
))
(fromJSON (readFile ../../configuration.sample.json) // args);
in
{
check-deployment-cli-nothing = makeTestDeployment {
attic.enable = true;
};
check-deployment-cli-mastodon-pixelfed = makeTestDeployment {
mastodon.enable = true;
pixelfed.enable = true;
attic.enable = true;
};
check-deployment-cli-peertube = makeTestDeployment {
peertube.enable = true;
attic.enable = true;
};
};
}

View file

@ -1,26 +0,0 @@
{
inputs = {
nixops4.follows = "nixops4-nixos/nixops4";
nixops4-nixos.url = "github:nixops4/nixops4-nixos";
};
outputs =
inputs:
import ./mkFlake.nix inputs (
{
inputs,
sources,
lib,
...
}:
{
imports = [
inputs.nixops4.modules.flake.default
];
nixops4Deployments = import ./deployment/check/cli/deployments.nix {
inherit inputs sources lib;
};
}
);
}

View file

@ -1,9 +1,4 @@
{ { inputs, hostPkgs, ... }:
inputs,
hostPkgs,
lib,
...
}:
let let
## Some places need a dummy file that will in fact never be used. We create ## Some places need a dummy file that will in fact never be used. We create
@ -16,21 +11,6 @@ in
name = "deployment-cli"; name = "deployment-cli";
sourceFileset = lib.fileset.unions [
./constants.nix
./deployments.nix
# REVIEW: I would like to be able to grab all of `/deployment` minus
# `/deployment/check`, but I can't because there is a bunch of other files
# in `/deployment`. Maybe we can think of a reorg making things more robust
# here? (comment also in panel test)
../../default.nix
../../options.nix
../../configuration.sample.json
../../../services/fediversity
];
nodes.deployer = nodes.deployer =
{ pkgs, ... }: { pkgs, ... }:
{ {
@ -45,8 +25,8 @@ in
peertube.inputDerivation peertube.inputDerivation
gixy gixy
gixy.inputDerivation gixy.inputDerivation
shellcheck pkgs.acl
shellcheck.inputDerivation pkgs.attr
]; ];
system.extraDependenciesFromModule = { system.extraDependenciesFromModule = {

View file

@ -54,19 +54,20 @@ in
system.extraDependencies = system.extraDependencies =
[ [
inputs.flake-parts
inputs.flake-parts.inputs.nixpkgs-lib
inputs.nixops4 inputs.nixops4
inputs.nixops4-nixos inputs.nixops4-nixos
inputs.nixpkgs inputs.nixpkgs
sources.flake-parts
sources.nixpkgs sources.nixpkgs
sources.flake-inputs sources.flake-inputs
sources.git-hooks
sources.vars sources.vars
sources.nix-templating sources.nix-templating
pkgs.stdenv pkgs.stdenv
pkgs.stdenvNoCC pkgs.stdenvNoCC
pkgs.acl
pkgs.attr
] ]
++ ( ++ (
let let

View file

@ -13,7 +13,6 @@ let
toJSON toJSON
; ;
inherit (lib) inherit (lib)
types
fileset fileset
mkOption mkOption
genAttrs genAttrs
@ -28,6 +27,14 @@ let
forConcat = xs: f: concatStringsSep "\n" (map f xs); forConcat = xs: f: concatStringsSep "\n" (map f xs);
## The whole repository, with the flake at its root.
## 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;
};
## We will need to override some inputs by the empty flake, so we make one. ## We will need to override some inputs by the empty flake, so we make one.
emptyFlake = runCommandNoCC "empty-flake" { } '' emptyFlake = runCommandNoCC "empty-flake" { } ''
mkdir $out mkdir $out
@ -46,40 +53,9 @@ in
## FIXME: I wish I could just use `testScript` but with something like ## FIXME: I wish I could just use `testScript` but with something like
## `mkOrder` to put this module's string before something else. ## `mkOrder` to put this module's string before something else.
extraTestScript = mkOption { }; extraTestScript = mkOption { };
sourceFileset = mkOption {
## FIXME: grab `lib.types.fileset` from NixOS, once upstreaming PR
## https://github.com/NixOS/nixpkgs/pull/428293 lands.
type = types.mkOptionType {
name = "fileset";
description = "fileset";
descriptionClass = "noun";
check = (x: (builtins.tryEval (fileset.unions [ x ])).success);
merge = (_: defs: fileset.unions (map (x: x.value) defs));
};
description = ''
A fileset that will be copied to the deployer node in the current
working directory. This should contain all the files that are
necessary to run that particular test, such as the NixOS
modules necessary to evaluate a deployment.
'';
};
}; };
config = { config = {
sourceFileset = fileset.unions [
# NOTE: not the flake itself; it will be overridden.
../../../mkFlake.nix
../../../flake.lock
../../../npins
./sharedOptions.nix
./targetNode.nix
./targetResource.nix
(config.pathToCwd + "/flake-under-test.nix")
];
acmeNodeIP = config.nodes.acme.networking.primaryIPAddress; acmeNodeIP = config.nodes.acme.networking.primaryIPAddress;
nodes = nodes =
@ -127,16 +103,8 @@ in
${n}.wait_for_unit("multi-user.target") ${n}.wait_for_unit("multi-user.target")
'')} '')}
## A subset of the repository that is necessary for this test. It will be
## copied inside the test. The smaller this set, the faster our CI, because we
## won't need to re-run when things change outside of it.
with subtest("Unpacking"): with subtest("Unpacking"):
deployer.succeed("cp -r --no-preserve=mode ${ deployer.succeed("cp -r --no-preserve=mode ${src}/* .")
fileset.toSource {
root = ../../..;
fileset = config.sourceFileset;
}
}/* .")
with subtest("Configure the network"): with subtest("Configure the network"):
${forConcat config.targetMachines ( ${forConcat config.targetMachines (
@ -166,16 +134,11 @@ in
## NOTE: This is super slow. It could probably be optimised in Nix, for ## 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. ## instance by allowing to grab things directly from the host's store.
## with subtest("Override the lock"):
## NOTE: We use the repository as-is (cf `src` above), overriding only
## `flake.nix` by our `flake-under-test.nix`. We also override the flake
## lock file to use locally available inputs, as we cannot download them.
##
with subtest("Override the flake and its lock"):
deployer.succeed("cp ${config.pathFromRoot}/flake-under-test.nix flake.nix")
deployer.succeed(""" deployer.succeed("""
nix flake lock --extra-experimental-features 'flakes nix-command' \ nix flake lock --extra-experimental-features 'flakes nix-command' \
--offline -v \ --offline -v \
--override-input flake-parts ${inputs.flake-parts} \
--override-input nixops4 ${inputs.nixops4.packages.${system}.flake-in-a-bottle} \ --override-input nixops4 ${inputs.nixops4.packages.${system}.flake-in-a-bottle} \
\ \
--override-input nixops4-nixos ${inputs.nixops4-nixos} \ --override-input nixops4-nixos ${inputs.nixops4-nixos} \
@ -187,6 +150,9 @@ in
inputs.nixops4-nixos.inputs.nixops4.packages.${system}.flake-in-a-bottle inputs.nixops4-nixos.inputs.nixops4.packages.${system}.flake-in-a-bottle
} \ } \
--override-input nixops4-nixos/git-hooks-nix ${emptyFlake} \ --override-input nixops4-nixos/git-hooks-nix ${emptyFlake} \
\
--override-input nixpkgs ${inputs.nixpkgs} \
--override-input git-hooks ${inputs.git-hooks} \
; ;
""") """)

View file

@ -1,12 +0,0 @@
{
targetMachines = [
"garage"
"mastodon"
"peertube"
"pixelfed"
"attic"
];
pathToRoot = ../../..;
pathFromRoot = ./.;
enableAcme = true;
}

View file

@ -1,19 +0,0 @@
{
runNixOSTest,
inputs,
sources,
}:
runNixOSTest {
imports = [
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
inherit (import ./constants.nix)
targetMachines
pathToRoot
pathFromRoot
enableAcme
;
}

View file

@ -1,58 +0,0 @@
{
inputs,
sources,
lib,
}:
let
inherit (builtins) fromJSON listToAttrs;
inherit (import ./constants.nix)
targetMachines
pathToRoot
pathFromRoot
enableAcme
;
makeTargetResource = nodeName: {
imports = [ ../common/targetResource.nix ];
_module.args = { inherit inputs sources; };
inherit
nodeName
pathToRoot
pathFromRoot
enableAcme
;
};
## The deployment function - what we are here to test!
##
## TODO: Modularise `deployment/default.nix` to get rid of the nested
## function calls.
makeTestDeployment =
args:
(import ../..)
{
inherit lib;
inherit (inputs) nixops4 nixops4-nixos;
fediversity = import ../../../services/fediversity;
}
(listToAttrs (
map (nodeName: {
name = "${nodeName}ConfigurationResource";
value = makeTargetResource nodeName;
}) targetMachines
))
args;
in
makeTestDeployment (
fromJSON (
let
env = builtins.getEnv "DEPLOYMENT";
in
if env == "" then
throw "The DEPLOYMENT environment needs to be set. You do not want to use this deployment unless in the `deployment-panel` NixOS test."
else
env
)
)

View file

@ -0,0 +1,95 @@
{
self,
inputs,
lib,
sources,
...
}:
let
inherit (builtins)
fromJSON
listToAttrs
;
targetMachines = [
"garage"
"mastodon"
"peertube"
"pixelfed"
"attic"
];
pathToRoot = /. + (builtins.unsafeDiscardStringContext self);
pathFromRoot = ./.;
enableAcme = true;
in
{
_class = "flake";
perSystem =
{ pkgs, ... }:
{
checks.deployment-panel = pkgs.testers.runNixOSTest {
imports = [
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
inherit
targetMachines
pathToRoot
pathFromRoot
enableAcme
;
};
};
nixops4Deployments =
let
makeTargetResource = nodeName: {
imports = [ ../common/targetResource.nix ];
_module.args = { inherit inputs sources; };
inherit
nodeName
pathToRoot
pathFromRoot
enableAcme
;
};
## The deployment function - what we are here to test!
##
## TODO: Modularise `deployment/default.nix` to get rid of the nested
## function calls.
makeTestDeployment =
args:
(import ../..)
{
inherit lib;
inherit (inputs) nixops4 nixops4-nixos;
fediversity = import ../../../services/fediversity;
}
(listToAttrs (
map (nodeName: {
name = "${nodeName}ConfigurationResource";
value = makeTargetResource nodeName;
}) targetMachines
))
args;
in
{
check-deployment-panel = makeTestDeployment (
fromJSON (
let
env = builtins.getEnv "DEPLOYMENT";
in
if env == "" then
throw "The DEPLOYMENT environment needs to be set. You do not want to use this deployment unless in the `deployment-panel` NixOS test."
else
env
)
);
};
}

View file

@ -1,26 +0,0 @@
{
inputs = {
nixops4.follows = "nixops4-nixos/nixops4";
nixops4-nixos.url = "github:nixops4/nixops4-nixos";
};
outputs =
inputs:
import ./mkFlake.nix inputs (
{
inputs,
sources,
lib,
...
}:
{
imports = [
inputs.nixops4.modules.flake.default
];
nixops4Deployments.check-deployment-panel = import ./deployment/check/panel/deployment.nix {
inherit inputs sources lib;
};
}
);
}

View file

@ -127,20 +127,6 @@ in
name = "deployment-panel"; name = "deployment-panel";
sourceFileset = lib.fileset.unions [
./constants.nix
./deployment.nix
# REVIEW: I would like to be able to grab all of `/deployment` minus
# `/deployment/check`, but I can't because there is a bunch of other files
# in `/deployment`. Maybe we can think of a reorg making things more robust
# here? (comment also in CLI test)
../../default.nix
../../options.nix
../../../services/fediversity
];
## The panel's module sets `nixpkgs.overlays` which clashes with ## The panel's module sets `nixpkgs.overlays` which clashes with
## `pkgsReadOnly`. We disable it here. ## `pkgsReadOnly`. We disable it here.
node.pkgsReadOnly = false; node.pkgsReadOnly = false;

View file

@ -1,9 +1,9 @@
{ {
"domain": "fediversity.net", "domain": "fediversity.net",
"mastodon": { "enable": false }, "mastodon": { "enable": true },
"peertube": { "enable": false }, "peertube": { "enable": true },
"pixelfed": { "enable": false }, "pixelfed": { "enable": true },
"attic": { "enable": false }, "attic": { "enable": true },
"initialUser": { "initialUser": {
"displayName": "Testy McTestface", "displayName": "Testy McTestface",
"username": "test", "username": "test",

View file

@ -1,13 +1,9 @@
let let
inherit (import ../default.nix { }) pkgs inputs; inherit (import ../default.nix { }) pkgs;
inherit (pkgs) lib; inherit (pkgs) lib;
inherit (lib) mkOption;
eval = eval =
module: module:
(lib.evalModules { (lib.evalModules {
specialArgs = {
inherit inputs;
};
modules = [ modules = [
module module
./data-model.nix ./data-model.nix
@ -20,51 +16,32 @@ in
test-eval = { test-eval = {
expr = expr =
let let
fediversity = eval ( example = eval {
{ config, ... }: runtime-environments.bar.nixos = {
{ module =
config = { { ... }:
applications.hello = {
{ ... }: system.stateVersion = "25.05";
{
description = ''Command-line tool that will print "Hello, world!" on the terminal'';
module =
{ ... }:
{
options = {
enable = lib.mkEnableOption "Hello in the shell";
};
};
implementation =
cfg:
lib.optionalAttrs cfg.enable {
dummy.login-shell.packages.hello = pkgs.hello;
};
};
};
options = {
example-configuration = mkOption {
type = config.configuration;
readOnly = true;
default = {
enable = true;
applications.hello.enable = true;
};
}; };
}; };
} applications.foo = {
); module =
{ pkgs, ... }:
{
environment.systemPackages = [
pkgs.hello
];
};
};
};
in in
{ {
inherit (fediversity) has-runtime = lib.isAttrs example.runtime-environments.bar.nixos.module;
example-configuration has-application = lib.isAttrs example.applications.foo.module;
;
}; };
expected = { expected = {
example-configuration = { has-runtime = true;
enable = true; has-application = true;
applications.hello.enable = true;
};
}; };
}; };
} }

View file

@ -1,89 +1,45 @@
{ {
lib, lib,
config,
... ...
}: }:
let let
inherit (lib) mkOption types; inherit (lib) types mkOption;
inherit (lib.types)
attrsOf
attrTag
deferredModuleWith
submodule
optionType
functionTo
;
functionType = import ./function.nix;
application-resources = {
options.resources = mkOption {
# TODO: maybe transpose, and group the resources by type instead
type = attrsOf (
attrTag (lib.mapAttrs (_name: resource: mkOption { type = resource.request; }) config.resources)
);
};
};
in in
with types;
{ {
_class = "nixops4Deployment"; _class = "nixops4Deployment";
options = { options = {
applications = mkOption { runtime-environments = mkOption {
description = "Collection of Fediversity applications"; description = "Collection of runtime environments into which applications can be deployed";
type = attrsOf ( type = attrsOf (attrTag {
submodule (application: { nixos = mkOption {
_class = "fediversity-application"; description = "A single NixOS machine";
options = { type = submodule {
description = mkOption { options = {
description = "Description to be shown in the application overview"; module = mkOption {
type = types.str; description = "The NixOS module describing the base configuration for that machine";
}; type = deferredModule;
module = mkOption {
description = "Operator-facing configuration options for the application";
type = deferredModuleWith { staticModules = [ { _class = "fediversity-application-config"; } ]; };
};
implementation = mkOption {
description = "Mapping of application configuration to deployment resources, a description of what an application needs to run";
type = application.config.config-mapping.function-type;
};
resources = mkOption {
description = "Compute resources required by an application";
type = functionTo application.config.config-mapping.output-type;
readOnly = true;
default = input: (application.config.implementation input).output;
};
config-mapping = mkOption {
description = "Function type for the mapping from application configuration to required resources";
type = submodule functionType;
readOnly = true;
default = {
input-type = application.config.module;
output-type = application-resources;
}; };
}; };
}; };
})
);
};
configuration = mkOption {
description = "Configuration type declaring options to be set by operators";
type = optionType;
readOnly = true;
default = submodule {
options = {
enable = lib.mkEnableOption {
description = "your Fediversity configuration";
};
applications = lib.mapAttrs (
_name: application:
mkOption {
description = application.description;
type = submodule application.module;
default = { };
}
) config.applications;
}; };
}; });
};
applications = mkOption {
description = "Collection of Fediversity applications";
type = attrsOf (submoduleWith {
modules = [
{
options = {
module = mkOption {
description = "The NixOS module for that application, for configuring that application";
type = deferredModule;
};
};
}
];
});
}; };
}; };
} }

View file

@ -1,26 +1,9 @@
{ inputs, sources, ... }:
{ {
_class = "flake"; _class = "flake";
perSystem = imports = [
{ pkgs, ... }: ./check/basic/flake-part.nix
{ ./check/cli/flake-part.nix
checks = { ./check/panel/flake-part.nix
deployment-basic = import ./check/basic { ];
inherit (pkgs.testers) runNixOSTest;
inherit inputs sources;
};
deployment-cli = import ./check/cli {
inherit (pkgs.testers) runNixOSTest;
inherit inputs sources;
};
deployment-panel = import ./check/panel {
inherit (pkgs.testers) runNixOSTest;
inherit inputs sources;
};
};
};
} }

View file

@ -1,37 +0,0 @@
/**
Modular function type
*/
{ config, lib, ... }:
let
inherit (lib) mkOption types;
inherit (types)
deferredModule
submodule
functionTo
optionType
;
in
{
options = {
input-type = mkOption {
type = deferredModule;
};
output-type = mkOption {
type = deferredModule;
};
function-type = mkOption {
type = optionType;
readOnly = true;
default = functionTo (submodule {
options = {
input = mkOption {
type = submodule config.input-type;
};
output = mkOption {
type = submodule config.output-type;
};
};
});
};
};
}

121
flake.lock generated
View file

@ -59,6 +59,22 @@
} }
}, },
"flake-compat_2": { "flake-compat_2": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_3": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1733328505, "lastModified": 1733328505,
@ -74,7 +90,7 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat_3": { "flake-compat_4": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1696426674, "lastModified": 1696426674,
@ -127,6 +143,24 @@
} }
}, },
"flake-parts_3": { "flake-parts_3": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib_3"
},
"locked": {
"lastModified": 1738453229,
"narHash": "sha256-7H9XgNiGLKN1G1CgRh0vUL4AheZSYzPm+zmZ7vxbJdo=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "32ea77a06711b758da0ad9bd6a844c5740a87abd",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_4": {
"inputs": { "inputs": {
"nixpkgs-lib": [ "nixpkgs-lib": [
"nixops4-nixos", "nixops4-nixos",
@ -167,12 +201,32 @@
"type": "github" "type": "github"
} }
}, },
"git-hooks-nix": { "git-hooks": {
"inputs": { "inputs": {
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
"gitignore": "gitignore", "gitignore": "gitignore",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": {
"lastModified": 1742649964,
"narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"git-hooks-nix": {
"inputs": {
"flake-compat": "flake-compat_2",
"gitignore": "gitignore_2",
"nixpkgs": "nixpkgs_2"
},
"locked": { "locked": {
"lastModified": 1737465171, "lastModified": 1737465171,
"narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=", "narHash": "sha256-R10v2hoJRLq8jcL4syVFag7nIGE7m13qO48wRIukWNg=",
@ -227,6 +281,27 @@
} }
}, },
"gitignore": { "gitignore": {
"inputs": {
"nixpkgs": [
"git-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"gitignore_2": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"nixops4-nixos", "nixops4-nixos",
@ -266,8 +341,8 @@
}, },
"nix": { "nix": {
"inputs": { "inputs": {
"flake-compat": "flake-compat_2", "flake-compat": "flake-compat_3",
"flake-parts": "flake-parts_3", "flake-parts": "flake-parts_4",
"git-hooks-nix": "git-hooks-nix_2", "git-hooks-nix": "git-hooks-nix_2",
"nixfmt": "nixfmt", "nixfmt": "nixfmt",
"nixpkgs": [ "nixpkgs": [
@ -341,10 +416,10 @@
}, },
"nixops4": { "nixops4": {
"inputs": { "inputs": {
"flake-parts": "flake-parts_2", "flake-parts": "flake-parts_3",
"nix": "nix", "nix": "nix",
"nix-cargo-integration": "nix-cargo-integration", "nix-cargo-integration": "nix-cargo-integration",
"nixpkgs": "nixpkgs_2", "nixpkgs": "nixpkgs_3",
"nixpkgs-old": "nixpkgs-old" "nixpkgs-old": "nixpkgs-old"
}, },
"locked": { "locked": {
@ -363,7 +438,7 @@
}, },
"nixops4-nixos": { "nixops4-nixos": {
"inputs": { "inputs": {
"flake-parts": "flake-parts", "flake-parts": "flake-parts_2",
"git-hooks-nix": "git-hooks-nix", "git-hooks-nix": "git-hooks-nix",
"nixops4": "nixops4", "nixops4": "nixops4",
"nixops4-nixos": [ "nixops4-nixos": [
@ -445,6 +520,18 @@
"url": "https://github.com/NixOS/nixpkgs/archive/072a6db25e947df2f31aab9eccd0ab75d5b2da11.tar.gz" "url": "https://github.com/NixOS/nixpkgs/archive/072a6db25e947df2f31aab9eccd0ab75d5b2da11.tar.gz"
} }
}, },
"nixpkgs-lib_3": {
"locked": {
"lastModified": 1738452942,
"narHash": "sha256-vJzFZGaCpnmo7I6i416HaBLpC+hvcURh/BQwROcGIp8=",
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/072a6db25e947df2f31aab9eccd0ab75d5b2da11.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://github.com/NixOS/nixpkgs/archive/072a6db25e947df2f31aab9eccd0ab75d5b2da11.tar.gz"
}
},
"nixpkgs-old": { "nixpkgs-old": {
"locked": { "locked": {
"lastModified": 1735563628, "lastModified": 1735563628,
@ -478,6 +565,22 @@
} }
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": {
"lastModified": 1730768919,
"narHash": "sha256-8AKquNnnSaJRXZxc5YmF/WfmxiHX6MMZZasRP6RRQkE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a04d33c0c3f1a59a2c1cb0c6e34cd24500e5a1dc",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1738410390, "lastModified": 1738410390,
"narHash": "sha256-xvTo0Aw0+veek7hvEVLzErmJyQkEcRk6PSR4zsRQFEc=", "narHash": "sha256-xvTo0Aw0+veek7hvEVLzErmJyQkEcRk6PSR4zsRQFEc=",
@ -518,7 +621,7 @@
}, },
"purescript-overlay": { "purescript-overlay": {
"inputs": { "inputs": {
"flake-compat": "flake-compat_3", "flake-compat": "flake-compat_4",
"nixpkgs": [ "nixpkgs": [
"nixops4-nixos", "nixops4-nixos",
"nixops4", "nixops4",
@ -561,6 +664,8 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"flake-parts": "flake-parts",
"git-hooks": "git-hooks",
"nixops4": [ "nixops4": [
"nixops4-nixos", "nixops4-nixos",
"nixops4" "nixops4"

115
flake.nix
View file

@ -1,52 +1,83 @@
{ {
inputs = { inputs = {
flake-parts.url = "github:hercules-ci/flake-parts";
git-hooks.url = "github:cachix/git-hooks.nix";
nixops4.follows = "nixops4-nixos/nixops4"; nixops4.follows = "nixops4-nixos/nixops4";
nixops4-nixos.url = "github:nixops4/nixops4-nixos"; nixops4-nixos.url = "github:nixops4/nixops4-nixos";
}; };
outputs = outputs =
inputs: inputs@{ self, flake-parts, ... }:
import ./mkFlake.nix inputs ( let
{ inputs, sources, ... }: sources = import ./npins;
inherit (import sources.flake-inputs) import-flake;
inherit (sources) git-hooks;
# XXX(@fricklerhandwerk): this atrocity is required to splice in a foreign Nixpkgs via flake-parts
# XXX - this is just importing a flake
nixpkgs = import-flake { src = sources.nixpkgs; };
# XXX - this overrides the inputs attached to `self`
inputs' = self.inputs // {
nixpkgs = nixpkgs;
};
self' = self // {
inputs = inputs';
};
in
# XXX - finally we override the overall set of `inputs` -- we need both:
# `flake-parts obtains `nixpkgs` from `self.inputs` and not from `inputs`.
flake-parts.lib.mkFlake
{ {
imports = [ inputs = inputs // {
"${sources.git-hooks}/flake-module.nix" inherit nixpkgs;
inputs.nixops4.modules.flake.default };
self = self';
./deployment/flake-part.nix specialArgs = {
./infra/flake-part.nix inherit sources;
./keys/flake-part.nix };
./secrets/flake-part.nix
./services/tests/flake-part.nix
];
perSystem =
{
pkgs,
lib,
system,
...
}:
{
checks = {
panel = (import ./. { inherit sources system; }).tests.panel.basic;
};
formatter = pkgs.nixfmt-rfc-style;
pre-commit.settings.hooks =
let
## Add a directory here if pre-commit hooks shouldn't apply to it.
optout = [ "npins" ];
excludes = map (dir: "^${dir}/") optout;
addExcludes = lib.mapAttrs (_: c: c // { inherit excludes; });
in
addExcludes {
nixfmt-rfc-style.enable = true;
deadnix.enable = true;
trim-trailing-whitespace.enable = true;
shellcheck.enable = true;
};
};
} }
); (
{ inputs, ... }:
{
systems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
imports = [
"${git-hooks}/flake-module.nix"
inputs.nixops4.modules.flake.default
./deployment/flake-part.nix
./infra/flake-part.nix
./keys/flake-part.nix
./secrets/flake-part.nix
];
perSystem =
{
pkgs,
lib,
...
}:
{
formatter = pkgs.nixfmt-rfc-style;
pre-commit.settings.hooks =
let
## Add a directory here if pre-commit hooks shouldn't apply to it.
optout = [ "npins" ];
excludes = map (dir: "^${dir}/") optout;
addExcludes = lib.mapAttrs (_: c: c // { inherit excludes; });
in
addExcludes {
nixfmt-rfc-style.enable = true;
deadnix.enable = true;
trim-trailing-whitespace.enable = true;
shellcheck.enable = true;
};
};
}
);
} }

View file

@ -1,13 +1,14 @@
# Infra # Infra
This directory contains the definition of [the VMs](../machines/machines.md) that host our This directory contains the definition of [the VMs](machines.md) that host our
infrastructure. infrastructure.
## Provisioning VMs with an initial configuration ## Provisioning VMs with an initial configuration
> NOTE[Niols]: This is still very manual and clunky. Two things will happen: NOTE[Niols]: This is very manual and clunky. Two things will happen. In the near
> 1. In the near future, I will improve the provisioning script to make this a bit less clunky. future, I will improve the provisioning script to make this a bit less clunky.
> 2. In the far future, NixOps4 will be able to communicate with Proxmox directly and everything will become much cleaner. In the far future, NixOps4 will be able to communicate with Proxmox directly and
everything will become much cleaner.
1. Choose names for your VMs. It is recommended to choose `fediXXX`, with `XXX` 1. Choose names for your VMs. It is recommended to choose `fediXXX`, with `XXX`
above 100. For instance, `fedi117`. above 100. For instance, `fedi117`.
@ -24,7 +25,8 @@ infrastructure.
Those files need to exist during provisioning, but their content matters only Those files need to exist during provisioning, but their content matters only
when updating the machines' configuration. when updating the machines' configuration.
> FIXME: Remove this step by making the provisioning script not fail with the public key does not exist yet. FIXME: Remove this step by making the provisioning script not fail with the
public key does not exist yet.
3. Run the provisioning script: 3. Run the provisioning script:
``` ```
@ -42,7 +44,7 @@ infrastructure.
ssh fedi117.abundos.eu 'sudo cat /etc/ssh/ssh_host_ed25519_key.pub' > keys/systems/fedi117.pub ssh fedi117.abundos.eu 'sudo cat /etc/ssh/ssh_host_ed25519_key.pub' > keys/systems/fedi117.pub
``` ```
> FIXME: Make the provisioning script do that for us. FIXME: Make the provisioning script do that for us.
7. Regenerate the list of machines: 7. Regenerate the list of machines:
``` ```
@ -54,7 +56,7 @@ infrastructure.
just enough for it to boot and be reachable. Go on to the next section to just enough for it to boot and be reachable. Go on to the next section to
update the machine and put an actual configuration. update the machine and put an actual configuration.
> FIXME: Figure out why the full configuration isn't on the machine at this FIXME: Figure out why the full configuration isn't on the machine at this
point and fix it. point and fix it.
## Updating existing VM configurations ## Updating existing VM configurations

View file

@ -24,14 +24,6 @@ in
experimental-features = nix-command flakes experimental-features = nix-command flakes
''; '';
nix.settings = {
trusted-substituters = [
"https://attic.fediversity.net/demo"
];
trusted-public-keys = [
"demo:N3CAZ049SeBVqBM+OnhLMrxWJ9altbD/aoJtHrY19KM="
];
};
boot.loader = { boot.loader = {
systemd-boot.enable = true; systemd-boot.enable = true;
efi.canTouchEfiVariables = true; efi.canTouchEfiVariables = true;

View file

@ -1,13 +1,7 @@
{
config,
...
}:
{ {
_class = "nixos"; _class = "nixos";
users.users = { users.users = {
root.openssh.authorizedKeys.keys = config.users.users.procolix.openssh.authorizedKeys.keys;
procolix = { procolix = {
isNormalUser = true; isNormalUser = true;
extraGroups = [ "wheel" ]; extraGroups = [ "wheel" ];

View file

@ -20,13 +20,16 @@ in
''; '';
}; };
isFediversityVm = mkOption { proxmox = mkOption {
type = types.bool; type = types.nullOr (
types.enum [
"procolix"
"fediversity"
]
);
description = '' description = ''
Whether the machine is a Fediversity VM or not. This is used to The Proxmox instance. This is used for provisioning only and should be
determine whether the machine should be provisioned via Proxmox or not. set to `null` if the machine is not a VM.
Machines that are _not_ Fediversity VM could be physical machines, or
VMs that live outside Fediversity, eg. on Procolix's Proxmox.
''; '';
}; };

View file

@ -1,14 +1,9 @@
{ ... }: { modulesPath, ... }:
{ {
_class = "nixos"; _class = "nixos";
## FIXME: It would be nice, but the following leads to infinite recursion imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
## in the way we currently plug `sources` in.
##
# imports = [
# "${sources.nixpkgs}/nixos/modules/profiles/qemu-guest.nix"
# ];
boot = { boot = {
initrd = { initrd = {

View file

@ -2,6 +2,7 @@
inputs, inputs,
lib, lib,
config, config,
sources,
keys, keys,
secrets, secrets,
... ...
@ -31,10 +32,13 @@ 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.
nixos.module = { nixos.module = {
imports = [ imports = with sources; [
"${agenix}/modules/age.nix"
"${disko}/module.nix"
"${vars}/options.nix"
"${vars}/backends/on-machine.nix"
./options.nix ./options.nix
./nixos ./nixos
./proxmox-qemu-vm.nix
]; ];
## Inject the shared options from the resource's `config` into the NixOS ## Inject the shared options from the resource's `config` into the NixOS
@ -46,9 +50,9 @@ in
## the secret's file. ## the secret's 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 = secrets.rootPath + "/${name}"; ${removeSuffix ".age" name}.file = secrets.rootPath + "/${name}";
} })
) secrets.mapping; ) secrets.mapping;
## FIXME: Remove direct root authentication once the NixOps4 NixOS provider ## FIXME: Remove direct root authentication once the NixOps4 NixOS provider
@ -56,8 +60,6 @@ in
users.users.root.openssh.authorizedKeys.keys = attrValues keys.contributors ++ [ users.users.root.openssh.authorizedKeys.keys = attrValues keys.contributors ++ [
# allow our panel vm access to the test machines # allow our panel vm access to the test machines
keys.panel keys.panel
# allow continuous deployment access
keys.cd
]; ];
}; };

View file

@ -14,42 +14,49 @@ let
mkOption mkOption
evalModules evalModules
filterAttrs filterAttrs
mapAttrs'
deepSeq
; ;
inherit (lib.attrsets) genAttrs; inherit (lib.attrsets) genAttrs;
commonResourceModule = { ## Given a machine's name and whether it is a test VM, make a resource module,
# TODO(@fricklerhandwerk): this is terrible but IMO we should just ditch ## except for its missing provider. (Depending on the use of that resource, we
# flake-parts and have our own data model for how the project is organised ## will provide a different one.)
# internally makeResourceModule =
_module.args = { { vmName, isTestVm }:
inherit {
inputs # TODO(@fricklerhandwerk): this is terrible but IMO we should just ditch flake-parts and have our own data model for how the project is organised internally
keys _module.args = {
secrets inherit
sources inputs
; sources
keys
secrets
;
};
imports =
[
./common/resource.nix
]
++ (
if isTestVm then
[
./common/proxmox-qemu-vm.nix
../machines/operator/${vmName}
{
nixos.module.users.users.root.openssh.authorizedKeys.keys = [
# allow our panel vm access to the test machines
keys.panel
];
}
]
else
[
../machines/dev/${vmName}
]
);
fediversityVm.name = vmName;
}; };
## FIXME: It would be preferrable to have those `sources`-related imports in
## the modules that use them. However, doing so triggers infinite recursions
## because of the way we propagate `sources`. `sources` must be propagated by
## means of `specialArgs`, but this requires a bigger change.
nixos.module.imports = [
"${sources.nixpkgs}/nixos/modules/profiles/qemu-guest.nix"
"${sources.agenix}/modules/age.nix"
"${sources.disko}/module.nix"
"${sources.home-manager}/nixos"
"${sources.vars}/options.nix"
"${sources.vars}/backends/on-machine.nix"
];
imports = [
./common/resource.nix
];
};
## Given a list of machine names, make a deployment with those machines' ## Given a list of machine names, make a deployment with those machines'
## configurations as resources. ## configurations as resources.
makeDeployment = makeDeployment =
@ -61,8 +68,10 @@ let
type = providers.local.exec; type = providers.local.exec;
imports = [ imports = [
inputs.nixops4-nixos.modules.nixops4Resource.nixos inputs.nixops4-nixos.modules.nixops4Resource.nixos
commonResourceModule (makeResourceModule {
../machines/dev/${vmName} inherit vmName;
isTestVm = false;
})
]; ];
}); });
}; };
@ -79,35 +88,25 @@ let
fediversity = import ../services/fediversity; fediversity = import ../services/fediversity;
} }
{ {
garageConfigurationResource = { garageConfigurationResource = makeResourceModule {
imports = [ vmName = "test01";
commonResourceModule isTestVm = true;
../machines/operator/test01
];
}; };
mastodonConfigurationResource = { mastodonConfigurationResource = makeResourceModule {
imports = [ vmName = "test06"; # somehow `test02` has a problem - use test06 instead
commonResourceModule isTestVm = true;
../machines/operator/test06 # somehow `test02` has a problem - use test06 instead
];
}; };
peertubeConfigurationResource = { peertubeConfigurationResource = makeResourceModule {
imports = [ vmName = "test05";
commonResourceModule isTestVm = true;
../machines/operator/test05
];
}; };
pixelfedConfigurationResource = { pixelfedConfigurationResource = makeResourceModule {
imports = [ vmName = "test04";
commonResourceModule isTestVm = true;
../machines/operator/test04
];
}; };
atticConfigurationResource = { atticConfigurationResource = makeResourceModule {
imports = [ vmName = "test12";
commonResourceModule isTestVm = true;
../machines/operator/test12
];
}; };
}; };
@ -120,63 +119,54 @@ let
## this is only needed to expose NixOS configurations for provisioning ## this is only needed to expose NixOS configurations for provisioning
## purposes, and eventually all of this should be handled by NixOps4. ## purposes, and eventually all of this should be handled by NixOps4.
options = { options = {
nixos.module = mkOption { type = lib.types.deferredModule; }; # NOTE: not just `nixos` otherwise merging will go wrong nixos.module = mkOption { }; # NOTE: not just `nixos` otherwise merging will go wrong
nixpkgs = mkOption { }; nixpkgs = mkOption { };
ssh = mkOption { }; ssh = mkOption { };
}; };
}; };
makeResourceConfig = makeResourceConfig =
{ vmName, isTestVm }: vm:
(evalModules { (evalModules {
modules = [ modules = [
nixops4ResourceNixosMockOptions nixops4ResourceNixosMockOptions
commonResourceModule (makeResourceModule vm)
(if isTestVm then ../machines/operator/${vmName} else ../machines/dev/${vmName})
]; ];
}).config; }).config;
## 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: isTestVm: vmName:
import "${sources.nixpkgs}/nixos" { let
configuration = (makeResourceConfig { inherit vmName isTestVm; }).nixos.module; inherit (sources) nixpkgs;
system = "x86_64-linux"; in
import "${nixpkgs}/nixos" {
modules = [
(makeResourceConfig { inherit vmName isTestVm; }).nixos.module
];
}; };
makeVmOptions = makeVmOptions = isTestVm: vmName: {
isTestVm: vmName: inherit ((makeResourceConfig { inherit vmName isTestVm; }).fediversityVm)
let proxmox
config = (makeResourceConfig { inherit vmName isTestVm; }).fediversityVm; vmId
in description
if config.isFediversityVm then
{ sockets
inherit (config) cores
vmId memory
description diskSize
sockets
cores hostPublicKey
memory unsafeHostPrivateKey
diskSize ;
hostPublicKey };
unsafeHostPrivateKey
;
}
else
null;
listSubdirectories = path: attrNames (filterAttrs (_: type: type == "directory") (readDir path)); listSubdirectories = path: attrNames (filterAttrs (_: type: type == "directory") (readDir path));
machines = listSubdirectories ../machines/dev; machines = listSubdirectories ../machines/dev;
testMachines = listSubdirectories ../machines/operator; testMachines = listSubdirectories ../machines/operator;
nixosConfigurations =
genAttrs machines (makeConfiguration false)
// genAttrs testMachines (makeConfiguration true);
vmOptions =
filterAttrs (_: value: value != null) # Filter out non-Fediversity VMs
(genAttrs machines (makeVmOptions false) // genAttrs testMachines (makeVmOptions true));
in in
{ {
_class = "flake"; _class = "flake";
@ -200,23 +190,10 @@ in
) )
); );
}; };
flake = { inherit nixosConfigurations vmOptions; }; flake.nixosConfigurations =
genAttrs machines (makeConfiguration false)
perSystem = // genAttrs testMachines (makeConfiguration true);
{ pkgs, ... }: flake.vmOptions =
{ genAttrs machines (makeVmOptions false)
checks = // genAttrs testMachines (makeVmOptions true);
mapAttrs' (name: nixosConfiguration: {
name = "nixosConfigurations-${name}";
value = nixosConfiguration.config.system.build.toplevel;
}) nixosConfigurations
// mapAttrs' (name: vmOptions: {
name = "vmOptions-${name}";
## Check that VM options builds/evaluates correctly. `deepSeq e1
## e2` evaluates `e1` strictly in depth before returning `e2`. We
## use this trick because checks need to be derivations, which VM
## options are not.
value = deepSeq vmOptions pkgs.hello;
}) vmOptions;
};
} }

View file

@ -15,6 +15,7 @@ let
installer = installer =
{ {
config,
pkgs, pkgs,
lib, lib,
... ...

View file

@ -179,9 +179,15 @@ grab_vm_options () {
--log-format raw --quiet --log-format raw --quiet
) )
proxmox=$(echo "$options" | jq -r .proxmox)
vm_id=$(echo "$options" | jq -r .vmId) vm_id=$(echo "$options" | jq -r .vmId)
description=$(echo "$options" | jq -r .description) description=$(echo "$options" | jq -r .description)
if [ "$proxmox" != fediversity ]; then
die "I do not know how to provision things that are not Fediversity VMs,
but I got proxmox = '%s' for VM %s." "$proxmox" "$vm_name"
fi
sockets=$(echo "$options" | jq -r .sockets) sockets=$(echo "$options" | jq -r .sockets)
cores=$(echo "$options" | jq -r .cores) cores=$(echo "$options" | jq -r .cores)
memory=$(echo "$options" | jq -r .memory) memory=$(echo "$options" | jq -r .memory)

View file

@ -167,10 +167,16 @@ grab_vm_options () {
--log-format raw --quiet --log-format raw --quiet
) )
proxmox=$(echo "$options" | jq -r .proxmox)
vm_id=$(echo "$options" | jq -r .vmId) vm_id=$(echo "$options" | jq -r .vmId)
printf 'done grabing VM options for VM %s. Got id: %d.\n' \ if [ "$proxmox" != fediversity ]; then
"$vm_name" "$vm_id" die "I do not know how to remove things that are not Fediversity VMs,
but I got proxmox = '%s' for VM %s." "$proxmox" "$vm_name"
fi
printf 'done grabing VM options for VM %s. Found VM %d on %s Proxmox.\n' \
"$vm_name" "$vm_id" "$proxmox"
fi fi
} }

View file

@ -1 +0,0 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMlsYTtMx3hFO8B5B8iHaXL2JKj9izHeC+/AMhIWXBPs cd-age

View file

@ -35,5 +35,4 @@ in
contributors = collectKeys ./contributors; contributors = collectKeys ./contributors;
systems = collectKeys ./systems; systems = collectKeys ./systems;
panel = removeTrailingWhitespace (readFile ./panel-ssh-key.pub); panel = removeTrailingWhitespace (readFile ./panel-ssh-key.pub);
cd = removeTrailingWhitespace (readFile ./cd-ssh-key.pub);
} }

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "fedi200";
isFediversityVm = true;
vmId = 200; vmId = 200;
proxmox = "fediversity";
description = "Testing machine for Hans"; description = "Testing machine for Hans";
domain = "abundos.eu"; domain = "abundos.eu";

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "fedi201";
isFediversityVm = true;
vmId = 201; vmId = 201;
proxmox = "fediversity";
description = "FediPanel"; description = "FediPanel";
domain = "abundos.eu"; domain = "abundos.eu";
@ -20,6 +19,7 @@
nixos.module = { nixos.module = {
imports = [ imports = [
../../../infra/common/proxmox-qemu-vm.nix
./fedipanel.nix ./fedipanel.nix
]; ];
}; };

View file

@ -1,5 +1,6 @@
{ {
config, config,
sources,
... ...
}: }:
let let
@ -10,6 +11,7 @@ in
imports = [ imports = [
(import ../../../panel { }).module (import ../../../panel { }).module
(import "${sources.home-manager}/nixos")
]; ];
security.acme = { security.acme = {

View file

@ -20,9 +20,7 @@ in
ssh.host = mkForce "forgejo-ci"; ssh.host = mkForce "forgejo-ci";
fediversityVm = { fediversityVm = {
name = "forgejo-ci";
domain = "procolix.com"; domain = "procolix.com";
isFediversityVm = false;
ipv4 = { ipv4 = {
interface = "enp1s0f0"; interface = "enp1s0f0";
@ -50,7 +48,7 @@ in
}; };
## NOTE: This is a physical machine, so is not covered by disko ## NOTE: This is a physical machine, so is not covered by disko
fileSystems."/" = lib.mkForce { fileSystems."/" = {
device = "rpool/root"; device = "rpool/root";
fsType = "zfs"; fsType = "zfs";
}; };
@ -60,7 +58,7 @@ in
fsType = "zfs"; fsType = "zfs";
}; };
fileSystems."/boot" = lib.mkForce { fileSystems."/boot" = {
device = "/dev/disk/by-uuid/50B2-DD3F"; device = "/dev/disk/by-uuid/50B2-DD3F";
fsType = "vfat"; fsType = "vfat";
options = [ options = [

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "vm02116";
isFediversityVm = false;
vmId = 2116; vmId = 2116;
proxmox = "procolix";
description = "Forgejo"; description = "Forgejo";
ipv4.address = "185.206.232.34"; ipv4.address = "185.206.232.34";
@ -15,6 +14,7 @@
{ lib, ... }: { lib, ... }:
{ {
imports = [ imports = [
../../../infra/common/proxmox-qemu-vm.nix
./forgejo.nix ./forgejo.nix
]; ];

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "vm02187";
isFediversityVm = false;
vmId = 2187; vmId = 2187;
proxmox = "procolix";
description = "Wiki"; description = "Wiki";
ipv4.address = "185.206.232.187"; ipv4.address = "185.206.232.187";
@ -15,6 +14,7 @@
{ lib, ... }: { lib, ... }:
{ {
imports = [ imports = [
../../../infra/common/proxmox-qemu-vm.nix
./wiki.nix ./wiki.nix
]; ];

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "test01";
isFediversityVm = true;
vmId = 7001; vmId = 7001;
proxmox = "fediversity";
hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub; hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub;
unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key; unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key;

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "test02";
isFediversityVm = true;
vmId = 7002; vmId = 7002;
proxmox = "fediversity";
hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub; hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub;
unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key; unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key;

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "test03";
isFediversityVm = true;
vmId = 7003; vmId = 7003;
proxmox = "fediversity";
hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub; hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub;
unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key; unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key;

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "test04";
isFediversityVm = true;
vmId = 7004; vmId = 7004;
proxmox = "fediversity";
hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub; hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub;
unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key; unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key;

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "test05";
isFediversityVm = true;
vmId = 7005; vmId = 7005;
proxmox = "fediversity";
hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub; hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub;
unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key; unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key;

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "test06";
isFediversityVm = true;
vmId = 7006; vmId = 7006;
proxmox = "fediversity";
hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub; hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub;
unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key; unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key;

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "test11";
isFediversityVm = true;
vmId = 7011; vmId = 7011;
proxmox = "fediversity";
hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub; hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub;
unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key; unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key;

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "test12";
isFediversityVm = true;
vmId = 7012; vmId = 7012;
proxmox = "fediversity";
hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub; hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub;
unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key; unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key;
@ -19,4 +18,11 @@
gateway = "2a00:51c0:13:1305::1"; gateway = "2a00:51c0:13:1305::1";
}; };
}; };
nixos.module = {
imports = [
../../../infra/common/proxmox-qemu-vm.nix
../../../services/fediversity/attic
];
};
} }

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "test13";
isFediversityVm = true;
vmId = 7013; vmId = 7013;
proxmox = "fediversity";
hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub; hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub;
unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key; unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key;

View file

@ -2,9 +2,8 @@
_class = "nixops4Resource"; _class = "nixops4Resource";
fediversityVm = { fediversityVm = {
name = "test14";
isFediversityVm = true;
vmId = 7014; vmId = 7014;
proxmox = "fediversity";
hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub; hostPublicKey = builtins.readFile ./ssh_host_ed25519_key.pub;
unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key; unsafeHostPrivateKey = builtins.readFile ./ssh_host_ed25519_key;

View file

@ -1,54 +0,0 @@
## This file contains a tweak of flake-parts's `mkFlake` function to splice in
## sources taken from npins.
## NOTE: Much of the logic in this file feels like it should be not super
## specific to fediversity. Could it make sense to extract the core of this to
## another place it feels closer to in spirit, such as @fricklerhandwerk's
## flake-inputs (which this code already depends on anyway, and which already
## contained two distinct helpers for migrating away from flakes)? cf
## https://git.fediversity.eu/Fediversity/Fediversity/pulls/447#issuecomment-8671
inputs@{ self, ... }:
let
sources = import ./npins;
inherit (import sources.flake-inputs) import-flake;
# XXX(@fricklerhandwerk): this atrocity is required to splice in a foreign Nixpkgs via flake-parts
# XXX - this is just importing a flake
nixpkgs = import-flake { src = sources.nixpkgs; };
# XXX - this overrides the inputs attached to `self`
inputs' = self.inputs // {
nixpkgs = nixpkgs;
};
self' = self // {
inputs = inputs';
};
flake-parts-lib = import "${sources.flake-parts}/lib.nix" { inherit (nixpkgs) lib; };
in
flakeModule:
flake-parts-lib.mkFlake
{
# XXX - finally we override the overall set of `inputs` -- we need both:
# `flake-parts obtains `nixpkgs` from `self.inputs` and not from `inputs`.
inputs = inputs // {
inherit nixpkgs;
};
self = self';
specialArgs = {
inherit sources;
};
}
{
systems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
imports = [ flakeModule ];
}

View file

@ -132,11 +132,11 @@
"owner": "KiaraGrouwstra", "owner": "KiaraGrouwstra",
"repo": "nix-templating" "repo": "nix-templating"
}, },
"branch": "master", "branch": "lib-default-arg",
"submodules": false, "submodules": false,
"revision": "1a0873296232e804a982e6613e88dc180afeca79", "revision": "e1ff247d508b4efd057a4d6bb13cf45b62c2512f",
"url": "https://github.com/KiaraGrouwstra/nix-templating/archive/1a0873296232e804a982e6613e88dc180afeca79.tar.gz", "url": "https://github.com/KiaraGrouwstra/nix-templating/archive/e1ff247d508b4efd057a4d6bb13cf45b62c2512f.tar.gz",
"hash": "0cfi03cjfk3y7ilyfx797v6dljb1jvva0gan6qjwlrfi5sz9x0sp" "hash": "0g59h4r029jw8vlvn8da62fk9m737s80fg2qk57322iv9lkqlvp0"
}, },
"nix-unit": { "nix-unit": {
"type": "Git", "type": "Git",
@ -168,14 +168,14 @@
"type": "Git", "type": "Git",
"repository": { "repository": {
"type": "GitHub", "type": "GitHub",
"owner": "KiaraGrouwstra", "owner": "kiaragrouwstra",
"repo": "vars" "repo": "vars"
}, },
"branch": "main", "branch": "templates",
"submodules": false, "submodules": false,
"revision": "626d5d05e9450294054b1304ea4159e8b70fc0a0", "revision": "6ff942bf2b514edaa1022a92edb6552ac32a09d1",
"url": "https://github.com/KiaraGrouwstra/vars/archive/626d5d05e9450294054b1304ea4159e8b70fc0a0.tar.gz", "url": "https://github.com/kiaragrouwstra/vars/archive/6ff942bf2b514edaa1022a92edb6552ac32a09d1.tar.gz",
"hash": "13c4hp4gzyvrvlmzpqnb6dzjgb9wc66rk5n4s54kd67mcc76ry3s" "hash": "1h1q3l1l1c1j4ak5lcj2yh85jwqww74ildiak2dkd4h1js9v6cvw"
} }
}, },
"version": 5 "version": 5

View file

@ -45,7 +45,7 @@ in
''; '';
}; };
module = ./nix/configuration.nix; module = import ./nix/configuration.nix;
tests = pkgs.callPackage ./nix/tests.nix { }; tests = pkgs.callPackage ./nix/tests.nix { };
# re-export inputs so they can be overridden granularly # re-export inputs so they can be overridden granularly

View file

@ -202,8 +202,11 @@ in
}; };
}; };
# needed to place a config file with home-manager users.users.${name} = {
users.users.${name}.isNormalUser = true; # TODO[Niols]: change to system user or document why we specifically
# need a normal user.
isNormalUser = true;
};
users.groups.${name} = { }; users.groups.${name} = { };
systemd.services.${name} = { systemd.services.${name} = {

Binary file not shown.

View file

@ -1,19 +1,17 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-ed25519 Jpc21A bBCQmvfRUwJuIXbpVJ092XUBVszGrb6gILGbgV9j9BY -> ssh-ed25519 Jpc21A 9edPaA2tT4SeYNTPzF0E157daC2o+JH/WQQCT+vLbFg
7DEGwhqdfqMs5cxXtlMkSTPjw4qhczBgW0dmoJ6dh6g C48EtLdhB75TTzfEZTw1DypicHiVlSmFzjfbqfO9N/8
-> ssh-ed25519 BAs8QA oiVedFC6UklEFCJUybGr93+XrddyCtV4r4TnE4nhpWI -> ssh-ed25519 BAs8QA T+kXpZg1v0XRkub5DWir7vYwO7KaOJLZBNYxxXiBUCw
xasnkP4NCl9TuYSE1u0Xi0b/PiwcrfHCz2QMnpTjLcU zBRwMTDpyI7twEwUGsmJYyYPw9btBx5Kakj1yT+XY8U
-> ssh-ed25519 ofQnlg LrMcWdaEUVyIgd/KznwJW/2sucIu5MuxDEcEJAmf8mA -> ssh-ed25519 ofQnlg 4UoEDY/tdKz8LrX1BkBU1/cn+vSaYLUl7xX9YmzANBY
p6pQoisuXre2J4r6ArV6C6lKO2J/aNdBFhqLPBoZ2wA 8CACq1n3AJgD9IyPN23iRvThqsfQFF5+jmkKnhun24U
-> ssh-ed25519 COspvA q2OGeVofPKyGCpr4Mf9VoaRvZCWTRl8n2mvkQOdTnyQ -> ssh-ed25519 COspvA HxcbkqHL+LpVmwb+Fo5JuUU+C+Pxzdxtb0yZHixwuzM
M+ffAGecJG/94k/Z5DdokltrZppS2IcxkZa8JKHwIMs 7FIhxdbjHJlgQQgjrHHUK5cecqs5aT7X3I8TWf8c2gc
-> ssh-ed25519 2XrTgw Bsz/G4QderToPSfMKOR6s5yWb0xCGUlsjGJxJYQNBRc -> ssh-ed25519 2XrTgw R6Ia8MVIZKPnNZ0rspZ34EqoY8fOLeB9H7vnvNBLg1g
JYrXZb8qj1Yi9u5bnI/WzuNxy7gyFLCTIUaGNmcOYnk 55NUqz5Yygt6FKJ3bR5iHxQp8G7S2gyFwrJNX1Pb/2Y
-> ssh-ed25519 awJeHA KKJMQSt0PvC6P+T/kxQv96tSBdLQLiY2f8q35IwGm28 -> ssh-ed25519 awJeHA hJdTuAScoewVMt7HWiisSkL0zSeClFzYzzKL84G893o
p7Cf2HLlPl0qmsO6Hh5zwVgKkEs3A6fdSBndMKsacbk ou780VLrW1s4d6L+lEVu3kXaGn4dvtFPA31supwEL50
-> ssh-ed25519 Fa25Dw 3m/qyannP4gjXxkUuO0LQRU8Z8HXOg4WReMDd7786y8 -> ssh-ed25519 Fa25Dw mJcqnXA3fQeoKrG7RJ7nVeLxPvrxqbj+lJdx6jQ9IR8
dNMyiBGeJDrBScE9TEyZZ7+MGMG6FLuoRTK82EVeX1w f5Q7mrQSSDsm1Z/uSAnvx66mgnRC3XaBLQrVL9f/Ijs
-> ssh-ed25519 i+ecmQ oCs4Ep2K75yjmUOh1ox4F25tGq+O/mZ2/c2E8+IRlEc --- W/KmboXTLV12X6WtVQKHNe+ZHvS2q9EHUZwofSgJSE8
0Wc9gDxhvHK5tEVM5kJ0mQXc3kp7tJ2JNHg54N0+tJ8 ^kûÚ h©0ÔkÇ ¢¸_Ç·ûQÞm7\òÖ}÷Áë?½qø<ÿm
--- mXrqbcHxjjkS5MrQaCVm4hTsAUEENAWlIYtiYx6rtas
ž`€úì}öÙ7Ù>­iŒbàéëÕè/& ɪŠwŽ„ì7àí[ã±Hˆc“

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -7,12 +7,11 @@ let
keys = import ../keys; keys = import ../keys;
contributors = attrValues keys.contributors; contributors = attrValues keys.contributors;
cd = [ keys.cd ];
in in
concatMapAttrs concatMapAttrs
(name: systems: { (name: systems: {
"${name}.age".publicKeys = contributors ++ systems ++ cd; "${name}.age".publicKeys = contributors ++ systems;
}) })
( (
@ -25,7 +24,6 @@ concatMapAttrs
## are able to decrypt them. ## are able to decrypt them.
{ {
attic-ci-token = [ forgejo-ci ];
forgejo-database-password = [ vm02116 ]; forgejo-database-password = [ vm02116 ];
forgejo-email-password = [ vm02116 ]; forgejo-email-password = [ vm02116 ];
forgejo-runner-token = [ forgejo-ci ]; forgejo-runner-token = [ forgejo-ci ];

View file

@ -1,19 +1,18 @@
age-encryption.org/v1 age-encryption.org/v1
-> ssh-ed25519 Jpc21A NStZFZPTHMhVCnQ5Zkbl39vWztrxfsSXok24/e8H7QQ -> ssh-ed25519 Jpc21A EuMYAiZX+4A12eu19mIY7u+WYF7NJ9qJosQSVlxR6n8
JjHP6Cus76PGYYxpbnc2cSZ79zvdD8LISYDPbvXsnqU bK5CMXAmP23t1p9bgmqoVg4Qcu2qYKGc4t36v8e9eow
-> ssh-ed25519 BAs8QA iocHfHjWlEUsbtibqEbYDceAqURr2vjxuYapqon9hyU -> ssh-ed25519 BAs8QA IwRyitDNTzUPzQAUbDNEKjFiF8WPD/OyztOZQeoTEzw
ljL+olZdhWtHeV3uh3pOu22+sY13wPn2vKQDduPSqVs OwiTWvk4NmUgExav0uH6HlThDNU5hsKXfR6KHsFOV3I
-> ssh-ed25519 ofQnlg 9YVfMKyoP3+xtzg/ok2I9yf3YdIYoBpUJa/3d2N/8lI -> ssh-ed25519 ofQnlg 3TcMbLX1JsQL8+Gqy7IFZwykZr2BspvPCuZT1SHtnQQ
2yUalyj7O3c1YDA2xTb9QNYrFBDHwcyGBX3mydv0ifI Ci5OeBj2aiC8ut9jIEUMt3qfYH+cJrnVud6AH54Ndn8
-> ssh-ed25519 COspvA cOSNsZXBbhQ/B49fq3KwcY6siVrTz48doTrta/0d/Hw -> ssh-ed25519 COspvA 0t9f3Wu3ILv4QTJhwT619y+7XFrryCLbpIZC6aE+qQI
jcRtVxA/tVFM9btPAPI6zKk8BwAVlaQlvHC203MpmIQ oPQP48F6oO/tkqLZDdjkGtIap7KHiAknbpTNL6/yLaU
-> ssh-ed25519 2XrTgw d3EKtYkxjeJZ8kt3ofIklGmRwUCgTIB/WVVlvxggGRk -> ssh-ed25519 2XrTgw YOZsaYQH9vMH0QqSXGh8GyhRV4MbcBGPFfFaKpo3Ckk
IhcrpWN9xFsKRw9iCfYMONPOU7TpTt4kTBNwMDtk7zo kUShJbADA+6bpx2adxvzlI/0jSM5bIBfZfdSE/7Vm5Y
-> ssh-ed25519 awJeHA Ei64e3+FJDM6S8NP+YfEWEg9t72qTXZ0IdZE8dYQPm4 -> ssh-ed25519 awJeHA dF3m0hQWX9c0EezDr56Kt/F4d1Uim7NwvIX6zRws0Eo
ggRc86sXin06eXJkLbK8CdJFDa1237WMfSgwNd5ngmM pst243yrARODwrnyz8cJAzgDxdPOUsRbs7yPZePABFs
-> ssh-ed25519 dgBsjw 9etK6tNrFlWVAKTz5U0TitkiGYLKTad3QiRWVpLPrwM -> ssh-ed25519 dgBsjw PUYHcP/tgNnKyvlIoJRcNcW3zabVV1iHXIWfKqgW9xc
xHLzFnRtcvpVZYZrxWz5q4uadhHrHVlfqjteOWfIccE tXNjSuVH/g/oN5o75FPkFFpviF7SeFSN9kbqURvgMDE
-> ssh-ed25519 i+ecmQ SDTnYBLMOaH173B/wqaOifE6a90gSesRqMHmX7/iZFk --- wHgBAN9c6F6T5hFJGo8uH8zqDkQDwx3/jVNKUtQ3arE
kS9tuKnMXCXNUnoZ06DisOOyZHe/mZl4a0JRA+eynE8 «Ñ¢Á
--- C0R5WxDDCqQGxyvFoeNX838az0bjp55PGh//1NFG4LE ò@µú¡fÃ`m;ÕcæäU²€ùò£Íd…eSèyfv¿»¡€J?ø `œfj£Äa}lÃó ¿Úxç²BÇt2èfìôm08ÓoÝtRál9˜èx¤¢ŒÅžæ÷
ŠÉY—±³<EFBFBD>„ÏKRÇËej±éŒ7xÑí Óì¾7jÏ-œJý«[ÀF?Ÿ=-wXMC~)èŃ<E280BA>Éõb«ëƒCÜ4ÌÖÞOwý~¿š8ñv—ÙÜžèX»ØÆƒí!5¦

Binary file not shown.

Binary file not shown.

View file

@ -21,11 +21,11 @@ For those that know it, we could say that the current module is an analogous of
## Content of this directory ## Content of this directory
- [fediversity](./fediversity) contains the definition of the services. Look in - [fediversity][./fediversity] contains the definition of the services. Look in
particular at its `default.nix` that contains the definition of the options. particular at its `default.nix` that contains the definition of the options.
- [vm](./vm) contains options specific to making the service run in local QEMU - [vm][./vm] contains options specific to making the service run in local QEMU
VMs. These modules will for instance override the defaults to disable SSL, and VMs. These modules will for instance override the defaults to disable SSL, and
they will add virtualisation options to forward ports, for instance. they will add virtualisation options to forward ports, for instance.
- [tests](./tests) contain full NixOS tests of the services. - [tests][./tests] contain full NixOS tests of the services.

13
services/default.nix Normal file
View file

@ -0,0 +1,13 @@
{
system ? builtins.currentSystem,
sources ? import ../npins,
pkgs ? import sources.nixpkgs { inherit system; },
...
}:
{
tests = {
mastodon = pkgs.nixosTest ./tests/mastodon.nix;
pixelfed-garage = pkgs.nixosTest ./tests/pixelfed-garage.nix;
peertube = pkgs.nixosTest ./tests/peertube.nix;
};
}

View file

@ -7,7 +7,6 @@
let let
inherit (lib) mkIf mkMerge; inherit (lib) mkIf mkMerge;
sources = import ../../../npins; sources = import ../../../npins;
inherit (import "${sources.nix-templating}/lib.nix" { inherit pkgs; }) fileContents template_text;
in in
{ {
imports = with sources; [ imports = with sources; [
@ -70,77 +69,68 @@ in
]; ];
}; };
# open up access. 80 is necessary if only for ACME # open up access to the mastodon web interface. 80 is necessary if only for ACME
networking.firewall.allowedTCPPorts = [ networking.firewall.allowedTCPPorts = [
80 80
443 443
8080 8080
9000
]; ];
# https://wiki.nixos.org/wiki/Nginx#TLS_reverse_proxy
services.nginx = {
enable = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts."attic.${config.fediversity.domain}" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://127.0.0.1:8080";
proxyWebsockets = true; # needed if you need to use WebSocket
extraConfig =
# required when the target is also TLS server with multiple hosts
"proxy_ssl_server_name on;"
+
# required when the server wants to use HTTP Authentication
"proxy_pass_header Authorization;";
};
};
};
vars.settings.on-machine.enable = true; vars.settings.on-machine.enable = true;
vars.generators."templates" = rec {
vars.generators.attic = { dependencies = [ "attic" ];
runtimeInputs = [ runtimeInputs = [
pkgs.coreutils pkgs.coreutils
pkgs.openssl pkgs.gnused
]; ];
files.token = { script = lib.concatStringsSep "\n" (
lib.mapAttrsToList (template: _: ''
cp "$templates/${template}" "$out/${template}"
echo "filling placeholders in template ${template}..."
${lib.concatStringsSep "\n" (
lib.mapAttrsToList (
parent:
{ placeholder, ... }:
''
sed -i "s/${placeholder}/$(cat "$in/attic/${parent}")/g" "$out/${template}"
echo "- substituted ${parent}"
''
) config.vars.generators."attic".files
)}
'') files
);
files."attic.env" = {
secret = true; secret = true;
owner = "atticd"; template = pkgs.writeText "attic.env" ''
ATTIC_SERVER_TOKEN_RS256_SECRET_BASE64=${config.vars.generators.attic.files.token.placeholder}
AWS_ACCESS_KEY_ID=$(cat ${config.fediversity.attic.s3AccessKeyFile})
AWS_SECRET_ACCESS_KEY=$(cat ${config.fediversity.attic.s3SecretKeyFile})
'';
}; };
script = ''
openssl genrsa -traditional 4096 | base64 -w0 > "$out"/token
'';
}; };
systemd.services.atticd.serviceConfig = { vars.generators.attic = {
EnvironmentFile = lib.mkForce "-/tmp/attic.env"; runtimeInputs = [ pkgs.openssl ];
ExecStartPre = "${ files.token.secret = true;
template_text { script = ''
# FIXME find a place not public genrsa -traditional 4096 | base64 -w0 > "$out"/token
outPath = "/tmp/attic.env"; '';
text = ''
ATTIC_SERVER_TOKEN_RS256_SECRET_BASE64="${fileContents config.vars.generators.attic.files.token.path}"
AWS_ACCESS_KEY_ID="${fileContents config.fediversity.attic.s3AccessKeyFile}"
AWS_SECRET_ACCESS_KEY="${fileContents config.fediversity.attic.s3SecretKeyFile}"
'';
name = "write";
}
}/bin/write";
}; };
services.atticd = { services.atticd = {
enable = true; enable = true;
environmentFile = "/dev/null"; # set dummy to overwrite
# one `monolithic` and any number of `api-server` nodes # one `monolithic` and any number of `api-server` nodes
mode = "monolithic"; mode = "monolithic";
environmentFile = config.vars.generators."templates".files."attic.env".path;
# https://github.com/zhaofengli/attic/blob/main/server/src/config-template.toml # https://github.com/zhaofengli/attic/blob/main/server/src/config-template.toml
settings = { settings = {
# Socket address to listen on # Socket address to listen on
listen = "127.0.0.1:8080"; # listen = "[::]:8080";
listen = "0.0.0.0:8080";
# listen = "127.0.0.1:8080";
# Allowed `Host` headers # Allowed `Host` headers
# #

View file

@ -50,7 +50,7 @@ in
displayName = mkOption { displayName = mkOption {
type = types.str; type = types.str;
description = "Name of the initial user, for humans"; description = "Name of the initial user, for humans";
default = config.fediversity.temp.initialUser.username; default = config.fediversity.temp.initialUser.name;
}; };
email = mkOption { email = mkOption {
type = types.str; type = types.str;
@ -66,16 +66,4 @@ in
}; };
}; };
}; };
config = {
## FIXME: This should clearly go somewhere else; and we should have a
## `staging` vs. `production` setting somewhere.
security.acme = {
acceptTerms = true;
# use a priority more urgent than mkDefault for panel deployment to work,
# yet looser than default so this will not clash with the setting in tests.
defaults.email = lib.modules.mkOverride 200 "something@fediversity.net";
# defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory";
};
};
} }

View file

@ -1,14 +0,0 @@
{ ... }:
{
_class = "flake";
perSystem =
{ pkgs, ... }:
{
checks = {
test-mastodon-service = pkgs.testers.runNixOSTest ./mastodon.nix;
test-pixelfed-garage-service = pkgs.testers.runNixOSTest ./pixelfed-garage.nix;
test-peertube-service = pkgs.testers.runNixOSTest ./peertube.nix;
};
};
}

View file

@ -6,7 +6,7 @@
{ pkgs, ... }: { pkgs, ... }:
let let
inherit (pkgs) lib writeText; lib = pkgs.lib;
## FIXME: this binding was not used, but maybe we want a side-effect or something? ## FIXME: this binding was not used, but maybe we want a side-effect or something?
# rebuildableTest = import ./rebuildableTest.nix pkgs; # rebuildableTest = import ./rebuildableTest.nix pkgs;
@ -69,17 +69,9 @@ in
expect expect
]; ];
environment.variables = { environment.variables = {
AWS_ACCESS_KEY_ID = "$(cat ${config.fediversity.mastodon.s3AccessKeyFile})"; AWS_ACCESS_KEY_ID = config.fediversity.garage.ensureKeys.mastodon.id;
AWS_SECRET_ACCESS_KEY = "$(cat ${config.fediversity.mastodon.s3SecretKeyFile})"; AWS_SECRET_ACCESS_KEY = config.fediversity.garage.ensureKeys.mastodon.secret;
}; };
services.mastodon.extraEnvFiles = [
# generate as: cd ${pkgs.mastodon}; IGNORE_ALREADY_SET_SECRETS=true RAILS_ENV=development ${pkgs.mastodon}/bin/rails db:encryption:init
(writeText "rest" ''
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY=naGoEzeyjUmwIlmgZZmGQDWJrlWud5eX
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT=A0tE1VJ7S3cjaOQ58mNkhrVFY7o5NKDB
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY=tGHhd5Os7hLxa8QTzWwjyVLrvsj5VsCw
'')
];
}; };
}; };

View file

@ -113,7 +113,6 @@ let
${seleniumQuit}''; ${seleniumQuit}'';
dummyFile = pkgs.writeText "dummy" "dummy";
in in
{ {
name = "test-pixelfed-garage"; name = "test-pixelfed-garage";
@ -162,8 +161,8 @@ in
]; ];
environment.variables = { environment.variables = {
POST_MEDIA = ./fediversity.png; POST_MEDIA = ./fediversity.png;
AWS_ACCESS_KEY_ID = "$(cat ${config.fediversity.pixelfed.s3AccessKeyFile})"; AWS_ACCESS_KEY_ID = config.fediversity.garage.ensureKeys.pixelfed.id;
AWS_SECRET_ACCESS_KEY = "$(cat ${config.fediversity.pixelfed.s3SecretKeyFile})"; AWS_SECRET_ACCESS_KEY = config.fediversity.garage.ensureKeys.pixelfed.secret;
## without this we get frivolous errors in the logs ## without this we get frivolous errors in the logs
MC_REGION = "garage"; MC_REGION = "garage";
}; };
@ -171,12 +170,6 @@ in
users.users.selenium = { users.users.selenium = {
isNormalUser = true; isNormalUser = true;
}; };
fediversity.temp.initialUser = {
username = "dummy";
displayName = "dummy";
email = "dummy";
passwordFile = dummyFile;
};
}; };
}; };