Compare commits

..

16 commits

Author SHA1 Message Date
222fca8249
use mapAttrs right
`mapAttrs'` takes two args rather than a set, whereas if only the val
changes `mapAttrs (_: v: ...)` should do
2025-07-04 23:04:28 +02:00
4880766c59
test for configuration passes, test for deployment wip 2025-07-03 20:31:26 +02:00
d185d5f94f
fix typos, lint, format 2025-07-03 20:23:04 +02:00
ba047997f2 WIP: illustrate an entire NixOS configuration as a resource 2025-07-03 13:08:14 +02:00
0c592d81f3 WIP: (broken) implement test 2025-07-02 03:39:36 +02:00
f8d1be9f6e WIP: implement mappings 2025-07-02 01:20:35 +02:00
7a667c7517 WIP: start writing an evaluation test
turns out we also need a collection of configurations, obviously
next: figure out where to wire everything up to obtain a deployment
2025-07-01 23:59:16 +02:00
5c97e35970 WIP: add missing types 2025-07-01 22:07:42 +02:00
3ec853a32a WIP: implement data model as in diagram
this doesn't update the tests yet because we don't have all the data
types in place anyway yet, and I still need to come up with testable examples.
2025-07-01 17:55:46 +02:00
c764c0f7b6
better reflect naming from diagram configuration data flow 2025-06-30 14:20:21 +02:00
34529a7de4
data model: migration 2025-06-23 19:22:47 +02:00
6c2022d064
data model: deployment 2025-06-23 16:35:11 +02:00
f51462afc9
data model: runtime environment
allows declaring options so instantiations may configure required
settings
2025-06-23 16:35:04 +02:00
fefcd93bc1
grant run-time environments their own modules with their own description 2025-06-23 11:25:18 +02:00
c1f3aa6aed
have run-time environments use their corresponding run-time configurations 2025-06-23 09:34:59 +02:00
8b2ee21dbe
data model: add run-time configuration 2025-06-23 09:06:52 +02:00
82 changed files with 442 additions and 549 deletions

View file

@ -25,13 +25,13 @@ jobs:
runs-on: native
steps:
- uses: actions/checkout@v4
- run: nix-build services -A tests.peertube
- run: cd services && nix-build -A tests.peertube
check-panel:
runs-on: native
steps:
- uses: actions/checkout@v4
- run: nix-build panel -A tests
- run: cd panel && nix-build -A tests
check-deployment-basic:
runs-on: native

View file

@ -2,9 +2,8 @@ name: update-dependencies
on:
workflow_dispatch: # allows manual triggering
# FIXME: re-enable when manual run works
# schedule:
# - cron: '0 0 1 * *' # monthly
schedule:
- cron: '0 0 1 * *' # monthly
jobs:
lockfile:
@ -12,12 +11,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Update pins
- name: Install npins
run: nix-shell --run "npins update"
- name: Create PR
uses: https://github.com/KiaraGrouwstra/gitea-create-pull-request@f9f80aa5134bc5c03c38f5aaa95053492885b397
uses: peter-evans/create-pull-request@v7
with:
remote-instance-api-version: v1
token: "${{ secrets.DEPLOY_KEY }}"
branch: npins-update
commit-message: "npins: update sources"

View file

@ -9,9 +9,9 @@ let
git-hooks
gitignore
;
inherit (pkgs) lib;
inherit (import sources.flake-inputs) import-flake;
inherit ((import-flake { src = ./.; }).inputs) nixops4;
inputs = (import-flake { src = ./.; }).inputs;
inherit (pkgs) lib;
pre-commit-check =
(import "${git-hooks}/nix" {
inherit nixpkgs system;
@ -57,15 +57,8 @@ in
};
in
[
pkgs.npins
pkgs.nil
(pkgs.callPackage "${sources.agenix}/pkgs/agenix.nix" { })
pkgs.openssh
pkgs.httpie
pkgs.jq
pkgs.nix-unit
test-loop
nixops4.packages.${system}.default
];
};
@ -76,6 +69,7 @@ in
# re-export inputs so they can be overridden granularly
# (they can't be accessed from the outside any other way)
inherit
inputs
sources
system
pkgs

View file

@ -2,7 +2,6 @@
self,
inputs,
lib,
sources,
...
}:
@ -18,8 +17,6 @@ let
in
{
_class = "flake";
perSystem =
{ pkgs, ... }:
{
@ -28,7 +25,7 @@ in
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
_module.args.inputs = inputs;
inherit targetMachines pathToRoot pathFromRoot;
};
};
@ -45,7 +42,7 @@ in
inputs.nixops4-nixos.modules.nixops4Resource.nixos
../common/targetResource.nix
];
_module.args = { inherit inputs sources; };
_module.args.inputs = inputs;
inherit nodeName pathToRoot pathFromRoot;
nixos.module =
{ pkgs, ... }:

View file

@ -1,8 +1,6 @@
{ inputs, ... }:
{
_class = "nixosTest";
name = "deployment-basic";
nodes.deployer =

View file

@ -2,7 +2,6 @@
self,
inputs,
lib,
sources,
...
}:
@ -21,8 +20,6 @@ let
in
{
_class = "flake";
perSystem =
{ pkgs, ... }:
{
@ -31,7 +28,7 @@ in
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
_module.args.inputs = inputs;
inherit
targetMachines
pathToRoot
@ -45,7 +42,7 @@ in
let
makeTargetResource = nodeName: {
imports = [ ../common/targetResource.nix ];
_module.args = { inherit inputs sources; };
_module.args.inputs = inputs;
inherit
nodeName
pathToRoot

View file

@ -7,8 +7,6 @@ let
in
{
_class = "nixosTest";
name = "deployment-cli";
nodes.deployer =

View file

@ -3,7 +3,6 @@
lib,
pkgs,
config,
sources,
...
}:
@ -15,10 +14,10 @@ let
types
;
sources = import ../../../npins;
in
{
_class = "nixos";
imports = [ ./sharedOptions.nix ];
options.system.extraDependenciesFromModule = mkOption {
@ -54,12 +53,13 @@ in
system.extraDependencies =
[
inputs.nixops4
inputs.nixops4-nixos
inputs.nixpkgs
"${inputs.flake-parts}"
"${inputs.flake-parts.inputs.nixpkgs-lib}"
"${inputs.nixops4}"
"${inputs.nixops4-nixos}"
"${inputs.nixpkgs}"
sources.flake-parts
sources.flake-inputs
"${sources.flake-inputs}"
pkgs.stdenv
pkgs.stdenvNoCC
@ -76,7 +76,7 @@ in
config.system.extraDependenciesFromModule
{
nixpkgs.hostPlatform = "x86_64-linux";
_module.args = { inherit inputs sources; };
_module.args.inputs = inputs;
enableAcme = config.enableAcme;
acmeNodeIP = config.acmeNodeIP;
}

View file

@ -3,7 +3,6 @@
lib,
config,
hostPkgs,
sources,
...
}:
@ -43,8 +42,6 @@ let
in
{
_class = "nixosTest";
imports = [
./sharedOptions.nix
];
@ -62,7 +59,7 @@ in
{
deployer = {
imports = [ ./deployerNode.nix ];
_module.args = { inherit inputs sources; };
_module.args.inputs = inputs;
enableAcme = config.enableAcme;
acmeNodeIP = config.nodes.acme.networking.primaryIPAddress;
};
@ -89,7 +86,7 @@ in
genAttrs config.targetMachines (_: {
imports = [ ./targetNode.nix ];
_module.args = { inherit inputs sources; };
_module.args.inputs = inputs;
enableAcme = config.enableAcme;
acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null;
});
@ -138,6 +135,7 @@ in
deployer.succeed("""
nix flake lock --extra-experimental-features 'flakes nix-command' \
--offline -v \
--override-input flake-parts ${inputs.flake-parts} \
--override-input nixops4 ${inputs.nixops4.packages.${system}.flake-in-a-bottle} \
\
--override-input nixops4-nixos ${inputs.nixops4-nixos} \
@ -150,6 +148,7 @@ in
} \
--override-input nixops4-nixos/git-hooks-nix ${emptyFlake} \
\
--override-input nixpkgs ${inputs.nixpkgs} \
--override-input git-hooks ${inputs.git-hooks} \
;
""")

View file

@ -11,7 +11,6 @@ let
inherit (lib) mkOption types;
in
# `config` not set and imported from multiple places: no fixed module class
{
options = {
targetMachines = mkOption {

View file

@ -12,8 +12,6 @@ let
in
{
_class = "nixos";
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
(modulesPath + "/../lib/testing/nixos-test-base.nix")

View file

@ -2,7 +2,6 @@
inputs,
lib,
config,
sources,
...
}:
@ -13,8 +12,6 @@ let
in
{
_class = "nixops4Resource";
imports = [ ./sharedOptions.nix ];
options = {
@ -41,7 +38,7 @@ in
(lib.modules.importJSON (config.pathToCwd + "/${config.nodeName}-network.json"))
];
_module.args = { inherit inputs sources; };
_module.args.inputs = inputs;
enableAcme = config.enableAcme;
acmeNodeIP = trim (readFile (config.pathToCwd + "/acme_server_ip"));

View file

@ -2,7 +2,6 @@
self,
inputs,
lib,
sources,
...
}:
@ -24,8 +23,6 @@ let
in
{
_class = "flake";
perSystem =
{ pkgs, ... }:
{
@ -34,7 +31,7 @@ in
../common/nixosTest.nix
./nixosTest.nix
];
_module.args = { inherit inputs sources; };
_module.args.inputs = inputs;
inherit
targetMachines
pathToRoot
@ -48,7 +45,7 @@ in
let
makeTargetResource = nodeName: {
imports = [ ../common/targetResource.nix ];
_module.args = { inherit inputs sources; };
_module.args.inputs = inputs;
inherit
nodeName
pathToRoot

View file

@ -121,8 +121,6 @@ let
in
{
_class = "nixosTest";
name = "deployment-panel";
## The panel's module sets `nixpkgs.overlays` which clashes with
@ -155,6 +153,7 @@ in
SECRET_KEY = dummyFile;
};
port = panelPort;
nixops4Package = inputs.nixops4.packages.${pkgs.system}.default;
deployment = {
flake = "/run/fedipanel/flake";

View file

@ -1,7 +1,7 @@
let
inherit (import ../default.nix { }) pkgs inputs;
inherit (pkgs) lib;
inherit (lib) mkOption;
inherit (lib) mkOption types;
eval =
module:
(lib.evalModules {
@ -13,10 +13,9 @@ let
./data-model.nix
];
}).config;
nixops4Deployment = inputs.nixops4.modules.nixops4Deployment.default;
in
{
_class = "nix-unit";
test-eval = {
expr =
let
@ -24,6 +23,84 @@ in
{ config, ... }:
{
config = {
resources.nixos-configuration = {
description = "An entire NixOS configuration";
request =
{ ... }:
{
_class = "fediversity-resource-request";
options.config = mkOption {
description = "Any options from NixOS";
};
};
policy =
{ config, ... }:
{
_class = "fediversity-resource-policy";
options = {
extra-config = mkOption {
description = "Any options from NixOS";
};
apply = mkOption {
type = with types; functionTo raw;
default = requests: lib.mkMerge (requests ++ [ config.extra-config ]);
};
};
};
};
resources.login-shell = {
description = "The operator needs to be able to log into the shell";
request =
{ ... }:
{
_class = "fediversity-resource-request";
options = {
wheel = mkOption {
description = "Whether the login user needs root permissions";
type = types.bool;
default = false;
};
packages = mkOption {
description = "Packages that need to be available in the user environment";
type = with types; attrsOf package;
};
};
};
policy =
{ config, ... }:
{
_class = "fediversity-resource-policy";
options = {
username = mkOption {
description = "Username for the operator";
type = types.str; # TODO: use the proper constraints from NixOS
};
wheel = mkOption {
description = "Whether to allow login with root permissions";
type = types.bool;
default = false;
};
apply = mkOption {
type = with types; functionTo raw; # TODO: splice out the user type from NixOS
default =
requests:
let
# Filter out requests that need wheel if policy doesn't allow it
validRequests = lib.filterAttrs (_name: req: !req.wheel || config.wheel) requests;
in
lib.optionalAttrs (validRequests != { }) {
${config.username} = {
isNormalUser = true;
packages = with lib; concatMapAttrs (_name: request: attrValues request.packages) validRequests;
extraGroups = lib.optional config.wheel "wheel";
};
};
};
};
};
};
applications.hello =
{ ... }:
{
@ -41,6 +118,32 @@ in
dummy.login-shell.packages.hello = pkgs.hello;
};
};
environments.single-nixos-vm =
{ config, ... }:
{
resources.shell.login-shell.username = "operator";
implementation =
requests:
{ providers, ... }:
{
providers = {
inherit (inputs.nixops4.modules.nixops4Provider) local;
};
resources.the-machine = {
type = providers.local.exec;
imports = [
inputs.nixops4-nixos.modules.nixops4Resource.nixos
];
nixos.module =
{ ... }:
{
users.users = config.resources.shell.login-shell.apply (
lib.filterAttrs (_name: value: value ? login-shell) requests
);
};
};
};
};
};
options = {
example-configuration = mkOption {
@ -51,6 +154,11 @@ in
applications.hello.enable = true;
};
};
example-deployment = mkOption {
type = types.submodule nixops4Deployment;
readOnly = true;
default = config.environments.single-nixos-vm.deployment config.example-configuration;
};
};
}
);
@ -58,6 +166,7 @@ in
{
inherit (fediversity)
example-configuration
example-deployment
;
};
expected = {

View file

@ -1,6 +1,7 @@
{
lib,
config,
inputs,
...
}:
let
@ -23,11 +24,44 @@ let
);
};
};
nixops4Deployment = inputs.nixops4.modules.nixops4Deployment.default;
in
{
_class = "nixops4Deployment";
options = {
resources = mkOption {
description = "Collection of deployment resources that can be required by applications and policed by hosting providers";
type = attrsOf (
submodule (
{ ... }:
{
_class = "fediversity-resource";
options = {
description = mkOption {
description = "Description of the resource to help application module authors and hosting providers to work with it";
type = types.str;
};
request = mkOption {
description = "Options for declaring resource requirements by an application, a description of how the resource is consumed or accessed";
type = deferredModuleWith { staticModules = [ { _class = "fediversity-resource-request"; } ]; };
};
policy = mkOption {
description = "Options for configuring the resource policy for the hosting provider, a description of how the resource is made available";
type = deferredModuleWith {
staticModules = [
{
_class = "fediversity-resource-policy";
options.apply = mkOption {
description = "Apply the policy to a request";
};
}
];
};
};
};
}
)
);
};
applications = mkOption {
description = "Collection of Fediversity applications";
type = attrsOf (
@ -65,6 +99,57 @@ in
})
);
};
environments = mkOption {
description = "Run-time environments for Fediversity applications to be deployed to";
type = attrsOf (
submodule (environment: {
_class = "fediversity-environment";
options = {
resources = mkOption {
description = ''
Resources made available by the hosting provider, and their policies.
Setting this is optional, but provides a place to declare that information for programmatic use in the resource mapping.
'';
# TODO: maybe transpose, and group the resources by type instead
type = attrsOf (
attrTag (
lib.mapAttrs (_name: resource: mkOption { type = submodule resource.policy; }) config.resources
)
);
};
implementation = mkOption {
description = "Mapping of resources required by applications to available resources; the result can be deployed";
type = environment.config.resource-mapping.function-type;
};
resource-mapping = mkOption {
description = "Function type for the mapping from resources to a (NixOps4) deployment";
type = submodule functionType;
readOnly = true;
default = {
input-type = application-resources;
output-type = nixops4Deployment;
};
};
deployment = mkOption {
description = "Generate a deployment from a configuration";
type = functionTo environment.config.resource-mapping.output-type;
readOnly = true;
default =
cfg:
# TODO: check cfg.enable.true
let
required-resources = lib.mapAttrs (
name: application-settings: config.applications.${name}.resources application-settings
) cfg.applications;
in
(environment.config.implementation required-resources).output;
};
};
})
);
};
configuration = mkOption {
description = "Configuration type declaring options to be set by operators";
type = optionType;

View file

@ -65,8 +65,6 @@ let
cfg = config.deployment;
in
{
_class = "nixops4Deployment";
options = {
deployment = lib.mkOption {
description = ''

View file

@ -1,6 +1,4 @@
{
_class = "flake";
imports = [
./check/basic/flake-part.nix
./check/cli/flake-part.nix

View file

@ -22,16 +22,18 @@ in
function-type = mkOption {
type = optionType;
readOnly = true;
default = functionTo (submodule {
options = {
input = mkOption {
type = submodule config.input-type;
default = functionTo (
submodule (function: {
options = {
input = mkOption {
type = submodule config.input-type;
};
output = mkOption {
type = submodule config.output-type;
};
};
output = mkOption {
type = submodule config.output-type;
};
};
});
})
);
};
};
}

View file

@ -17,8 +17,6 @@ let
inherit (lib) types mkOption;
in
{
_class = "nixops4Deployment";
options = {
enable = lib.mkEnableOption "Fediversity configuration";
domain = mkOption {

37
flake.lock generated
View file

@ -143,6 +143,24 @@
}
},
"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": {
"nixpkgs-lib": [
"nixops4-nixos",
@ -324,7 +342,7 @@
"nix": {
"inputs": {
"flake-compat": "flake-compat_3",
"flake-parts": "flake-parts_3",
"flake-parts": "flake-parts_4",
"git-hooks-nix": "git-hooks-nix_2",
"nixfmt": "nixfmt",
"nixpkgs": [
@ -398,7 +416,7 @@
},
"nixops4": {
"inputs": {
"flake-parts": "flake-parts_2",
"flake-parts": "flake-parts_3",
"nix": "nix",
"nix-cargo-integration": "nix-cargo-integration",
"nixpkgs": "nixpkgs_3",
@ -420,7 +438,7 @@
},
"nixops4-nixos": {
"inputs": {
"flake-parts": "flake-parts",
"flake-parts": "flake-parts_2",
"git-hooks-nix": "git-hooks-nix",
"nixops4": "nixops4",
"nixops4-nixos": [
@ -502,6 +520,18 @@
"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": {
"locked": {
"lastModified": 1735563628,
@ -634,6 +664,7 @@
},
"root": {
"inputs": {
"flake-parts": "flake-parts",
"git-hooks": "git-hooks",
"nixops4": [
"nixops4-nixos",

120
flake.nix
View file

@ -1,48 +1,94 @@
{
inputs = {
flake-parts.url = "github:hercules-ci/flake-parts";
git-hooks.url = "github:cachix/git-hooks.nix";
nixops4.follows = "nixops4-nixos/nixops4";
nixops4-nixos.url = "github:nixops4/nixops4-nixos";
};
outputs =
inputs:
import ./mkFlake.nix inputs (
{ inputs, ... }:
inputs@{ self, flake-parts, ... }:
let
sources = import ./npins;
inherit (import sources.flake-inputs) import-flake;
inherit (sources) git-hooks agenix;
# 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.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;
};
};
inputs = inputs // {
inherit nixpkgs;
};
self = self';
}
);
(
{ inputs, ... }:
{
systems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
imports = [
(import "${git-hooks}/flake-module.nix")
inputs.nixops4.modules.flake.default
./deployment/flake-part.nix
./infra/flake-part.nix
];
perSystem =
{
pkgs,
lib,
inputs',
...
}:
{
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;
};
devShells.default = pkgs.mkShell {
packages = [
pkgs.npins
pkgs.nil
(pkgs.callPackage "${agenix}/pkgs/agenix.nix" { })
pkgs.openssh
pkgs.httpie
pkgs.jq
# exposing this env var as a hack to pass info in from form
(inputs'.nixops4.packages.default.overrideAttrs {
impureEnvVars = [ "DEPLOYMENT" ];
})
];
};
};
}
);
}

View file

@ -5,9 +5,8 @@ let
in
{
_class = "nixos";
imports = [
./hardware.nix
./networking.nix
./users.nix
];
@ -23,9 +22,4 @@ in
nix.extraOptions = ''
experimental-features = nix-command flakes
'';
boot.loader = {
systemd-boot.enable = true;
efi.canTouchEfiVariables = true;
};
}

View file

@ -1,15 +1,20 @@
{ modulesPath, ... }:
{
_class = "nixos";
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
boot = {
loader = {
systemd-boot.enable = true;
efi.canTouchEfiVariables = true;
};
initrd = {
availableKernelModules = [
"ata_piix"
"uhci_hcd"
"virtio_pci"
"virtio_scsi"
"sd_mod"
"sr_mod"
];

View file

@ -1,64 +1,63 @@
{ config, lib, ... }:
let
inherit (lib) mkDefault mkIf mkMerge;
inherit (lib) mkDefault;
in
{
_class = "nixos";
config = {
services.openssh = {
enable = true;
settings.PasswordAuthentication = false;
};
networking = mkMerge [
{
hostName = config.fediversityVm.name;
domain = config.fediversityVm.domain;
networking = {
hostName = config.fediversityVm.name;
domain = config.fediversityVm.domain;
## REVIEW: Do we actually need that, considering that we have static IPs?
useDHCP = mkDefault true;
## REVIEW: Do we actually need that, considering that we have static IPs?
useDHCP = mkDefault true;
## Disable the default firewall and use nftables instead, with a custom
## Procolix-made ruleset.
firewall.enable = false;
nftables = {
enable = true;
rulesetFile = ./nftables-ruleset.nft;
interfaces = {
eth0 = {
ipv4 = {
addresses = [
{
inherit (config.fediversityVm.ipv4) address prefixLength;
}
];
};
ipv6 = {
addresses = [
{
inherit (config.fediversityVm.ipv6) address prefixLength;
}
];
};
};
}
};
## IPv4
(mkIf config.fediversityVm.ipv4.enable {
interfaces.${config.fediversityVm.ipv4.interface}.ipv4.addresses = [
{ inherit (config.fediversityVm.ipv4) address prefixLength; }
];
defaultGateway = {
address = config.fediversityVm.ipv4.gateway;
interface = config.fediversityVm.ipv4.interface;
};
nameservers = [
"95.215.185.6"
"95.215.185.7"
];
})
defaultGateway = {
address = config.fediversityVm.ipv4.gateway;
interface = "eth0";
};
defaultGateway6 = {
address = config.fediversityVm.ipv6.gateway;
interface = "eth0";
};
## IPv6
(mkIf config.fediversityVm.ipv6.enable {
interfaces.${config.fediversityVm.ipv6.interface}.ipv6.addresses = [
{ inherit (config.fediversityVm.ipv6) address prefixLength; }
];
defaultGateway6 = {
address = config.fediversityVm.ipv6.gateway;
interface = config.fediversityVm.ipv6.interface;
};
nameservers = [
"2a00:51c0::5fd7:b906"
"2a00:51c0::5fd7:b907"
];
})
];
nameservers = [
"95.215.185.6"
"95.215.185.7"
"2a00:51c0::5fd7:b906"
"2a00:51c0::5fd7:b907"
];
firewall.enable = false;
nftables = {
enable = true;
rulesetFile = ./nftables-ruleset.nft;
};
};
};
}

View file

@ -1,6 +1,4 @@
{
_class = "nixos";
users.users = {
procolix = {
isNormalUser = true;

View file

@ -6,8 +6,6 @@ let
in
{
# `config` not set and imported from multiple places: no fixed module class
options.fediversityVm = {
##########################################################################
@ -91,17 +89,6 @@ in
};
ipv4 = {
enable = mkOption {
default = true;
};
interface = mkOption {
description = ''
The interface that carries the machine's IPv4 network.
'';
default = "eth0";
};
address = mkOption {
description = ''
The IP address of the machine, version 4. It will be injected as a
@ -127,17 +114,6 @@ in
};
ipv6 = {
enable = mkOption {
default = true;
};
interface = mkOption {
description = ''
The interface that carries the machine's IPv6 network.
'';
default = "eth0";
};
address = mkOption {
description = ''
The IP address of the machine, version 6. It will be injected as a

View file

@ -2,9 +2,6 @@
inputs,
lib,
config,
sources,
keys,
secrets,
...
}:
@ -12,11 +9,15 @@ let
inherit (lib) attrValues elem mkDefault;
inherit (lib.attrsets) concatMapAttrs optionalAttrs;
inherit (lib.strings) removeSuffix;
sources = import ../../npins;
inherit (sources) agenix disko;
secretsPrefix = ../../secrets;
secrets = import (secretsPrefix + "/secrets.nix");
keys = import ../../keys;
in
{
_class = "nixops4Resource";
imports = [ ./options.nix ];
fediversityVm.hostPublicKey = mkDefault keys.systems.${config.fediversityVm.name};
@ -33,8 +34,8 @@ in
## should go into the `./nixos` subdirectory.
nixos.module = {
imports = [
"${sources.agenix}/modules/age.nix"
"${sources.disko}/module.nix"
(import "${agenix}/modules/age.nix")
(import "${disko}/module.nix")
./options.nix
./nixos
];
@ -43,15 +44,15 @@ in
## configuration.
fediversityVm = config.fediversityVm;
## Read all the secrets, filter the ones that are supposed to be readable with
## public key, and create a mapping from `<name>.file` to the absolute path of
## the secret's file.
## 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 = secrets.rootPath + "/${name}";
}
) secrets.mapping;
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.

View file

@ -1,9 +1,6 @@
{
inputs,
lib,
sources,
keys,
secrets,
...
}:
@ -16,6 +13,7 @@ let
filterAttrs
;
inherit (lib.attrsets) genAttrs;
sources = import ../../npins;
## Given a machine's name and whether it is a test VM, make a resource module,
## except for its missing provider. (Depending on the use of that resource, we
@ -24,14 +22,7 @@ let
{ vmName, isTestVm }:
{
# 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
_module.args = {
inherit
inputs
sources
keys
secrets
;
};
_module.args = { inherit inputs; };
imports =
[
@ -40,12 +31,11 @@ let
++ (
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
(import ../keys).panel
];
}
]
@ -165,8 +155,6 @@ let
in
{
_class = "flake";
## - Each normal or test machine gets a NixOS configuration.
## - Each normal or test machine gets a VM options entry.
## - Each normal machine gets a deployment.

View file

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

View file

@ -1,5 +0,0 @@
{
_class = "flake";
_module.args.keys = import ./.;
}

View file

@ -1 +0,0 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIFXQW5fxJoNY9wtTMsNExgbAbvyljIRGBLjY+USh/0A

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 200;
proxmox = "fediversity";
@ -16,10 +14,4 @@
gateway = "2a00:51c0:13:1305::1";
};
};
nixos.module = {
imports = [
../../../infra/common/proxmox-qemu-vm.nix
];
};
}

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 201;
proxmox = "fediversity";
@ -19,7 +17,6 @@
nixos.module = {
imports = [
../../../infra/common/proxmox-qemu-vm.nix
./fedipanel.nix
];
};

View file

@ -1,17 +1,13 @@
{
config,
sources,
...
}:
let
name = "panel";
in
{
_class = "nixos";
imports = [
(import ../../../panel { }).module
(import "${sources.home-manager}/nixos")
];
security.acme = {

View file

@ -1,70 +0,0 @@
{ lib, ... }:
let
inherit (lib) mkDefault mkForce;
in
{
_class = "nixops4Resource";
# NOTE: This needs an SSH config entry `forgejo-ci` to locate and access the
# machine. This is because different people access the machine in different
# way (eg. via a proxy vs. via Procolix's VPN). This might look like:
#
# Host forgejo-ci
# HostName 45.142.234.216
# HostKeyAlias forgejo-ci
#
# The `HostKeyAlias` statement is crucial. Without it, deployment will fail
# with the SSH error “Host key verification failed”.
ssh.host = mkForce "forgejo-ci";
fediversityVm = {
domain = "procolix.com";
ipv4 = {
interface = "enp1s0f0";
address = "192.168.201.65";
prefixLength = 24;
gateway = "192.168.201.1";
};
ipv6.enable = false;
};
nixos.module =
{ config, ... }:
{
_class = "nixos";
imports = [
./forgejo-actions-runner.nix
];
hardware.cpu.intel.updateMicrocode = mkDefault config.hardware.enableRedistributableFirmware;
networking = {
nftables.enable = mkForce false;
hostId = "1d6ea552";
};
## NOTE: This is a physical machine, so is not covered by disko
fileSystems."/" = {
device = "rpool/root";
fsType = "zfs";
};
fileSystems."/home" = {
device = "rpool/home";
fsType = "zfs";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/50B2-DD3F";
fsType = "vfat";
options = [
"fmask=0077"
"dmask=0077"
];
};
};
}

View file

@ -1,47 +0,0 @@
{ pkgs, config, ... }:
{
_class = "nixos";
services.gitea-actions-runner = {
package = pkgs.forgejo-actions-runner;
instances.default = {
enable = true;
name = config.networking.fqdn;
url = "https://git.fediversity.eu";
tokenFile = config.age.secrets.forgejo-runner-token.path;
settings = {
log.level = "info";
runner = {
file = ".runner";
# Take only 1 job at a time to avoid clashing NixOS tests, see #362
capacity = 1;
timeout = "3h";
insecure = false;
fetch_timeout = "5s";
fetch_interval = "2s";
};
};
## This runner supports Docker (with a default Ubuntu image) and native
## modes. In native mode, it contains a few default packages.
labels = [
"docker:docker://node:16-bullseye"
"native:host"
];
hostPackages = with pkgs; [
bash
git
nix
nodejs
];
};
};
## For the Docker mode of the runner.
virtualisation.docker.enable = true;
}

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 2116;
proxmox = "procolix";
@ -14,7 +12,6 @@
{ lib, ... }:
{
imports = [
../../../infra/common/proxmox-qemu-vm.nix
./forgejo.nix
];

View file

@ -5,8 +5,6 @@ let
in
{
_class = "nixos";
services.forgejo = {
enable = true;

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 2187;
proxmox = "procolix";
@ -14,7 +12,6 @@
{ lib, ... }:
{
imports = [
../../../infra/common/proxmox-qemu-vm.nix
./wiki.nix
];

View file

@ -1,8 +1,6 @@
{ config, ... }:
{
_class = "nixos";
services.phpfpm.pools.mediawiki.phpOptions = ''
upload_max_filesize = 1024M;
post_max_size = 1024M;

View file

@ -7,10 +7,9 @@ Currently, this repository keeps track of the following VMs:
Machine | Proxmox | Description
--------|---------|-------------
[`fedi200`](./dev/fedi200) | fediversity | Testing machine for Hans
[`fedi201`](./dev/fedi201) | fediversity | FediPanel
[`vm02116`](./dev/vm02116) | procolix | Forgejo
[`vm02187`](./dev/vm02187) | procolix | Wiki
| `forgejo-ci` | n/a (physical) | Forgejo actions runner |
[`fedi200`](./fedi200) | fediversity | Testing machine for Hans
[`fedi201`](./fedi201) | fediversity | FediPanel
[`vm02116`](./vm02116) | procolix | Forgejo
[`vm02187`](./vm02187) | procolix | Wiki
This table excludes all machines with names starting with `test`.

View file

@ -32,12 +32,11 @@ for machine in $(echo "$vmOptions" | jq -r 'keys[]'); do
description=$(echo "$vmOptions" | jq -r ".$machine.description" | head -n 1)
# shellcheck disable=SC2016
printf '[`%s`](./dev/%s) | %s | %s\n' "$machine" "$machine" "$proxmox" "$description"
printf '[`%s`](./%s) | %s | %s\n' "$machine" "$machine" "$proxmox" "$description"
fi
done
cat <<\EOF
| `forgejo-ci` | n/a (physical) | Forgejo actions runner |
This table excludes all machines with names starting with `test`.
EOF

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 7001;
proxmox = "fediversity";

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 7002;
proxmox = "fediversity";

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 7003;
proxmox = "fediversity";

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 7004;
proxmox = "fediversity";

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 7005;
proxmox = "fediversity";

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 7006;
proxmox = "fediversity";

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 7011;
proxmox = "fediversity";

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 7012;
proxmox = "fediversity";

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 7013;
proxmox = "fediversity";

View file

@ -1,6 +1,4 @@
{
_class = "nixops4Resource";
fediversityVm = {
vmId = 7014;
proxmox = "fediversity";

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

@ -96,19 +96,6 @@
"url": "https://github.com/hercules-ci/gitignore.nix/archive/637db329424fd7e46cf4185293b9cc8c88c95394.tar.gz",
"hash": "02wxkdpbhlm3yk5mhkhsp3kwakc16xpmsf2baw57nz1dg459qv8w"
},
"home-manager": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "nix-community",
"repo": "home-manager"
},
"branch": "master",
"submodules": false,
"revision": "863842639722dd12ae9e37ca83bcb61a63b36f6c",
"url": "https://github.com/nix-community/home-manager/archive/863842639722dd12ae9e37ca83bcb61a63b36f6c.tar.gz",
"hash": "0rw9n8d4v87pzlmw7ws15f0sldb51fd9528skpbzmrzl4pinsgij"
},
"htmx": {
"type": "GitRelease",
"repository": {

View file

@ -22,12 +22,12 @@ in
manage
# NixOps4 and its dependencies
pkgs.nixops4
# FIXME: grab NixOps4 and add it here
pkgs.nix
pkgs.openssh
];
env = {
DEPLOYMENT_FLAKE = toString ../.;
DEPLOYMENT_FLAKE = ../.;
DEPLOYMENT_NAME = "test";
NPINS_DIRECTORY = toString ../npins;
CREDENTIALS_DIRECTORY = toString ./.credentials;

View file

@ -76,8 +76,6 @@ in
# https://git.dgnum.eu/mdebray/djangonix/
# unlicensed at the time of writing, but surely worth taking some inspiration from...
{
_class = "nixos";
options.services.${name} = {
enable = mkEnableOption "Service configuration for `${name}`";
production = mkOption {
@ -147,7 +145,6 @@ in
NixOps4 from the package's npins-based code, we will have to do with
this workaround.
'';
default = pkgs.nixops4;
};
deployment = {
@ -202,8 +199,11 @@ in
};
};
# needed to place a config file with home-manager
users.users.${name}.isNormalUser = true;
users.users.${name} = {
# TODO[Niols]: change to system user or document why we specifically
# need a normal user.
isNormalUser = true;
};
users.groups.${name} = { };
systemd.services.${name} = {

View file

@ -8,17 +8,4 @@ let
in
{
python3 = prev.lib.attrsets.recursiveUpdate prev.python3 { pkgs = extraPython3Packages; };
nixops4 =
let
sources = import ../../npins;
inherit (import sources.flake-inputs) import-flake;
inherit
(import-flake {
src = ../../.;
})
inputs
;
inherit (inputs) nixops4;
in
nixops4.packages.${prev.system}.default;
}

View file

@ -60,8 +60,6 @@ let
];
in
python3.pkgs.buildPythonPackage {
_class = "package";
pname = name;
inherit (pyproject.project) version;
pyproject = true;

View file

@ -8,8 +8,6 @@
}:
buildPythonPackage rec {
_class = "package";
pname = "django-pydantic-field";
version = "v0.3.12";
pyproject = true;

View file

@ -10,8 +10,6 @@
}:
buildPythonPackage rec {
_class = "package";
pname = "drf-pydantic";
version = "v2.7.1";
pyproject = true;

View file

@ -13,6 +13,7 @@ let
secrets = {
SECRET_KEY = pkgs.writeText "SECRET_KEY" "secret";
};
nixops4Package = pkgs.hello; # FIXME: actually pass NixOps4
};
virtualisation = {

View file

@ -1,4 +0,0 @@
{
mapping = import ./secrets.nix;
rootPath = ./.;
}

View file

@ -1,5 +0,0 @@
{
_class = "flake";
_module.args.secrets = import ./.;
}

Binary file not shown.

View file

@ -26,7 +26,7 @@ concatMapAttrs
{
forgejo-database-password = [ vm02116 ];
forgejo-email-password = [ vm02116 ];
forgejo-runner-token = [ forgejo-ci ];
forgejo-runner-token = [ ];
panel-secret-key = [ fedi201 ];
panel-ssh-key = [ fedi201 ];
wiki-basicauth-htpasswd = [ vm02187 ];

View file

@ -6,8 +6,6 @@ let
in
{
_class = "nixos";
imports = [
./garage
./mastodon
@ -65,16 +63,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

@ -97,8 +97,6 @@ let
in
{
_class = "nixos";
imports = [ ./options.nix ];
config = mkIf config.fediversity.garage.enable {

View file

@ -5,8 +5,6 @@ let
in
{
_class = "nixos";
options.fediversity.garage = {
enable = mkEnableOption "Enable a Garage server on the machine";

View file

@ -11,8 +11,6 @@ let
in
{
_class = "nixos";
imports = [ ./options.nix ];
config = mkMerge [

View file

@ -1,8 +1,6 @@
{ config, lib, ... }:
{
_class = "nixos";
options.fediversity.mastodon =
(import ../sharedOptions.nix {
inherit config lib;

View file

@ -5,8 +5,6 @@ let
in
{
_class = "nixos";
imports = [ ./options.nix ];
config = mkMerge [

View file

@ -6,8 +6,6 @@ let
in
{
_class = "nixos";
options.fediversity.peertube =
(import ../sharedOptions.nix {
inherit config lib;

View file

@ -15,8 +15,6 @@ let
in
{
_class = "nixos";
imports = [ ./options.nix ];
config = mkMerge [

View file

@ -1,8 +1,6 @@
{ config, lib, ... }:
{
_class = "nixos";
options.fediversity.pixelfed =
(import ../sharedOptions.nix {
inherit config lib;

View file

@ -14,8 +14,6 @@ let
in
{
_class = "nixos";
enable = mkEnableOption "Enable a ${serviceDocName} server on the machine";
s3AccessKeyFile = mkOption {

View file

@ -127,8 +127,6 @@ let
preOverride = pkgs.nixosTest (
test
// {
_class = "nixosTest";
interactive = (test.interactive or { }) // {
# no need to // with test.interactive.nodes here, since we are iterating
# over all of them, and adding back in the config via `imports`

View file

@ -10,8 +10,6 @@ let
in
{
_class = "nixos";
imports = [ (modulesPath + "/virtualisation/qemu-vm.nix") ];
fediversity.garage.enable = true;

View file

@ -1,8 +1,6 @@
# customize nixos-rebuild build-vm to be a bit more convenient
{ pkgs, ... }:
{
_class = "nixos";
# let us log in
users.mutableUsers = false;
users.users.root.hashedPassword = "";

View file

@ -6,7 +6,6 @@
...
}:
{
_class = "nixos";
imports = [ (modulesPath + "/virtualisation/qemu-vm.nix") ];

View file

@ -5,8 +5,6 @@
}:
{
_class = "nixos";
imports = [ (modulesPath + "/virtualisation/qemu-vm.nix") ];
fediversity = {

View file

@ -11,8 +11,6 @@ let
in
{
_class = "nixos";
imports = [ (modulesPath + "/virtualisation/qemu-vm.nix") ];
fediversity = {