Compare commits

...

1 commit

Author SHA1 Message Date
Ilya K b8e196a385 treewide: add pre-commit nixfmt hook, reformat everything 2024-08-09 18:41:10 +03:00
48 changed files with 1320 additions and 823 deletions

1
.gitignore vendored
View file

@ -6,3 +6,4 @@ config.tf.json
.terraform.lock.hcl .terraform.lock.hcl
secrets/* secrets/*
!secrets/*.age !secrets/*.age
.pre-commit-config.yaml

View file

@ -1,16 +1,17 @@
let let
keys = import ./ssh-keys.nix; keys = import ./ssh-keys.nix;
in { in
{
users.users.root.openssh.authorizedKeys.keys = users.users.root.openssh.authorizedKeys.keys =
keys.users.delroth ++ keys.users.delroth
keys.users.emilylange ++ ++ keys.users.emilylange
keys.users.hexchen ++ ++ keys.users.hexchen
keys.users.jade ++ ++ keys.users.jade
keys.users.janik ++ ++ keys.users.janik
keys.users.k900 ++ ++ keys.users.k900
keys.users.lukegb ++ ++ keys.users.lukegb
keys.users.maxine ++ ++ keys.users.maxine
keys.users.raito ++ ++ keys.users.raito
keys.users.thubrecht ++ ++ keys.users.thubrecht
keys.users.yuka; ++ keys.users.yuka;
} }

View file

@ -1,7 +1,6 @@
{ lib, pkgs, ... }: { { lib, pkgs, ... }:
imports = [ {
./known-ssh-keys.nix imports = [ ./known-ssh-keys.nix ];
];
nixpkgs.overlays = import ../overlays; nixpkgs.overlays = import ../overlays;
@ -36,7 +35,8 @@
services.journald.extraConfig = "SystemMaxUse=512M"; services.journald.extraConfig = "SystemMaxUse=512M";
boot.kernelParams = [ boot.kernelParams = [
"panic=30" "boot.panic_on_fail" "panic=30"
"boot.panic_on_fail"
]; ];
boot.kernel.sysctl = { boot.kernel.sysctl = {

View file

@ -3,9 +3,9 @@
{ {
nix.settings.allowed-users = [ "root" ]; nix.settings.allowed-users = [ "root" ];
boot.specialFileSystems = lib.mkIf (!config.security.rtkit.enable && !config.security.polkit.enable) { boot.specialFileSystems = lib.mkIf (
"/proc".options = [ "hidepid=2" ]; !config.security.rtkit.enable && !config.security.polkit.enable
}; ) { "/proc".options = [ "hidepid=2" ]; };
boot.kernel.sysctl."kernel.dmesg_restrict" = 1; boot.kernel.sysctl."kernel.dmesg_restrict" = 1;
@ -14,9 +14,7 @@
settings.KbdInteractiveAuthentication = false; settings.KbdInteractiveAuthentication = false;
# prevents mutable /home/$user/.ssh/authorized_keys from being loaded to ensure that all user keys are config managed # prevents mutable /home/$user/.ssh/authorized_keys from being loaded to ensure that all user keys are config managed
authorizedKeysFiles = lib.mkForce [ authorizedKeysFiles = lib.mkForce [ "/etc/ssh/authorized_keys.d/%u" ];
"/etc/ssh/authorized_keys.d/%u"
];
}; };
users.mutableUsers = false; users.mutableUsers = false;

View file

@ -5,31 +5,52 @@ let
cfg = config.bagel.raito.v6-proxy-awareness; cfg = config.bagel.raito.v6-proxy-awareness;
allowedUpstream = "2001:bc8:38ee:99::1/128"; allowedUpstream = "2001:bc8:38ee:99::1/128";
in in
{ {
options.bagel.raito.v6-proxy-awareness.enable = mkEnableOption "the kurisu.lahfa.xyz's sniproxy awareness for NGINX"; options.bagel.raito.v6-proxy-awareness.enable = mkEnableOption "the kurisu.lahfa.xyz's sniproxy awareness for NGINX";
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.nginx = { services.nginx = {
# IPv6-only server # IPv6-only server
defaultListen = [ defaultListen = [
{ addr = "[::0]"; proxyProtocol = true; port = 444; ssl = true; } {
{ addr = "[::0]"; port = 443; ssl = true; } addr = "[::0]";
{ addr = "[::0]"; port = 80; ssl = false; } proxyProtocol = true;
# Private networking port = 444;
{ addr = "127.0.0.1"; port = 80; ssl = false; } ssl = true;
{ addr = "[::1]"; port = 80; ssl = false; } }
]; {
addr = "[::0]";
port = 443;
ssl = true;
}
{
addr = "[::0]";
port = 80;
ssl = false;
}
# Private networking
{
addr = "127.0.0.1";
port = 80;
ssl = false;
}
{
addr = "[::1]";
port = 80;
ssl = false;
}
];
appendHttpConfig = '' appendHttpConfig = ''
# Kurisu node # Kurisu node
set_real_ip_from ${allowedUpstream}; set_real_ip_from ${allowedUpstream};
real_ip_header proxy_protocol; real_ip_header proxy_protocol;
'';
};
# Move to nftables if firewall is enabled.
networking.nftables.enable = true;
networking.firewall.extraInputRules = ''
ip6 saddr ${allowedUpstream} tcp dport 444 accept
''; '';
}; };
}
# Move to nftables if firewall is enabled.
networking.nftables.enable = true;
networking.firewall.extraInputRules = ''
ip6 saddr ${allowedUpstream} tcp dport 444 accept
'';
};
}

View file

@ -1,7 +1,12 @@
{ lib, config, ... }: { lib, config, ... }:
let let
cfg = config.bagel.hardware.raito-vm; cfg = config.bagel.hardware.raito-vm;
inherit (lib) mkEnableOption mkIf mkOption types; inherit (lib)
mkEnableOption
mkIf
mkOption
types
;
in in
{ {
options.bagel.hardware.raito-vm = { options.bagel.hardware.raito-vm = {

View file

@ -23,7 +23,9 @@
users = { users = {
delroth = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII3tjB4KYDok3KlWxdBp/yEmqhhmybd+w0VO4xUwLKKV" ]; delroth = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII3tjB4KYDok3KlWxdBp/yEmqhhmybd+w0VO4xUwLKKV" ];
emilylange = [ "no-touch-required sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIL7jgq3i+N3gVJhs4shm7Kmw6dIocs2OuR0GBMG1RxfKAAAABHNzaDo=" ]; emilylange = [
"no-touch-required sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIL7jgq3i+N3gVJhs4shm7Kmw6dIocs2OuR0GBMG1RxfKAAAABHNzaDo="
];
hexchen = [ hexchen = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINJ0tCxsEilAzV6LaNpUpcjzyEn4ptw8kFz3R+Z3YjEF hexchen@backup" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINJ0tCxsEilAzV6LaNpUpcjzyEn4ptw8kFz3R+Z3YjEF hexchen@backup"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDI3T1eFS77URHZ/HVWkMOqx7W1U54zJtn9C7QWsHOtyH72i/4EVj8SxYqLllElh1kuKUXSUipPeEzVsipFVvfH0wEuTDgFffiSQ3a8lfUgdEBuoySwceEoPgc5deapkOmiDIDeeWlrRe3nqspLRrSWU1DirMxoFPbwqJXRvpl6qJPxRg+2IolDcXlZ6yxB4Vv48vzRfVzZNUz7Pjmy2ebU8PbDoFWL/S3m7yOzQpv3L7KYBz7+rkjuF3AU2vy6CAfIySkVpspZZLtkTGCIJF228ev0e8NvhuN6ZnjzXxVTQOy32HCdPdbBbicu0uHfZ5O7JX9DjGd8kk1r2dnZwwy/ hexchen@yubi5" "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDI3T1eFS77URHZ/HVWkMOqx7W1U54zJtn9C7QWsHOtyH72i/4EVj8SxYqLllElh1kuKUXSUipPeEzVsipFVvfH0wEuTDgFffiSQ3a8lfUgdEBuoySwceEoPgc5deapkOmiDIDeeWlrRe3nqspLRrSWU1DirMxoFPbwqJXRvpl6qJPxRg+2IolDcXlZ6yxB4Vv48vzRfVzZNUz7Pjmy2ebU8PbDoFWL/S3m7yOzQpv3L7KYBz7+rkjuF3AU2vy6CAfIySkVpspZZLtkTGCIJF228ev0e8NvhuN6ZnjzXxVTQOy32HCdPdbBbicu0uHfZ5O7JX9DjGd8kk1r2dnZwwy/ hexchen@yubi5"
@ -40,7 +42,9 @@
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBLZxVITpJ8xbiCa/u2gjSSIupeiqOnRh+8tFIoVhCON" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBLZxVITpJ8xbiCa/u2gjSSIupeiqOnRh+8tFIoVhCON"
]; ];
k900 = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOi9vgVGs+S5kEsUqHPvyMMh1Q9gqL4TcbHoe5d73tun" ]; k900 = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOi9vgVGs+S5kEsUqHPvyMMh1Q9gqL4TcbHoe5d73tun" ];
lukegb = [ ''cert-authority,principals="lukegb" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEqNOwlR7Qa8cbGpDfSCOweDPbAGQOZIcoRgh6s/J8DR'' ]; lukegb = [
''cert-authority,principals="lukegb" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEqNOwlR7Qa8cbGpDfSCOweDPbAGQOZIcoRgh6s/J8DR''
];
maxine = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILpWQfhNFdrxMTP/1DwBVuk49f3df9iH7Tbdu8ltIKjr" ]; maxine = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILpWQfhNFdrxMTP/1DwBVuk49f3df9iH7Tbdu8ltIKjr" ];
raito = [ raito = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICaw9ihTG7ucB8P38XdalEWev8+q96e2yNm4B+/I9IJp" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICaw9ihTG7ucB8P38XdalEWev8+q96e2yNm4B+/I9IJp"
@ -49,6 +53,8 @@
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKiXXYkhRh+s7ixZ8rvG8ntIqd6FELQ9hh7HoaHQJRPU" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKiXXYkhRh+s7ixZ8rvG8ntIqd6FELQ9hh7HoaHQJRPU"
]; ];
thubrecht = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPM1jpXR7BWQa7Sed7ii3SbvIPRRlKb3G91qC0vOwfJn" ]; thubrecht = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPM1jpXR7BWQa7Sed7ii3SbvIPRRlKb3G91qC0vOwfJn" ];
yuka = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKath4/fDnlv/4fzxkPrQN1ttmoPRNu/m9bEtdPJBDfY cardno:16_933_242" ]; yuka = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKath4/fDnlv/4fzxkPrQN1ttmoPRNu/m9bEtdPJBDfY cardno:16_933_242"
];
}; };
} }

View file

@ -1,29 +1,34 @@
{ pkgs, config, lib, ... }: {
pkgs,
config,
lib,
...
}:
let let
inherit (lib) mkIf mkEnableOption; inherit (lib) mkIf mkEnableOption;
cfg = config.bagel.sysadmin; cfg = config.bagel.sysadmin;
in in
{ {
options.bagel.sysadmin.enable = mkEnableOption "sysadmin tooling"; options.bagel.sysadmin.enable = mkEnableOption "sysadmin tooling";
config = mkIf cfg.enable { config = mkIf cfg.enable {
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
wget wget
vim vim
tmux tmux
rsync rsync
fd fd
ripgrep ripgrep
pv pv
kitty.terminfo kitty.terminfo
config.boot.kernelPackages.perf config.boot.kernelPackages.perf
bcc bcc
tcpdump tcpdump
ncdu ncdu
# Useful to invoke `coredumpctl gdb` # Useful to invoke `coredumpctl gdb`
gdb gdb
htop htop
btop btop
]; ];
}; };
} }

View file

@ -1,4 +1,10 @@
{ lib, pkgs, config, ... }: { {
lib,
pkgs,
config,
...
}:
{
users.defaultUserShell = pkgs.zsh; users.defaultUserShell = pkgs.zsh;
programs.zsh = { programs.zsh = {
enable = true; enable = true;

View file

@ -278,6 +278,22 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat_5": {
"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-parts": { "flake-parts": {
"inputs": { "inputs": {
"nixpkgs-lib": [ "nixpkgs-lib": [
@ -385,6 +401,27 @@
"type": "github" "type": "github"
} }
}, },
"gitignore": {
"inputs": {
"nixpkgs": [
"pre-commit-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"
}
},
"grapevine": { "grapevine": {
"inputs": { "inputs": {
"attic": "attic", "attic": "attic",
@ -631,6 +668,22 @@
"type": "github" "type": "github"
} }
}, },
"nixpkgs-stable_2": {
"locked": {
"lastModified": 1720386169,
"narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "194846768975b7ad2c4988bdb82572c00222c0d7",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-24.05",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1723151389, "lastModified": 1723151389,
@ -678,6 +731,29 @@
"type": "github" "type": "github"
} }
}, },
"pre-commit-hooks_2": {
"inputs": {
"flake-compat": "flake-compat_5",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": "nixpkgs-stable_2"
},
"locked": {
"lastModified": 1723202784,
"narHash": "sha256-qbhjc/NEGaDbyy0ucycubq4N3//gDFFH3DOmp1D3u1Q=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "c7012d0c18567c889b948781bc74a501e92275d1",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"root": { "root": {
"inputs": { "inputs": {
"agenix": "agenix", "agenix": "agenix",
@ -691,6 +767,7 @@
], ],
"nix-gerrit": "nix-gerrit", "nix-gerrit": "nix-gerrit",
"nixpkgs": "nixpkgs_2", "nixpkgs": "nixpkgs_2",
"pre-commit-hooks": "pre-commit-hooks_2",
"terranix": "terranix" "terranix": "terranix"
} }
}, },

236
flake.nix
View file

@ -29,100 +29,158 @@
repo = "grapevine-fork"; repo = "grapevine-fork";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
pre-commit-hooks.url = "github:cachix/pre-commit-hooks.nix";
pre-commit-hooks.inputs.nixpkgs.follows = "nixpkgs";
}; };
outputs = { self, nixpkgs, terranix, colmena, ... } @ inputs: outputs =
let {
supportedSystems = [ "x86_64-linux" "aarch64-linux" ]; self,
forEachSystem = f: builtins.listToAttrs (map (system: { nixpkgs,
name = system; terranix,
value = f system; colmena,
}) supportedSystems); pre-commit-hooks,
systemBits = forEachSystem (system: rec { ...
inherit system; }@inputs:
pkgs = import nixpkgs { let
localSystem = system; supportedSystems = [
overlays = [ "x86_64-linux"
inputs.hydra.overlays.default "aarch64-linux"
inputs.lix.overlays.default
inputs.nix-gerrit.overlays.default
];
};
terraform = pkgs.opentofu;
terraformCfg = terranix.lib.terranixConfiguration {
inherit system;
modules = [
./terraform
{
bagel.gandi.enable = true;
bagel.hydra.enable = true;
}
];
};
});
forEachSystem' = f: forEachSystem (system: (f systemBits.${system}));
inherit (nixpkgs) lib;
in
{
apps = forEachSystem' ({ system, pkgs, terraformCfg, terraform, ... }: {
tf = {
type = "app";
program = toString (pkgs.writers.writeBash "tf" ''
set -eo pipefail
ln -snf ${terraformCfg} config.tf.json
exec ${lib.getExe terraform} "$@"
'');
};
default = self.apps.${system}.tf;
});
devShells = forEachSystem' ({ system, pkgs, ... }: {
default = pkgs.mkShell {
packages = [
inputs.agenix.packages.${system}.agenix
pkgs.opentofu
(pkgs.callPackage ./lib/colmena-wrapper.nix { })
];
};
});
nixosConfigurations = (colmena.lib.makeHive self.outputs.colmena).nodes;
colmena = let
commonModules = [
inputs.agenix.nixosModules.default
inputs.hydra.nixosModules.hydra
inputs.buildbot-nix.nixosModules.buildbot-coordinator
inputs.buildbot-nix.nixosModules.buildbot-worker
./services
./common
]; ];
forEachSystem =
f:
builtins.listToAttrs (
map (system: {
name = system;
value = f system;
}) supportedSystems
);
systemBits = forEachSystem (system: rec {
inherit system;
pkgs = import nixpkgs {
localSystem = system;
overlays = [
inputs.hydra.overlays.default
inputs.lix.overlays.default
inputs.nix-gerrit.overlays.default
];
};
terraform = pkgs.opentofu;
terraformCfg = terranix.lib.terranixConfiguration {
inherit system;
modules = [
./terraform
{
bagel.gandi.enable = true;
bagel.hydra.enable = true;
}
];
};
});
forEachSystem' = f: forEachSystem (system: (f systemBits.${system}));
inherit (nixpkgs) lib;
in
{
apps = forEachSystem' (
{
system,
pkgs,
terraformCfg,
terraform,
...
}:
{
tf = {
type = "app";
program = toString (
pkgs.writers.writeBash "tf" ''
set -eo pipefail
ln -snf ${terraformCfg} config.tf.json
exec ${lib.getExe terraform} "$@"
''
);
};
makeBuilder = i: lib.nameValuePair "builder-${toString i}" { default = self.apps.${system}.tf;
imports = commonModules; }
bagel.baremetal.builders = { enable = true; num = i; netboot = i >= 6; }; );
};
builders = lib.listToAttrs (lib.genList makeBuilder 12); devShells = forEachSystem' (
in { { system, pkgs, ... }:
meta.nixpkgs = systemBits.x86_64-linux.pkgs; {
meta.specialArgs.inputs = inputs; default = pkgs.mkShell {
packages = [
inputs.agenix.packages.${system}.agenix
bagel-box.imports = commonModules ++ [ ./hosts/bagel-box ]; pkgs.opentofu
meta01.imports = commonModules ++ [ ./hosts/meta01 ];
gerrit01.imports = commonModules ++ [ ./hosts/gerrit01 ];
fodwatch.imports = commonModules ++ [ ./hosts/fodwatch ];
git.imports = commonModules ++ [ ./hosts/git ];
wob-vpn-gw.imports = commonModules ++ [ ./hosts/wob-vpn-gw ];
buildbot.imports = commonModules ++ [ ./hosts/buildbot ];
public01.imports = commonModules ++ [ ./hosts/public01 ];
} // builders;
hydraJobs = builtins.mapAttrs (n: v: v.config.system.build.netbootDir or v.config.system.build.toplevel) self.nixosConfigurations; (pkgs.callPackage ./lib/colmena-wrapper.nix { })
buildbotJobs = builtins.mapAttrs (_: v: v.config.system.build.toplevel) self.nixosConfigurations; ];
};
inherit (inputs.self.checks.${system}.pre-commit) shellHook;
};
}
);
checks = forEachSystem' (
{ system, pkgs, ... }:
{
pre-commit = pre-commit-hooks.lib.${system}.run {
src = ./.;
hooks.nixfmt = {
enable = true;
package = pkgs.nixfmt-rfc-style;
};
};
}
);
nixosConfigurations = (colmena.lib.makeHive self.outputs.colmena).nodes;
colmena =
let
commonModules = [
inputs.agenix.nixosModules.default
inputs.hydra.nixosModules.hydra
inputs.buildbot-nix.nixosModules.buildbot-coordinator
inputs.buildbot-nix.nixosModules.buildbot-worker
./services
./common
];
makeBuilder =
i:
lib.nameValuePair "builder-${toString i}" {
imports = commonModules;
bagel.baremetal.builders = {
enable = true;
num = i;
netboot = i >= 6;
};
};
builders = lib.listToAttrs (lib.genList makeBuilder 12);
in
{
meta.nixpkgs = systemBits.x86_64-linux.pkgs;
meta.specialArgs.inputs = inputs;
bagel-box.imports = commonModules ++ [ ./hosts/bagel-box ];
meta01.imports = commonModules ++ [ ./hosts/meta01 ];
gerrit01.imports = commonModules ++ [ ./hosts/gerrit01 ];
fodwatch.imports = commonModules ++ [ ./hosts/fodwatch ];
git.imports = commonModules ++ [ ./hosts/git ];
wob-vpn-gw.imports = commonModules ++ [ ./hosts/wob-vpn-gw ];
buildbot.imports = commonModules ++ [ ./hosts/buildbot ];
public01.imports = commonModules ++ [ ./hosts/public01 ];
}
// builders;
hydraJobs = builtins.mapAttrs (
n: v: v.config.system.build.netbootDir or v.config.system.build.toplevel
) self.nixosConfigurations;
buildbotJobs = builtins.mapAttrs (_: v: v.config.system.build.toplevel) self.nixosConfigurations;
};
} }

View file

@ -9,7 +9,11 @@
boot.specialFileSystems = lib.mkForce { boot.specialFileSystems = lib.mkForce {
"/run/wrappers" = { "/run/wrappers" = {
fsType = "tmpfs"; fsType = "tmpfs";
options = [ "nodev" "mode=755" "size=${config.security.wrapperDirSize}" ]; options = [
"nodev"
"mode=755"
"size=${config.security.wrapperDirSize}"
];
}; };
}; };
@ -24,13 +28,22 @@
nameservers = [ "2001:4860:4860::8844" ]; nameservers = [ "2001:4860:4860::8844" ];
interfaces.host0.ipv6.addresses = [ interfaces.host0.ipv6.addresses = [
{ address = "2001:bc8:38ee:100:100::1"; prefixLength = 64; } {
address = "2001:bc8:38ee:100:100::1";
prefixLength = 64;
}
]; ];
interfaces.host1.ipv4.addresses = [ interfaces.host1.ipv4.addresses = [
{ address = "172.16.100.2"; prefixLength = 24; } {
address = "172.16.100.2";
prefixLength = 24;
}
]; ];
defaultGateway = { address = "172.16.100.1"; interface = "host1"; }; defaultGateway = {
address = "172.16.100.1";
interface = "host1";
};
firewall.allowPing = true; firewall.allowPing = true;
}; };

View file

@ -32,9 +32,7 @@
bagel.services.gerrit = { bagel.services.gerrit = {
enable = true; enable = true;
domains = [ domains = [ "cl.forkos.org" ];
"cl.forkos.org"
];
canonicalDomain = "cl.forkos.org"; canonicalDomain = "cl.forkos.org";
data = "/gerrit-data"; data = "/gerrit-data";
}; };
@ -46,81 +44,93 @@
group = "git"; group = "git";
}; };
bagel.nixpkgs.one-way-sync = bagel.nixpkgs.one-way-sync =
let let
mkNixpkgsJob = { timer, fromRefspec, localRefspec ? fromRefspec }: { mkNixpkgsJob =
fromUri = "https://github.com/NixOS/nixpkgs"; {
inherit fromRefspec localRefspec timer; timer,
}; fromRefspec,
mkLocalJob = { timer, fromRefspec, localRefspec }: { localRefspec ? fromRefspec,
fromUri = "https://cl.forkos.org/nixpkgs"; }:
inherit fromRefspec localRefspec timer; {
}; fromUri = "https://github.com/NixOS/nixpkgs";
inherit fromRefspec localRefspec timer;
};
mkLocalJob =
{
timer,
fromRefspec,
localRefspec,
}:
{
fromUri = "https://cl.forkos.org/nixpkgs";
inherit fromRefspec localRefspec timer;
};
in in
{ {
enable = true; enable = true;
pushUrl = "ssh://ows_bot@cl.forkos.org:29418/nixpkgs"; pushUrl = "ssh://ows_bot@cl.forkos.org:29418/nixpkgs";
deployKeyPath = config.age.secrets.ows-deploy-key.path; deployKeyPath = config.age.secrets.ows-deploy-key.path;
# Sync main -> staging-next -> staging # Sync main -> staging-next -> staging
branches."main-to-staging-next" = mkLocalJob { branches."main-to-staging-next" = mkLocalJob {
timer = "00/8:20:00"; # every 8 hours, 20 minutes past the full hour timer = "00/8:20:00"; # every 8 hours, 20 minutes past the full hour
fromRefspec = "main"; fromRefspec = "main";
localRefspec = "staging-next"; localRefspec = "staging-next";
}; };
branches."staging-next-to-staging" = mkLocalJob { branches."staging-next-to-staging" = mkLocalJob {
timer = "00/8:40:00"; # every 8 hours, 40 minutes past the full hour timer = "00/8:40:00"; # every 8 hours, 40 minutes past the full hour
fromRefspec = "staging-next"; fromRefspec = "staging-next";
localRefspec = "staging"; localRefspec = "staging";
}; };
# Sync nixpkgs -> fork # Sync nixpkgs -> fork
branches."nixpkgs-master" = mkNixpkgsJob { branches."nixpkgs-master" = mkNixpkgsJob {
timer = "hourly"; timer = "hourly";
fromRefspec = "master"; fromRefspec = "master";
localRefspec = "main"; localRefspec = "main";
}; };
branches."nixpkgs-staging" = mkNixpkgsJob { branches."nixpkgs-staging" = mkNixpkgsJob {
timer = "hourly"; timer = "hourly";
fromRefspec = "staging"; fromRefspec = "staging";
}; };
branches."nixpkgs-release-24.05" = mkNixpkgsJob { branches."nixpkgs-release-24.05" = mkNixpkgsJob {
timer = "hourly"; timer = "hourly";
fromRefspec = "release-24.05"; fromRefspec = "release-24.05";
}; };
branches."nixpkgs-staging-24.05" = mkNixpkgsJob { branches."nixpkgs-staging-24.05" = mkNixpkgsJob {
timer = "hourly"; timer = "hourly";
fromRefspec = "staging-24.05"; fromRefspec = "staging-24.05";
}; };
branches."nixpkgs-release-23.11" = mkNixpkgsJob { branches."nixpkgs-release-23.11" = mkNixpkgsJob {
timer = "hourly"; timer = "hourly";
fromRefspec = "release-23.11"; fromRefspec = "release-23.11";
}; };
branches."nixpkgs-staging-23.11" = mkNixpkgsJob { branches."nixpkgs-staging-23.11" = mkNixpkgsJob {
timer = "hourly"; timer = "hourly";
fromRefspec = "staging-23.11"; fromRefspec = "staging-23.11";
}; };
# Testing jobs for personal sandbox branches # Testing jobs for personal sandbox branches
branches."raito-unstable-sync" = { branches."raito-unstable-sync" = {
fromUri = "https://github.com/NixOS/nixpkgs"; fromUri = "https://github.com/NixOS/nixpkgs";
fromRefspec = "nixos-unstable-small"; fromRefspec = "nixos-unstable-small";
localRefspec = "sandbox/raito/raito-unstable-small"; localRefspec = "sandbox/raito/raito-unstable-small";
timer = "*-*-* 12:00:00"; timer = "*-*-* 12:00:00";
}; };
branches."raito-release-sync" = { branches."raito-release-sync" = {
fromUri = "https://github.com/NixOS/nixpkgs"; fromUri = "https://github.com/NixOS/nixpkgs";
fromRefspec = "nixos-24.05"; fromRefspec = "nixos-24.05";
localRefspec = "sandbox/raito/raito-nixos-24.05"; localRefspec = "sandbox/raito/raito-nixos-24.05";
timer = "daily"; timer = "daily";
};
}; };
};
i18n.defaultLocale = "fr_FR.UTF-8"; i18n.defaultLocale = "fr_FR.UTF-8";

View file

@ -1,6 +1,6 @@
let let
ipv6 = { ipv6 = {
openssh ="2001:bc8:38ee:100:1000::41"; openssh = "2001:bc8:38ee:100:1000::41";
forgejo = "2001:bc8:38ee:100:1000::40"; forgejo = "2001:bc8:38ee:100:1000::40";
}; };
in in
@ -27,9 +27,7 @@ in
# Add one additional IPv6, so we can have both OpenSSH and # Add one additional IPv6, so we can have both OpenSSH and
# Forgejo's built-in server bind on port :22. # Forgejo's built-in server bind on port :22.
systemd.network.networks."10-wan".networkConfig.Address = [ "${ipv6.openssh}/64" ]; systemd.network.networks."10-wan".networkConfig.Address = [ "${ipv6.openssh}/64" ];
services.openssh.listenAddresses = [{ services.openssh.listenAddresses = [ { addr = "[${ipv6.openssh}]"; } ];
addr = "[${ipv6.openssh}]";
}];
# Defaults to network.target, but networkd may take a while to settle and set up # Defaults to network.target, but networkd may take a while to settle and set up
# the required (additional) IPv6 address, leading to sshd to not being able to # the required (additional) IPv6 address, leading to sshd to not being able to
# bind to the requested IP, crashing 5 times and running into the default # bind to the requested IP, crashing 5 times and running into the default

View file

@ -27,9 +27,7 @@
bagel.services.grapevine.enable = true; bagel.services.grapevine.enable = true;
bagel.services.hookshot = { bagel.services.hookshot = {
enable = true; enable = true;
admins = [ admins = [ "@k900:0upti.me" ];
"@k900:0upti.me"
];
}; };
i18n.defaultLocale = "fr_FR.UTF-8"; i18n.defaultLocale = "fr_FR.UTF-8";

View file

@ -1,25 +1,29 @@
{ pkgs, lib, ... }: { pkgs, lib, ... }:
{ {
imports = [ imports = [ ./netboot.nix ];
./netboot.nix
];
###### Hardware ###### ###### Hardware ######
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "ehci_pci" "sd_mod" "sdhci_pci" ]; boot.initrd.availableKernelModules = [
"xhci_pci"
"ahci"
"ehci_pci"
"sd_mod"
"sdhci_pci"
];
boot.kernelModules = [ "kvm-amd" ]; boot.kernelModules = [ "kvm-amd" ];
boot.loader.grub.device = "/dev/sda"; boot.loader.grub.device = "/dev/sda";
fileSystems."/" = fileSystems."/" = {
{ device = "/dev/disk/by-uuid/58688a5c-e3ce-4868-804b-4e34d1370f36"; device = "/dev/disk/by-uuid/58688a5c-e3ce-4868-804b-4e34d1370f36";
fsType = "f2fs"; fsType = "f2fs";
}; };
fileSystems."/boot" = fileSystems."/boot" = {
{ device = "/dev/disk/by-uuid/38caa628-3b6d-4fb4-8767-beee09a196a6"; device = "/dev/disk/by-uuid/38caa628-3b6d-4fb4-8767-beee09a196a6";
fsType = "ext2"; fsType = "ext2";
}; };
nixpkgs.hostPlatform = "x86_64-linux"; nixpkgs.hostPlatform = "x86_64-linux";
@ -65,29 +69,36 @@
}; };
}; };
}; };
networks = { networks =
"40-enp1s0" = { {
name = "enp1s0"; "40-enp1s0" = {
bond = [ "uplink" ]; name = "enp1s0";
}; bond = [ "uplink" ];
"40-enp2s0" = { };
name = "enp2s0"; "40-enp2s0" = {
bond = [ "uplink" ]; name = "enp2s0";
}; bond = [ "uplink" ];
"40-enp3s0" = { };
name = "enp3s0"; "40-enp3s0" = {
bond = [ "oob" ]; name = "enp3s0";
}; bond = [ "oob" ];
"40-enp4s0" = { };
name = "enp4s0"; "40-enp4s0" = {
bond = [ "oob" ]; name = "enp4s0";
}; bond = [ "oob" ];
} // lib.listToAttrs (map (x: lib.nameValuePair "40-bmc${toString x}" { };
name = "bmc${toString x}"; }
address = [ "192.168.1.${toString (x*4 + 1)}/30" ]; // lib.listToAttrs (
#address = [ "192.168.${toString x}.1/24" ]; map (
networkConfig.DHCPServer = true; x:
}) (lib.genList lib.id 12)); lib.nameValuePair "40-bmc${toString x}" {
name = "bmc${toString x}";
address = [ "192.168.1.${toString (x * 4 + 1)}/30" ];
#address = [ "192.168.${toString x}.1/24" ];
networkConfig.DHCPServer = true;
}
) (lib.genList lib.id 12)
);
}; };
networking.nftables.enable = true; networking.nftables.enable = true;
@ -95,10 +106,15 @@
iifname { "bmc*" } meta nfproto ipv4 udp dport 67 accept comment "DHCP server" iifname { "bmc*" } meta nfproto ipv4 udp dport 67 accept comment "DHCP server"
''; '';
networking.vlans = lib.listToAttrs (map (x: lib.nameValuePair "bmc${toString x}" { networking.vlans = lib.listToAttrs (
interface = "oob"; map (
id = 101 + x; x:
}) (lib.genList lib.id 12)); lib.nameValuePair "bmc${toString x}" {
interface = "oob";
id = 101 + x;
}
) (lib.genList lib.id 12)
);
networking.interfaces = { networking.interfaces = {
uplink = { uplink = {
@ -111,7 +127,10 @@
}; };
}; };
networking.defaultGateway6 = { interface = "uplink"; address = "2a01:584:11::1"; }; networking.defaultGateway6 = {
interface = "uplink";
address = "2a01:584:11::1";
};
networking.hostName = "vpn-gw"; networking.hostName = "vpn-gw";
networking.domain = "wob01.infra.forkos.org"; networking.domain = "wob01.infra.forkos.org";

View file

@ -1,4 +1,11 @@
{ config, lib, pkgs, nodes, modulesPath, ... }: {
config,
lib,
pkgs,
nodes,
modulesPath,
...
}:
# The way the connection is established is specific to the wob01 site and the Intel S2600KPR blades. # The way the connection is established is specific to the wob01 site and the Intel S2600KPR blades.
# Proper netboot is not possible, because while the blades and the APU board (which is the netboot # Proper netboot is not possible, because while the blades and the APU board (which is the netboot
@ -10,8 +17,11 @@
let let
netboot-server-ip = "2a01:584:11::2"; netboot-server-ip = "2a01:584:11::2";
netbootNodes = lib.filterAttrs (_: node: node.config.bagel.baremetal.builders.enable && node.config.bagel.baremetal.builders.netboot) nodes; netbootNodes = lib.filterAttrs (
in { _: node: node.config.bagel.baremetal.builders.enable && node.config.bagel.baremetal.builders.netboot
) nodes;
in
{
assertions = [ assertions = [
{ {
@ -23,19 +33,23 @@ in {
} }
]; ];
systemd.services = lib.mapAttrs' (nodename: node: let systemd.services = lib.mapAttrs' (
bmcIp = "192.168.1.${toString (node.config.bagel.baremetal.builders.num * 4 + 2)}"; nodename: node:
notipxe = node.config.system.build.notipxe.config.system.build.usbImage; let
in lib.nameValuePair "iusb-spoof-${nodename}" { bmcIp = "192.168.1.${toString (node.config.bagel.baremetal.builders.num * 4 + 2)}";
wantedBy = [ "multi-user.target" ]; notipxe = node.config.system.build.notipxe.config.system.build.usbImage;
serviceConfig = { in
Restart = "always"; lib.nameValuePair "iusb-spoof-${nodename}" {
}; wantedBy = [ "multi-user.target" ];
script = '' serviceConfig = {
AUTH_TOKEN=$(${pkgs.iusb-spoof}/bin/make-token ${bmcIp}) Restart = "always";
exec ${pkgs.iusb-spoof}/bin/iusb-spoof -r ${bmcIp} 5123 $AUTH_TOKEN ${notipxe} };
''; script = ''
}) netbootNodes; AUTH_TOKEN=$(${pkgs.iusb-spoof}/bin/make-token ${bmcIp})
exec ${pkgs.iusb-spoof}/bin/iusb-spoof -r ${bmcIp} 5123 $AUTH_TOKEN ${notipxe}
'';
}
) netbootNodes;
# Since the builders are stateless, they can not store their ssh hostkeys # Since the builders are stateless, they can not store their ssh hostkeys
networking.firewall.allowedTCPPorts = [ 80 ]; # for ACME networking.firewall.allowedTCPPorts = [ 80 ]; # for ACME
@ -49,15 +63,19 @@ in {
virtualHosts."vpn-gw.wob01.infra.forkos.org" = { virtualHosts."vpn-gw.wob01.infra.forkos.org" = {
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
locations = lib.mapAttrs' (nodename: node: let locations = lib.mapAttrs' (
ip = "2a01:584:11::1:${toString node.config.bagel.baremetal.builders.num}"; nodename: node:
in lib.nameValuePair "/${nodename}/" { let
root = "/var/www"; ip = "2a01:584:11::1:${toString node.config.bagel.baremetal.builders.num}";
extraConfig = '' in
allow ${ip}; lib.nameValuePair "/${nodename}/" {
deny all; root = "/var/www";
''; extraConfig = ''
}) netbootNodes; allow ${ip};
deny all;
'';
}
) netbootNodes;
}; };
}; };
} }

View file

@ -1,10 +1,7 @@
# A wrapper for colmena that prevents accidentally deploying changes without # A wrapper for colmena that prevents accidentally deploying changes without
# having pulled. # having pulled.
{ colmena, runCommandNoCC }: { colmena, runCommandNoCC }:
runCommandNoCC "colmena-wrapper" runCommandNoCC "colmena-wrapper" { env.colmena = "${colmena}/bin/colmena"; } ''
{
env.colmena = "${colmena}/bin/colmena";
} ''
mkdir -p $out mkdir -p $out
ln -s ${colmena}/share $out/share ln -s ${colmena}/share $out/share
mkdir $out/bin mkdir $out/bin

View file

@ -1,6 +1,6 @@
[ [
(final: prev: { (final: prev: {
iusb-spoof = final.callPackage ./iusb-spoof.nix {}; iusb-spoof = final.callPackage ./iusb-spoof.nix { };
u-root = final.callPackage ./u-root {}; u-root = final.callPackage ./u-root { };
}) })
] ]

View file

@ -1,4 +1,8 @@
{ rustPlatform, python3, makeWrapper }: {
rustPlatform,
python3,
makeWrapper,
}:
let let
pythonEnv = python3.withPackages (p: with p; [ requests ]); pythonEnv = python3.withPackages (p: with p; [ requests ]);
in in

View file

@ -11,9 +11,7 @@ buildGoModule rec {
hash = "sha256-8zA3pHf45MdUcq/MA/mf0KCTxB1viHieU/oigYwIPgo="; hash = "sha256-8zA3pHf45MdUcq/MA/mf0KCTxB1viHieU/oigYwIPgo=";
}; };
patches = [ patches = [ ./u-root-allow-https.patch ];
./u-root-allow-https.patch
];
vendorHash = null; vendorHash = null;
doCheck = false; doCheck = false;

View file

@ -12,7 +12,10 @@ let
mimir-webhook-url = [ machines.meta01 ]; mimir-webhook-url = [ machines.meta01 ];
grafana-oauth-secret = [ machines.meta01 ]; grafana-oauth-secret = [ machines.meta01 ];
loki-environment = [ machines.meta01 ]; loki-environment = [ machines.meta01 ];
gerrit-prometheus-bearer-token = [ machines.gerrit01 machines.meta01 ]; gerrit-prometheus-bearer-token = [
machines.gerrit01
machines.meta01
];
buildbot-worker-password = [ machines.buildbot ]; buildbot-worker-password = [ machines.buildbot ];
buildbot-oauth-secret = [ machines.buildbot ]; buildbot-oauth-secret = [ machines.buildbot ];
@ -31,9 +34,9 @@ let
ows-deploy-key = [ machines.gerrit01 ]; ows-deploy-key = [ machines.gerrit01 ];
}; };
in in
builtins.listToAttrs ( builtins.listToAttrs (
map (secretName: { map (secretName: {
name = "secrets/${secretName}.age"; name = "secrets/${secretName}.age";
value.publicKeys = secrets."${secretName}" ++ commonKeys; value.publicKeys = secrets."${secretName}" ++ commonKeys;
}) (builtins.attrNames secrets) }) (builtins.attrNames secrets)
) )

View file

@ -1,29 +1,61 @@
# This file contains information on which builder(s) are providing how many # This file contains information on which builder(s) are providing how many
# job slots and providing which nix features # job slots and providing which nix features
let let
genBuilders = { offset ? 0, count, f }: builtins.genList (x: rec { name = "builder-${toString (offset + x)}"; value = f name; }) count; genBuilders =
in builtins.listToAttrs ( {
offset ? 0,
count,
f,
}:
builtins.genList (x: rec {
name = "builder-${toString (offset + x)}";
value = f name;
}) count;
in
builtins.listToAttrs (
# The first 8 builders are general purpose hydra builders # The first 8 builders are general purpose hydra builders
genBuilders { count = 8; f = name: { genBuilders {
cores = 8; count = 8;
max-jobs = 8; f = name: {
supported-features = [ "kvm" "nixos-test" ]; cores = 8;
required-features = [ ]; max-jobs = 8;
}; } supported-features = [
"kvm"
"nixos-test"
];
required-features = [ ];
};
}
++ ++
# The last 2 builders are exclusively for big-parallel # The last 2 builders are exclusively for big-parallel
genBuilders { offset = 8; count = 2; f = name: { genBuilders {
cores = 20; offset = 8;
max-jobs = 1; count = 2;
supported-features = [ "kvm" "nixos-test" "big-parallel" ]; f = name: {
required-features = [ "big-parallel" ]; cores = 20;
}; } max-jobs = 1;
supported-features = [
"kvm"
"nixos-test"
"big-parallel"
];
required-features = [ "big-parallel" ];
};
}
++ ++
# These are not currently used for hydra # These are not currently used for hydra
genBuilders { offset = 10; count = 2; f = name: { genBuilders {
cores = 8; offset = 10;
max-jobs = 8; count = 2;
supported-features = [ "kvm" "nixos-test" "big-parallel" ]; f = name: {
required-features = [ ]; cores = 8;
}; } max-jobs = 8;
supported-features = [
"kvm"
"nixos-test"
"big-parallel"
];
required-features = [ ];
};
}
) )

View file

@ -1,4 +1,9 @@
{ pkgs, lib, config, ... }: {
pkgs,
lib,
config,
...
}:
let let
cfg = config.bagel.baremetal.builders; cfg = config.bagel.baremetal.builders;
in in
@ -10,14 +15,18 @@ in
bagel.baremetal.builders = { bagel.baremetal.builders = {
enable = lib.mkEnableOption "baremetal bagel oven"; enable = lib.mkEnableOption "baremetal bagel oven";
netboot = lib.mkEnableOption "netboot"; netboot = lib.mkEnableOption "netboot";
num = lib.mkOption { num = lib.mkOption { type = lib.types.int; };
type = lib.types.int;
};
}; };
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
boot.initrd.availableKernelModules = [ "ahci" "ehci_pci" "usb_storage" "usbhid" "sd_mod" ]; boot.initrd.availableKernelModules = [
"ahci"
"ehci_pci"
"usb_storage"
"usbhid"
"sd_mod"
];
boot.initrd.kernelModules = [ "dm-snapshot" ]; boot.initrd.kernelModules = [ "dm-snapshot" ];
users.users.builder = { users.users.builder = {
@ -44,7 +53,10 @@ in
]; ];
}; };
nix.settings = { nix.settings = {
trusted-users = [ "builder" "buildbot" ]; trusted-users = [
"builder"
"buildbot"
];
inherit ((import ./assignments.nix).${config.networking.hostName}) max-jobs cores; inherit ((import ./assignments.nix).${config.networking.hostName}) max-jobs cores;
}; };
@ -68,14 +80,17 @@ in
"/boot" = { "/boot" = {
device = "/dev/disk/by-label/BOOT"; device = "/dev/disk/by-label/BOOT";
fsType = "vfat"; fsType = "vfat";
options = [ "fmask=0022" "dmask=0022" ]; options = [
"fmask=0022"
"dmask=0022"
];
}; };
}) })
{ {
"/mnt" = { "/mnt" = {
device = "/dev/disk/by-label/hydra"; device = "/dev/disk/by-label/hydra";
fsType = "xfs"; fsType = "xfs";
options = ["logbsize=256k"]; options = [ "logbsize=256k" ];
}; };
# We want the tmp filesystem on the same filesystem as the hydra store, so that builds can use reflinks # We want the tmp filesystem on the same filesystem as the hydra store, so that builds can use reflinks
@ -89,7 +104,7 @@ in
swapDevices = lib.optionals (!cfg.netboot) [ swapDevices = lib.optionals (!cfg.netboot) [
{ {
device = "/swapfile"; device = "/swapfile";
size = 50 * 1024; # 50GiB size = 50 * 1024; # 50GiB
} }
]; ];
@ -132,9 +147,15 @@ in
}; };
}; };
networking.interfaces.uplink.ipv6.addresses = [ networking.interfaces.uplink.ipv6.addresses = [
{ address = "2a01:584:11::1:${toString cfg.num}"; prefixLength = 64; } {
address = "2a01:584:11::1:${toString cfg.num}";
prefixLength = 64;
}
]; ];
networking.defaultGateway6 = { interface = "uplink"; address = "2a01:584:11::1"; }; networking.defaultGateway6 = {
interface = "uplink";
address = "2a01:584:11::1";
};
deployment.targetHost = "2a01:584:11::1:${toString cfg.num}"; deployment.targetHost = "2a01:584:11::1:${toString cfg.num}";
deployment.tags = [ "builders" ]; deployment.tags = [ "builders" ];

View file

@ -1,4 +1,11 @@
{ modulesPath, pkgs, lib, config, extendModules, ... }@node: {
modulesPath,
pkgs,
lib,
config,
extendModules,
...
}@node:
let let
cfg = config.bagel.baremetal.builders; cfg = config.bagel.baremetal.builders;
in in
@ -32,8 +39,20 @@ in
{ {
system.stateVersion = "24.11"; system.stateVersion = "24.11";
boot.initrd.availableKernelModules = [ "ahci" "ehci_pci" "usb_storage" "usbhid" "sd_mod" "igb" "bonding" ]; boot.initrd.availableKernelModules = [
boot.kernelParams = [ "console=ttyS0,115200" "panic=1" "boot.panic_on_fail" ]; "ahci"
"ehci_pci"
"usb_storage"
"usbhid"
"sd_mod"
"igb"
"bonding"
];
boot.kernelParams = [
"console=ttyS0,115200"
"panic=1"
"boot.panic_on_fail"
];
#boot.initrd.systemd.emergencyAccess = true; #boot.initrd.systemd.emergencyAccess = true;
networking.hostName = "${node.config.networking.hostName}-boot"; networking.hostName = "${node.config.networking.hostName}-boot";
nixpkgs.overlays = import ../../overlays; nixpkgs.overlays = import ../../overlays;
@ -72,64 +91,84 @@ in
''; '';
# Provide a bootable USB drive image # Provide a bootable USB drive image
system.build.usbImage = pkgs.callPackage ({ stdenv, runCommand, dosfstools, e2fsprogs, mtools, libfaketime, util-linux, nukeReferences }: system.build.usbImage = pkgs.callPackage (
runCommand "boot-img-${node.config.networking.hostName}" { {
nativeBuildInputs = [ dosfstools e2fsprogs libfaketime mtools util-linux ]; stdenv,
outputs = [ "out" "firmware_part" ]; runCommand,
} '' dosfstools,
export img=$out e2fsprogs,
truncate -s 40M $img mtools,
libfaketime,
util-linux,
nukeReferences,
}:
runCommand "boot-img-${node.config.networking.hostName}"
{
nativeBuildInputs = [
dosfstools
e2fsprogs
libfaketime
mtools
util-linux
];
outputs = [
"out"
"firmware_part"
];
}
''
export img=$out
truncate -s 40M $img
sfdisk $img <<EOF sfdisk $img <<EOF
label: gpt label: gpt
label-id: F222513B-DED1-49FA-B591-20CE86A2FE7F label-id: F222513B-DED1-49FA-B591-20CE86A2FE7F
type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, bootable type=C12A7328-F81F-11D2-BA4B-00A0C93EC93B, bootable
EOF EOF
# Create a FAT32 /boot/firmware partition of suitable size into firmware_part.img # Create a FAT32 /boot/firmware partition of suitable size into firmware_part.img
eval $(partx $img -o START,SECTORS --nr 1 --pairs) eval $(partx $img -o START,SECTORS --nr 1 --pairs)
truncate -s $((2081 * 512 + SECTORS * 512)) firmware_part.img truncate -s $((2081 * 512 + SECTORS * 512)) firmware_part.img
mkfs.vfat --invariant -i 2e24ec82 -n BOOT firmware_part.img mkfs.vfat --invariant -i 2e24ec82 -n BOOT firmware_part.img
# Populate the files intended for /boot/firmware # Populate the files intended for /boot/firmware
mkdir -p firmware/EFI/BOOT firmware/loader/entries mkdir -p firmware/EFI/BOOT firmware/loader/entries
cp ${pkgs.systemd}/lib/systemd/boot/efi/systemd-boot*.efi firmware/EFI/BOOT/BOOT${lib.toUpper stdenv.hostPlatform.efiArch}.EFI cp ${pkgs.systemd}/lib/systemd/boot/efi/systemd-boot*.efi firmware/EFI/BOOT/BOOT${lib.toUpper stdenv.hostPlatform.efiArch}.EFI
cat > firmware/loader/loader.conf << EOF cat > firmware/loader/loader.conf << EOF
default foo default foo
EOF EOF
cat > firmware/loader/entries/default.conf << EOF cat > firmware/loader/entries/default.conf << EOF
title Default title Default
linux /EFI/${pkgs.stdenv.hostPlatform.linux-kernel.target} linux /EFI/${pkgs.stdenv.hostPlatform.linux-kernel.target}
initrd /EFI/initrd initrd /EFI/initrd
options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} options init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams}
EOF EOF
cp ${config.system.build.kernel}/${pkgs.stdenv.hostPlatform.linux-kernel.target} firmware/EFI/${pkgs.stdenv.hostPlatform.linux-kernel.target} cp ${config.system.build.kernel}/${pkgs.stdenv.hostPlatform.linux-kernel.target} firmware/EFI/${pkgs.stdenv.hostPlatform.linux-kernel.target}
cp ${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile} firmware/EFI/initrd cp ${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile} firmware/EFI/initrd
find firmware -exec touch --date=2000-01-01 {} + find firmware -exec touch --date=2000-01-01 {} +
# Copy the populated /boot/firmware into the SD image # Copy the populated /boot/firmware into the SD image
cd firmware cd firmware
# Force a fixed order in mcopy for better determinism, and avoid file globbing # Force a fixed order in mcopy for better determinism, and avoid file globbing
for d in $(find . -type d -mindepth 1 | sort); do for d in $(find . -type d -mindepth 1 | sort); do
faketime "2000-01-01 00:00:00" mmd -i ../firmware_part.img "::/$d" faketime "2000-01-01 00:00:00" mmd -i ../firmware_part.img "::/$d"
done done
for f in $(find . -type f | sort); do for f in $(find . -type f | sort); do
mcopy -pvm -i ../firmware_part.img "$f" "::/$f" mcopy -pvm -i ../firmware_part.img "$f" "::/$f"
done done
cd .. cd ..
# Verify the FAT partition before copying it. # Verify the FAT partition before copying it.
fsck.vfat -vn firmware_part.img fsck.vfat -vn firmware_part.img
dd conv=notrunc if=firmware_part.img of=$img seek=$START count=$SECTORS dd conv=notrunc if=firmware_part.img of=$img seek=$START count=$SECTORS
cp firmware_part.img $firmware_part cp firmware_part.img $firmware_part
'' ''
) {}; ) { };
} };
;
}; };
# This is the config which will actually be booted # This is the config which will actually be booted
@ -145,10 +184,11 @@ in
]; ];
}; };
# A derivation combining all the artifacts required for netbooting for the hydra job # A derivation combining all the artifacts required for netbooting for the hydra job
netbootDir = let netbootDir =
kernelTarget = pkgs.stdenv.hostPlatform.linux-kernel.target; let
build = config.system.build.netbootVariant.config.system.build; kernelTarget = pkgs.stdenv.hostPlatform.linux-kernel.target;
in build = config.system.build.netbootVariant.config.system.build;
in
pkgs.symlinkJoin { pkgs.symlinkJoin {
name = "netboot"; name = "netboot";
paths = [ paths = [

View file

@ -9,24 +9,33 @@ let
cfg = config.bagel.services.buildbot; cfg = config.bagel.services.buildbot;
cfgGerrit = nodes.gerrit01.config.bagel.services.gerrit; cfgGerrit = nodes.gerrit01.config.bagel.services.gerrit;
ssh-keys = import ../../common/ssh-keys.nix; ssh-keys = import ../../common/ssh-keys.nix;
inherit (lib) mkEnableOption mkOption mkIf types; inherit (lib)
mkEnableOption
mkOption
mkIf
types
;
in in
{ {
options.bagel.services.buildbot = { options.bagel.services.buildbot = {
enable = mkEnableOption "Buildbot"; enable = mkEnableOption "Buildbot";
domain = mkOption { domain = mkOption { type = types.str; };
type = types.str;
};
builders = mkOption { builders = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
description = "List of builders to configure for Buildbot"; description = "List of builders to configure for Buildbot";
example = [ "builder-2" "builder-3" ]; example = [
"builder-2"
"builder-3"
];
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = [ 80 443 ]; networking.firewall.allowedTCPPorts = [
80
443
];
age.secrets.buildbot-worker-password.file = ../../secrets/buildbot-worker-password.age; age.secrets.buildbot-worker-password.file = ../../secrets/buildbot-worker-password.age;
age.secrets.buildbot-oauth-secret.file = ../../secrets/buildbot-oauth-secret.age; age.secrets.buildbot-oauth-secret.file = ../../secrets/buildbot-oauth-secret.age;
age.secrets.buildbot-workers.file = ../../secrets/buildbot-workers.age; age.secrets.buildbot-workers.file = ../../secrets/buildbot-workers.age;
@ -56,18 +65,17 @@ in
workerPasswordFile = config.age.secrets.buildbot-worker-password.path; workerPasswordFile = config.age.secrets.buildbot-worker-password.path;
# All credits to eldritch horrors for this beauty. # All credits to eldritch horrors for this beauty.
workerArchitectures = workerArchitectures =
{ {
# nix-eval-jobs runs under a lock, error reports do not (but are cheap) # nix-eval-jobs runs under a lock, error reports do not (but are cheap)
other = 8; other = 8;
} // ( }
lib.filterAttrs // (lib.filterAttrs (n: v: lib.elem n config.services.buildbot-nix.coordinator.buildSystems) (
(n: v: lib.elem n config.services.buildbot-nix.coordinator.buildSystems) lib.zipAttrsWith (_: lib.foldl' lib.add 0) (
(lib.zipAttrsWith lib.concatMap (
(_: lib.foldl' lib.add 0) m: map (s: { ${s} = m.maxJobs; }) m.systems
(lib.concatMap ) config.services.buildbot-nix.coordinator.buildMachines
(m: map (s: { ${s} = m.maxJobs; }) m.systems) )
config.services.buildbot-nix.coordinator.buildMachines)) ));
);
}; };
services.buildbot-nix.coordinator = { services.buildbot-nix.coordinator = {
@ -90,28 +98,23 @@ in
# we can replace all of this with automatic localworker generation on buildbot-nix side. # we can replace all of this with automatic localworker generation on buildbot-nix side.
workersFile = config.age.secrets.buildbot-workers.path; workersFile = config.age.secrets.buildbot-workers.path;
allowedOrigins = [ allowedOrigins = [ "*.forkos.org" ];
"*.forkos.org"
];
# TODO(raito): is that really necessary when we can just collect buildMachines' systems? # TODO(raito): is that really necessary when we can just collect buildMachines' systems?
buildSystems = [ buildSystems = [ "x86_64-linux" ];
"x86_64-linux"
];
buildMachines = map (n: { buildMachines = map (n: {
hostName = nodes.${n}.config.networking.fqdn; hostName = nodes.${n}.config.networking.fqdn;
protocol = "ssh-ng"; protocol = "ssh-ng";
# Follows Hydra. # Follows Hydra.
maxJobs = 8; maxJobs = 8;
sshKey = config.age.secrets.buildbot-remote-builder-key.path; sshKey = config.age.secrets.buildbot-remote-builder-key.path;
sshUser = "buildbot"; sshUser = "buildbot";
systems = [ "x86_64-linux" ]; systems = [ "x86_64-linux" ];
supportedFeatures = nodes.${n}.config.nix.settings.system-features; supportedFeatures = nodes.${n}.config.nix.settings.system-features;
# Contrary to how Nix works, here we can specify non-base64 public host keys. # Contrary to how Nix works, here we can specify non-base64 public host keys.
publicHostKey = ssh-keys.machines.${n}; publicHostKey = ssh-keys.machines.${n};
} }) cfg.builders;
) cfg.builders;
gerrit = { gerrit = {
domain = cfgGerrit.canonicalDomain; domain = cfgGerrit.canonicalDomain;

View file

@ -1,18 +1,25 @@
{ pkgs, lib, config, ... }: {
pkgs,
lib,
config,
...
}:
let let
cfg = config.bagel.services.forgejo; cfg = config.bagel.services.forgejo;
inherit (lib) mkIf mkEnableOption mkOption types; inherit (lib)
mkIf
mkEnableOption
mkOption
types
;
domain = "git.forkos.org"; domain = "git.forkos.org";
in in
{ {
options.bagel.services.forgejo = { options.bagel.services.forgejo = {
enable = mkEnableOption "Forgejo"; enable = mkEnableOption "Forgejo";
sshBindAddr = mkOption { sshBindAddr = mkOption { type = types.str; };
type = types.str;
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@ -116,8 +123,14 @@ in
# start Forgejo *after* sshd.service, so in case Forgejo tries to wildcard bind :22 due to # start Forgejo *after* sshd.service, so in case Forgejo tries to wildcard bind :22 due to
# a bug or whatever, we don't lose OpenSSH in a race. # a bug or whatever, we don't lose OpenSSH in a race.
wants = [ "sshd.service" "redis-forgejo.service" ]; wants = [
requires = [ "sshd.service" "redis-forgejo.service" ]; "sshd.service"
"redis-forgejo.service"
];
requires = [
"sshd.service"
"redis-forgejo.service"
];
}; };
services.redis.servers.forgejo = { services.redis.servers.forgejo = {

View file

@ -1,9 +1,20 @@
# Gerrit configuration for the Nixpkgs monorepo # Gerrit configuration for the Nixpkgs monorepo
# Inspired from TVL configuration. # Inspired from TVL configuration.
{ pkgs, config, lib, ... }: {
pkgs,
config,
lib,
...
}:
let let
inherit (lib) mkEnableOption mkIf mkOption types head; inherit (lib)
mkEnableOption
mkIf
mkOption
types
head
;
cfgGerrit = config.services.gerrit; cfgGerrit = config.services.gerrit;
cfg = config.bagel.services.gerrit; cfg = config.bagel.services.gerrit;
@ -53,7 +64,7 @@ in
isSystemUser = true; isSystemUser = true;
group = "git"; group = "git";
}; };
users.groups.git = {}; users.groups.git = { };
services.gerrit = { services.gerrit = {
enable = true; enable = true;
@ -74,20 +85,22 @@ in
oauth oauth
metrics-reporter-prometheus metrics-reporter-prometheus
# Buildbot checks plugin (writeText because services.gerrit.plugins expects packages) # Buildbot checks plugin (writeText because services.gerrit.plugins expects packages)
(pkgs.runCommand "checks.js" { (pkgs.runCommand "checks.js"
BASE_URI = builtins.toJSON "https://buildbot.forkos.org"; {
SUPPORTED_PROJECTS = builtins.toJSON [ BASE_URI = builtins.toJSON "https://buildbot.forkos.org";
"infra" SUPPORTED_PROJECTS = builtins.toJSON [
"nixpkgs" "infra"
"buildbot-test" "nixpkgs"
]; "buildbot-test"
} ];
'' }
echo "configuring buildbot checks plugin for $BASE_URI with $SUPPORTED_PROJECTS project list" ''
substitute ${./checks.js} $out \ echo "configuring buildbot checks plugin for $BASE_URI with $SUPPORTED_PROJECTS project list"
--replace-fail "@BASE_URI@" "$BASE_URI" \ substitute ${./checks.js} $out \
--replace-fail "@SUPPORTED_PROJECTS@" "$SUPPORTED_PROJECTS" --replace-fail "@BASE_URI@" "$BASE_URI" \
'') --replace-fail "@SUPPORTED_PROJECTS@" "$SUPPORTED_PROJECTS"
''
)
]; ];
package = pkgs.gerrit; package = pkgs.gerrit;
@ -251,7 +264,7 @@ in
age.secrets.gerrit-prometheus-bearer-token.file = ../../secrets/gerrit-prometheus-bearer-token.age; age.secrets.gerrit-prometheus-bearer-token.file = ../../secrets/gerrit-prometheus-bearer-token.age;
bagel.monitoring.grafana-agent.exporters.gerrit = { bagel.monitoring.grafana-agent.exporters.gerrit = {
port = 4778; # grrt port = 4778; # grrt
bearerTokenFile = config.age.secrets.gerrit-prometheus-bearer-token.path; bearerTokenFile = config.age.secrets.gerrit-prometheus-bearer-token.path;
scrapeConfig.metrics_path = "/plugins/metrics-reporter-prometheus/metrics"; scrapeConfig.metrics_path = "/plugins/metrics-reporter-prometheus/metrics";
}; };

View file

@ -1,59 +1,90 @@
{ lib, config, pkgs, ... }: {
lib,
config,
pkgs,
...
}:
let let
cfg = config.bagel.nixpkgs.one-way-sync; cfg = config.bagel.nixpkgs.one-way-sync;
inherit (lib) mkIf mkOption mkEnableOption types mapAttrs'; inherit (lib)
mkIf
mkOption
mkEnableOption
types
mapAttrs'
;
mkSyncTimer = name: { timer, ... }: { mkSyncTimer =
wantedBy = [ "timers.target" ]; name:
{ timer, ... }:
{
wantedBy = [ "timers.target" ];
timerConfig = { timerConfig = {
OnCalendar = timer; OnCalendar = timer;
Persistent = true; Persistent = true;
Unit = "ows-${name}.service"; Unit = "ows-${name}.service";
};
}; };
}; mkSyncService =
mkSyncService = name: { fromUri, fromRefspec, localRefspec, ... }: { name:
path = [ pkgs.gitFull pkgs.openssh pkgs.lix ]; {
script = '' fromUri,
set -xe fromRefspec,
RUNTIME_DIRECTORY="/run/onewaysync-${name}" localRefspec,
trap "git worktree remove -f "$RUNTIME_DIRECTORY"/${name}" EXIT ...
}:
{
path = [
pkgs.gitFull
pkgs.openssh
pkgs.lix
];
script =
''
set -xe
RUNTIME_DIRECTORY="/run/onewaysync-${name}"
trap "git worktree remove -f "$RUNTIME_DIRECTORY"/${name}" EXIT
if [ ! -d "/var/lib/onewaysync/nixpkgs" ]; then if [ ! -d "/var/lib/onewaysync/nixpkgs" ]; then
echo "First run, synchronizing nixpkgs..." echo "First run, synchronizing nixpkgs..."
git clone https://cl.forkos.org/nixpkgs /var/lib/onewaysync/nixpkgs git clone https://cl.forkos.org/nixpkgs /var/lib/onewaysync/nixpkgs
fi fi
cd /var/lib/onewaysync/nixpkgs cd /var/lib/onewaysync/nixpkgs
echo "Syncing ${fromUri}:${fromRefspec} to ${cfg.pushUrl}:refs/heads/${localRefspec}" echo "Syncing ${fromUri}:${fromRefspec} to ${cfg.pushUrl}:refs/heads/${localRefspec}"
echo "Current ref: $EXPECTED_REF" echo "Current ref: $EXPECTED_REF"
git worktree add -f "$RUNTIME_DIRECTORY"/${name} refs/remotes/origin/${localRefspec} git worktree add -f "$RUNTIME_DIRECTORY"/${name} refs/remotes/origin/${localRefspec}
cd "$RUNTIME_DIRECTORY"/${name} cd "$RUNTIME_DIRECTORY"/${name}
git pull origin ${localRefspec} --no-rebase git pull origin ${localRefspec} --no-rebase
EXPECTED_REF=$(git rev-list refs/remotes/origin/${localRefspec} | head -1) EXPECTED_REF=$(git rev-list refs/remotes/origin/${localRefspec} | head -1)
git config user.name Fork-o-Tron git config user.name Fork-o-Tron
git config user.email noreply@forkos.org git config user.email noreply@forkos.org
git fetch ${fromUri} ${fromRefspec} git fetch ${fromUri} ${fromRefspec}
'' + lib.optionalString (!(lib.hasInfix "staging" localRefspec)) '' ''
OLD_STDENV=$(nix eval -f . stdenv.outPath --store "$RUNTIME_DIRECTORY") + lib.optionalString (!(lib.hasInfix "staging" localRefspec)) ''
'' + '' OLD_STDENV=$(nix eval -f . stdenv.outPath --store "$RUNTIME_DIRECTORY")
git merge FETCH_HEAD ''
'' + lib.optionalString (!(lib.hasInfix "staging" localRefspec)) '' + ''
NEW_STDENV=$(nix eval -f . stdenv.outPath --store "$RUNTIME_DIRECTORY") git merge FETCH_HEAD
# Do not allow auto-merging a staging iteration ''
test "$OLD_STDENV" = "$NEW_STDENV" + lib.optionalString (!(lib.hasInfix "staging" localRefspec)) ''
'' + '' NEW_STDENV=$(nix eval -f . stdenv.outPath --store "$RUNTIME_DIRECTORY")
GIT_SSH_COMMAND='ssh -i ${cfg.deployKeyPath}' git push ${cfg.pushUrl} HEAD:refs/heads/${localRefspec} # Do not allow auto-merging a staging iteration
''; test "$OLD_STDENV" = "$NEW_STDENV"
serviceConfig = { ''
User = "git"; + ''
Group = "git"; GIT_SSH_COMMAND='ssh -i ${cfg.deployKeyPath}' git push ${cfg.pushUrl} HEAD:refs/heads/${localRefspec}
Type = "oneshot"; '';
RuntimeDirectory = "onewaysync-${name}"; serviceConfig = {
WorkingDirectory = "/run/onewaysync-${name}"; User = "git";
StateDirectory = "onewaysync"; Group = "git";
Type = "oneshot";
RuntimeDirectory = "onewaysync-${name}";
WorkingDirectory = "/run/onewaysync-${name}";
StateDirectory = "onewaysync";
};
}; };
};
in in
{ {
options.bagel.nixpkgs.one-way-sync = { options.bagel.nixpkgs.one-way-sync = {
@ -84,35 +115,39 @@ in
}; };
branches = mkOption { branches = mkOption {
type = types.attrsOf (types.submodule ({ ... }: type = types.attrsOf (
{ types.submodule (
options = { { ... }:
name = mkOption { {
type = types.str; options = {
description = "User-friendly name"; name = mkOption {
}; type = types.str;
description = "User-friendly name";
};
fromUri = mkOption { fromUri = mkOption {
type = types.str; type = types.str;
description = "Git URI from which we need to sync"; description = "Git URI from which we need to sync";
}; };
fromRefspec = mkOption { fromRefspec = mkOption {
type = types.str; type = types.str;
description = "refspec for the fetch"; description = "refspec for the fetch";
}; };
localRefspec = mkOption { localRefspec = mkOption {
type = types.str; type = types.str;
default = "local refspec in the local repository to get the expected reference and avoid stale info"; default = "local refspec in the local repository to get the expected reference and avoid stale info";
}; };
timer = mkOption { timer = mkOption {
type = types.str; type = types.str;
description = "Calendar format everytime we need to run the sync"; description = "Calendar format everytime we need to run the sync";
}; };
}; };
})); }
)
);
description = "Set of branches mapping from cl.forkos.org to other Git repositories"; description = "Set of branches mapping from cl.forkos.org to other Git repositories";
}; };

View file

@ -3,39 +3,42 @@ let
inherit (lib) mkIf; inherit (lib) mkIf;
cfg = config.bagel.services.gerrit; cfg = config.bagel.services.gerrit;
in in
{ {
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.nginx = { services.nginx = {
enable = true; enable = true;
enableReload = true; enableReload = true;
appendHttpConfig = '' appendHttpConfig = ''
add_header Permissions-Policy "interest-cohort=()"; add_header Permissions-Policy "interest-cohort=()";
''; '';
recommendedProxySettings = false; recommendedProxySettings = false;
};
services.nginx.virtualHosts.gerrit = {
serverName = builtins.head cfg.domains;
serverAliases = builtins.tail cfg.domains;
enableACME = true;
forceSSL = true;
extraConfig = ''
location / {
proxy_pass http://localhost:4778;
proxy_set_header X-Forwarded-For $remote_addr;
# The :443 suffix is a workaround for https://b.tvl.fyi/issues/88.
proxy_set_header Host $host:443;
# Gerrit can throw a lot of data.
proxy_buffering off;
# NGINX should not give up super fast. Things can take time.
proxy_read_timeout 3600;
}
location = /robots.txt {
return 200 'User-agent: *\nAllow: /';
}
'';
};
networking.firewall.allowedTCPPorts = [ 443 80 ];
}; };
services.nginx.virtualHosts.gerrit = {
serverName = builtins.head cfg.domains;
serverAliases = builtins.tail cfg.domains;
enableACME = true;
forceSSL = true;
extraConfig = ''
location / {
proxy_pass http://localhost:4778;
proxy_set_header X-Forwarded-For $remote_addr;
# The :443 suffix is a workaround for https://b.tvl.fyi/issues/88.
proxy_set_header Host $host:443;
# Gerrit can throw a lot of data.
proxy_buffering off;
# NGINX should not give up super fast. Things can take time.
proxy_read_timeout 3600;
}
location = /robots.txt {
return 200 'User-agent: *\nAllow: /';
}
'';
};
networking.firewall.allowedTCPPorts = [
443
80
];
};
} }

View file

@ -1,4 +1,10 @@
{ nodes, config, lib, pkgs, ... }: {
nodes,
config,
lib,
pkgs,
...
}:
let let
cfg = config.bagel.services.hydra; cfg = config.bagel.services.hydra;
@ -7,46 +13,66 @@ let
narCacheDir = "/var/cache/hydra/nar-cache"; narCacheDir = "/var/cache/hydra/nar-cache";
port = 3000; port = 3000;
mkCacheSettings = settings: builtins.concatStringsSep "&" ( mkCacheSettings =
lib.mapAttrsToList (k: v: "${k}=${v}") settings settings: builtins.concatStringsSep "&" (lib.mapAttrsToList (k: v: "${k}=${v}") settings);
);
# XXX: to support Nix's dumb public host key syntax (base64'd), this outputs # XXX: to support Nix's dumb public host key syntax (base64'd), this outputs
# a string with shell-style command interpolations: $(...). # a string with shell-style command interpolations: $(...).
mkBaremetalBuilder = { mkBaremetalBuilder =
parallelBuilds, {
publicHostKey, parallelBuilds,
host, publicHostKey,
speedFactor ? 1, host,
user ? "builder", speedFactor ? 1,
supportedSystems ? [ "i686-linux" "x86_64-linux" ], user ? "builder",
supportedFeatures ? [ "big-parallel" "kvm" "nixos-test" ], supportedSystems ? [
requiredFeatures ? [ ] "i686-linux"
}: "x86_64-linux"
let ],
supportedFeatures_ = if (supportedFeatures != []) then lib.concatStringsSep "," supportedFeatures else "-"; supportedFeatures ? [
requiredFeatures_ = if (requiredFeatures != []) then lib.concatStringsSep "," requiredFeatures else "-"; "big-parallel"
in "kvm"
"ssh://${user}@${host}?remote-store=/mnt ${lib.concatStringsSep "," supportedSystems} ${config.age.secrets.hydra-ssh-key-priv.path} ${toString parallelBuilds} ${toString speedFactor} ${supportedFeatures_} ${requiredFeatures_} $(echo -n '${publicHostKey}' | base64 -w0)"; "nixos-test"
],
requiredFeatures ? [ ],
}:
let
supportedFeatures_ =
if (supportedFeatures != [ ]) then lib.concatStringsSep "," supportedFeatures else "-";
requiredFeatures_ =
if (requiredFeatures != [ ]) then lib.concatStringsSep "," requiredFeatures else "-";
in
"ssh://${user}@${host}?remote-store=/mnt ${lib.concatStringsSep "," supportedSystems} ${config.age.secrets.hydra-ssh-key-priv.path} ${toString parallelBuilds} ${toString speedFactor} ${supportedFeatures_} ${requiredFeatures_} $(echo -n '${publicHostKey}' | base64 -w0)";
# TODO: # TODO:
# - generalize to new architectures # - generalize to new architectures
# - generalize to new features # - generalize to new features
baremetalBuilders = lib.concatStringsSep "\n" baremetalBuilders = lib.concatStringsSep "\n" (
(map (n: let map (
assignments = (import ../baremetal-builder/assignments.nix).${n} or { n:
inherit (nodes.${n}.config.nix.settings) max-jobs; let
supported-features = [ "big-parallel" "kvm" "nixos-test" ]; assignments =
required-features = []; (import ../baremetal-builder/assignments.nix).${n} or {
}; inherit (nodes.${n}.config.nix.settings) max-jobs;
in mkBaremetalBuilder { supported-features = [
parallelBuilds = assignments.max-jobs; "big-parallel"
supportedFeatures = assignments.supported-features; "kvm"
requiredFeatures = assignments.required-features; "nixos-test"
publicHostKey = ssh-keys.machines.${n}; ];
host = nodes.${n}.config.networking.fqdn; required-features = [ ];
}) cfg.builders); };
in { in
mkBaremetalBuilder {
parallelBuilds = assignments.max-jobs;
supportedFeatures = assignments.supported-features;
requiredFeatures = assignments.required-features;
publicHostKey = ssh-keys.machines.${n};
host = nodes.${n}.config.networking.fqdn;
}
) cfg.builders
);
in
{
options.bagel.services.hydra = with lib; { options.bagel.services.hydra = with lib; {
enable = mkEnableOption "Hydra coordinator"; enable = mkEnableOption "Hydra coordinator";
@ -58,7 +84,10 @@ in {
builders = mkOption { builders = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
description = "List of builders to configure for Hydra"; description = "List of builders to configure for Hydra";
example = [ "builder-0" "builder-1" ]; example = [
"builder-0"
"builder-1"
];
}; };
}; };
@ -83,7 +112,12 @@ in {
# XXX: Otherwise services.hydra-dev overwrites it to only hydra-queue-runner... # XXX: Otherwise services.hydra-dev overwrites it to only hydra-queue-runner...
# #
# Can be removed once this is added to some common config template. # Can be removed once this is added to some common config template.
nix.settings.trusted-users = [ "root" "hydra" "hydra-www" "@wheel" ]; nix.settings.trusted-users = [
"root"
"hydra"
"hydra-www"
"@wheel"
];
# Because Hydra can't fetch flake inputs otherwise... also yes, this # Because Hydra can't fetch flake inputs otherwise... also yes, this
# prefix-based matching is absurdly bad. # prefix-based matching is absurdly bad.
@ -111,7 +145,7 @@ in {
package = pkgs.hydra; package = pkgs.hydra;
buildMachinesFiles = [ buildMachinesFiles = [
(pkgs.runCommandNoCC "hydra-builders.conf" {} '' (pkgs.runCommandNoCC "hydra-builders.conf" { } ''
cat >$out <<EOF cat >$out <<EOF
${baremetalBuilders} ${baremetalBuilders}
EOF EOF
@ -119,18 +153,20 @@ in {
]; ];
extraConfig = '' extraConfig = ''
store_uri = s3://bagel-cache?${mkCacheSettings { store_uri = s3://bagel-cache?${
endpoint = "s3.delroth.net"; mkCacheSettings {
region = "garage"; endpoint = "s3.delroth.net";
region = "garage";
secret-key = config.age.secrets.hydra-signing-priv.path; secret-key = config.age.secrets.hydra-signing-priv.path;
compression = "zstd"; compression = "zstd";
log-compression = "br"; log-compression = "br";
ls-compression = "br"; ls-compression = "br";
write-nar-listing = "1"; write-nar-listing = "1";
}} }
}
server_store_uri = https://bagel-cache.s3-web.delroth.net?local-nar-cache=${narCacheDir} server_store_uri = https://bagel-cache.s3-web.delroth.net?local-nar-cache=${narCacheDir}
binary_cache_public_url = https://bagel-cache.s3-web.delroth.net binary_cache_public_url = https://bagel-cache.s3-web.delroth.net
@ -186,6 +222,9 @@ in {
}; };
}; };
networking.firewall.allowedTCPPorts = [ 80 443 ]; networking.firewall.allowedTCPPorts = [
80
443
];
}; };
} }

View file

@ -6,7 +6,12 @@
}: }:
let let
cfg = config.bagel.services.hookshot; cfg = config.bagel.services.hookshot;
inherit (lib) mkEnableOption mkIf mkOption types; inherit (lib)
mkEnableOption
mkIf
mkOption
types
;
keyPath = "/var/lib/matrix-hookshot/key.pem"; keyPath = "/var/lib/matrix-hookshot/key.pem";
in in
{ {
@ -24,9 +29,9 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
systemd.services.matrix-hookshot = { systemd.services.matrix-hookshot = {
wantedBy = ["multi-user.target"]; wantedBy = [ "multi-user.target" ];
wants = ["network-online.target"]; wants = [ "network-online.target" ];
after = ["network-online.target"]; after = [ "network-online.target" ];
serviceConfig = { serviceConfig = {
ExecStart = "${lib.getExe pkgs.matrix-hookshot} ${pkgs.writers.writeYAML "config.yaml" cfg.settings}"; ExecStart = "${lib.getExe pkgs.matrix-hookshot} ${pkgs.writers.writeYAML "config.yaml" cfg.settings}";
ExecStartPre = pkgs.writeShellScript "hookshot-generate-key" '' ExecStartPre = pkgs.writeShellScript "hookshot-generate-key" ''
@ -50,21 +55,25 @@ in
bindAddress = "127.0.0.1"; bindAddress = "127.0.0.1";
}; };
passFile = keyPath; passFile = keyPath;
listeners = [{ listeners = [
port = 9994; {
bindAddress = "127.0.0.1"; port = 9994;
resources = [ "webhooks" ]; bindAddress = "127.0.0.1";
}]; resources = [ "webhooks" ];
}
];
generic = { generic = {
enabled = true; enabled = true;
urlPrefix = "https://alerts.forkos.org/webhook"; urlPrefix = "https://alerts.forkos.org/webhook";
}; };
permissions = map (mxid: { permissions = map (mxid: {
actor = mxid; actor = mxid;
services = [{ services = [
service = "*"; {
level = "admin"; service = "*";
}]; level = "admin";
}
];
}) cfg.admins; }) cfg.admins;
}; };

View file

@ -1,16 +1,19 @@
{ { config, lib, ... }:
config,
lib,
...
}:
let let
cfg = config.bagel.monitoring.grafana-agent; cfg = config.bagel.monitoring.grafana-agent;
inherit (lib) mkEnableOption mkOption mkIf types; inherit (lib)
mkEnableOption
mkOption
mkIf
types
;
passwordAsCredential = "\${CREDENTIALS_DIRECTORY}/password"; passwordAsCredential = "\${CREDENTIALS_DIRECTORY}/password";
in in
{ {
options.bagel.monitoring.grafana-agent = { options.bagel.monitoring.grafana-agent = {
enable = (mkEnableOption "Grafana Agent") // { default = true; }; enable = (mkEnableOption "Grafana Agent") // {
default = true;
};
exporters = mkOption { exporters = mkOption {
description = '' description = ''
@ -20,41 +23,47 @@ in
internally, which ends up exported as `job` label internally, which ends up exported as `job` label
on all metrics of that exporter. on all metrics of that exporter.
''; '';
type = types.attrsOf (types.submodule ({ config, name, ... }: { type = types.attrsOf (
options.port = mkOption { types.submodule (
description = "Exporter port"; { config, name, ... }:
type = types.int; {
}; options.port = mkOption {
options.bearerTokenFile = mkOption { description = "Exporter port";
description = "File containing a bearer token"; type = types.int;
type = types.nullOr types.path; };
default = null; options.bearerTokenFile = mkOption {
}; description = "File containing a bearer token";
type = types.nullOr types.path;
default = null;
};
options.scrapeConfig = mkOption { options.scrapeConfig = mkOption {
description = "Prometheus scrape config"; description = "Prometheus scrape config";
type = types.attrs; type = types.attrs;
}; };
config.scrapeConfig = lib.mkMerge [{ config.scrapeConfig = lib.mkMerge [
job_name = name; {
static_configs = [ job_name = name;
{ targets = [ "localhost:${toString config.port}" ]; } static_configs = [ { targets = [ "localhost:${toString config.port}" ]; } ];
]; }
} (lib.mkIf (config.bearerTokenFile != null) { (lib.mkIf (config.bearerTokenFile != null) {
authorization.credentials_file = "\${CREDENTIALS_DIRECTORY}/${name}-bearer-token"; authorization.credentials_file = "\${CREDENTIALS_DIRECTORY}/${name}-bearer-token";
})]; })
];
options.secrets = mkOption { options.secrets = mkOption {
description = "Secrets required for scrape config"; description = "Secrets required for scrape config";
type = types.attrs; type = types.attrs;
internal = true; internal = true;
default = {}; default = { };
}; };
config.secrets = lib.mkIf (config.bearerTokenFile != null) { config.secrets = lib.mkIf (config.bearerTokenFile != null) {
"${name}-bearer-token" = config.bearerTokenFile; "${name}-bearer-token" = config.bearerTokenFile;
}; };
})); }
default = {}; )
);
default = { };
}; };
}; };
@ -63,8 +72,10 @@ in
services.grafana-agent = { services.grafana-agent = {
enable = true; enable = true;
credentials = lib.mkMerge ([{ password = config.age.secrets.grafana-agent-password.path; }] ++ credentials = lib.mkMerge (
lib.mapAttrsToList (name: value: value.secrets) config.bagel.monitoring.grafana-agent.exporters); [ { password = config.age.secrets.grafana-agent-password.path; } ]
++ lib.mapAttrsToList (name: value: value.secrets) config.bagel.monitoring.grafana-agent.exporters
);
settings = { settings = {
metrics = { metrics = {
global.remote_write = [ global.remote_write = [
@ -80,7 +91,9 @@ in
configs = [ configs = [
{ {
name = config.networking.hostName; name = config.networking.hostName;
scrape_configs = lib.mapAttrsToList (name: value: value.scrapeConfig) config.bagel.monitoring.grafana-agent.exporters; scrape_configs = lib.mapAttrsToList (
name: value: value.scrapeConfig
) config.bagel.monitoring.grafana-agent.exporters;
} }
]; ];
}; };

View file

@ -1,14 +1,12 @@
{ { config, lib, ... }:
config,
lib,
...
}:
let let
cfg = config.bagel.monitoring.exporters.cadvisor; cfg = config.bagel.monitoring.exporters.cadvisor;
inherit (lib) mkEnableOption mkIf; inherit (lib) mkEnableOption mkIf;
in in
{ {
options.bagel.monitoring.exporters.cadvisor.enable = (mkEnableOption "Standard cAdvisor") // { default = !config.boot.isContainer; }; options.bagel.monitoring.exporters.cadvisor.enable = (mkEnableOption "Standard cAdvisor") // {
default = !config.boot.isContainer;
};
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.cadvisor = { services.cadvisor = {

View file

@ -1,15 +1,13 @@
{ { config, lib, ... }:
config,
lib,
...
}:
let let
cfg = config.bagel.monitoring.exporters.nginx; cfg = config.bagel.monitoring.exporters.nginx;
inherit (lib) mkEnableOption mkIf; inherit (lib) mkEnableOption mkIf;
logFormat = ''$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"''; logFormat = ''$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" rt=$request_time uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"'';
in in
{ {
options.bagel.monitoring.exporters.nginx.enable = (mkEnableOption "Nginx access.log exporter") // { default = config.services.nginx.enable; }; options.bagel.monitoring.exporters.nginx.enable = (mkEnableOption "Nginx access.log exporter") // {
default = config.services.nginx.enable;
};
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.nginx.appendHttpConfig = '' services.nginx.appendHttpConfig = ''
@ -25,7 +23,7 @@ in
{ {
name = "nginx"; name = "nginx";
format = logFormat; format = logFormat;
source.files = ["/var/log/nginx/access.log"]; source.files = [ "/var/log/nginx/access.log" ];
} }
]; ];
}; };

View file

@ -1,14 +1,12 @@
{ { config, lib, ... }:
config,
lib,
...
}:
let let
cfg = config.bagel.monitoring.exporters.postgres; cfg = config.bagel.monitoring.exporters.postgres;
inherit (lib) mkEnableOption mkIf; inherit (lib) mkEnableOption mkIf;
in in
{ {
options.bagel.monitoring.exporters.postgres.enable = (mkEnableOption "Postgres exporter") // { default = config.services.postgresql.enable; }; options.bagel.monitoring.exporters.postgres.enable = (mkEnableOption "Postgres exporter") // {
default = config.services.postgresql.enable;
};
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.prometheus.exporters.postgres = { services.prometheus.exporters.postgres = {

View file

@ -7,16 +7,16 @@
let let
cfg = config.bagel.services.alertmanager-hookshot-adapter; cfg = config.bagel.services.alertmanager-hookshot-adapter;
inherit (lib) mkEnableOption mkIf; inherit (lib) mkEnableOption mkIf;
package = pkgs.callPackage ./package.nix {}; package = pkgs.callPackage ./package.nix { };
in in
{ {
options.bagel.services.alertmanager-hookshot-adapter.enable = mkEnableOption "alertmanager to matrix-hookshot adapter"; options.bagel.services.alertmanager-hookshot-adapter.enable = mkEnableOption "alertmanager to matrix-hookshot adapter";
config = mkIf cfg.enable { config = mkIf cfg.enable {
systemd.services.alertmanager-hookshot-adapter = { systemd.services.alertmanager-hookshot-adapter = {
wantedBy = ["multi-user.target"]; wantedBy = [ "multi-user.target" ];
wants = ["network-online.target"]; wants = [ "network-online.target" ];
after = ["network-online.target"]; after = [ "network-online.target" ];
environment = { environment = {
PORT = "9100"; PORT = "9100";
UPSTREAM = "https://alerts.forkos.org/webhook"; UPSTREAM = "https://alerts.forkos.org/webhook";

View file

@ -1,8 +1,4 @@
{ { config, lib, ... }:
config,
lib,
...
}:
let let
cfg = config.bagel.services.grafana; cfg = config.bagel.services.grafana;
inherit (lib) mkEnableOption mkIf; inherit (lib) mkEnableOption mkIf;
@ -133,19 +129,21 @@ in
]; ];
}; };
nginx = let nginx =
scfg = config.services.grafana.settings.server; let
in { scfg = config.services.grafana.settings.server;
enable = true; in
virtualHosts."${scfg.domain}" = { {
enableACME = true; enable = true;
forceSSL = true; virtualHosts."${scfg.domain}" = {
locations."/" = { enableACME = true;
proxyPass = "http://${scfg.http_addr}:${toString scfg.http_port}"; forceSSL = true;
proxyWebsockets = true; locations."/" = {
proxyPass = "http://${scfg.http_addr}:${toString scfg.http_port}";
proxyWebsockets = true;
};
}; };
}; };
};
}; };
bagel.monitoring.grafana-agent.exporters.grafana.port = 2342; bagel.monitoring.grafana-agent.exporters.grafana.port = 2342;

View file

@ -1,8 +1,4 @@
{ { config, lib, ... }:
config,
lib,
...
}:
let let
cfg = config.bagel.services.loki; cfg = config.bagel.services.loki;
inherit (lib) mkEnableOption mkIf; inherit (lib) mkEnableOption mkIf;
@ -21,7 +17,7 @@ in
services.loki = { services.loki = {
enable = true; enable = true;
extraFlags = ["--config.expand-env"]; extraFlags = [ "--config.expand-env" ];
configuration = { configuration = {
server = { server = {
@ -90,7 +86,7 @@ in
services.nginx = { services.nginx = {
upstreams.loki = { upstreams.loki = {
servers."127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}" = {}; servers."127.0.0.1:${toString config.services.loki.configuration.server.http_listen_port}" = { };
extraConfig = "keepalive 16;"; extraConfig = "keepalive 16;";
}; };

View file

@ -25,7 +25,7 @@ in
services.mimir = { services.mimir = {
enable = true; enable = true;
extraFlags = ["--config.expand-env=true"]; extraFlags = [ "--config.expand-env=true" ];
configuration = { configuration = {
target = "all,alertmanager"; target = "all,alertmanager";
@ -60,7 +60,7 @@ in
blocks_storage.backend = "s3"; blocks_storage.backend = "s3";
ruler_storage = { ruler_storage = {
backend = "local"; backend = "local";
local.directory = pkgs.runCommand "mimir-rules" {} '' local.directory = pkgs.runCommand "mimir-rules" { } ''
mkdir -p $out mkdir -p $out
ln -s ${./alerts} $out/anonymous ln -s ${./alerts} $out/anonymous
''; '';
@ -70,17 +70,19 @@ in
sharding_ring.replication_factor = 1; sharding_ring.replication_factor = 1;
fallback_config_file = pkgs.writers.writeYAML "alertmanager.yaml" { fallback_config_file = pkgs.writers.writeYAML "alertmanager.yaml" {
route = { route = {
group_by = ["alertname"]; group_by = [ "alertname" ];
receiver = "matrix"; receiver = "matrix";
}; };
receivers = [ receivers = [
{ {
name = "matrix"; name = "matrix";
webhook_configs = [{ webhook_configs = [
# Mimir can't expand environment variables in external config files, {
# so work around it. # Mimir can't expand environment variables in external config files,
url_file = "/run/credentials/mimir.service/webhook-url"; # so work around it.
}]; url_file = "/run/credentials/mimir.service/webhook-url";
}
];
} }
]; ];
}; };
@ -96,7 +98,7 @@ in
# even when it's the only instance, and fails if it can't find one. # even when it's the only instance, and fails if it can't find one.
# Avoid that by ensuring it starts after the network is set up. # Avoid that by ensuring it starts after the network is set up.
wants = [ "network-online.target" ]; wants = [ "network-online.target" ];
after = ["network-online.target"]; after = [ "network-online.target" ];
serviceConfig = { serviceConfig = {
EnvironmentFile = [ config.age.secrets.mimir-environment.path ]; EnvironmentFile = [ config.age.secrets.mimir-environment.path ];
LoadCredential = [ "webhook-url:${config.age.secrets.mimir-webhook-url.path}" ]; LoadCredential = [ "webhook-url:${config.age.secrets.mimir-webhook-url.path}" ];
@ -105,7 +107,7 @@ in
services.nginx = { services.nginx = {
upstreams.mimir = { upstreams.mimir = {
servers."127.0.0.1:${toString mimirPort}" = {}; servers."127.0.0.1:${toString mimirPort}" = { };
extraConfig = "keepalive 16;"; extraConfig = "keepalive 16;";
}; };

View file

@ -8,15 +8,18 @@
let let
EnvironmentFile = [ config.age.secrets.netbox-environment.path ]; EnvironmentFile = [ config.age.secrets.netbox-environment.path ];
cfg = config.bagel.services.netbox; cfg = config.bagel.services.netbox;
inherit (lib) mkEnableOption mkOption mkIf types; inherit (lib)
mkEnableOption
mkOption
mkIf
types
;
in in
{ {
options.bagel.services.netbox = { options.bagel.services.netbox = {
enable = mkEnableOption "Netbox"; enable = mkEnableOption "Netbox";
domain = mkOption { domain = mkOption { type = types.str; };
type = types.str;
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {

View file

@ -5,7 +5,8 @@ let
amqpHost = "amqp.forkos.org"; amqpHost = "amqp.forkos.org";
amqpPort = 5671; amqpPort = 5671;
in { in
{
options.bagel.services.ofborg = with lib; { options.bagel.services.ofborg = with lib; {
enable = mkEnableOption "ofborg coordinator"; enable = mkEnableOption "ofborg coordinator";
}; };
@ -26,9 +27,8 @@ in {
webroot = "/var/lib/acme/.challenges"; webroot = "/var/lib/acme/.challenges";
group = "rabbitmq"; group = "rabbitmq";
}; };
services.nginx.virtualHosts.${amqpHost}.locations."/.well-known/acme-challenge".root = services.nginx.virtualHosts.${amqpHost}.locations."/.well-known/acme-challenge".root = "/var/lib/acme/.challenges";
"/var/lib/acme/.challenges"; systemd.services.rabbitmq.requires = [ "acme-finished-${amqpHost}.target" ];
systemd.services.rabbitmq.requires = ["acme-finished-${amqpHost}.target"];
networking.firewall.allowedTCPPorts = [ amqpPort ]; networking.firewall.allowedTCPPorts = [ amqpPort ];
}; };

View file

@ -1,10 +1,16 @@
{ config, lib, pkgs, ... }: {
config,
lib,
pkgs,
...
}:
let let
cfg = config.bagel.services.postgres; cfg = config.bagel.services.postgres;
dataDir = "/var/db/postgresql/16"; dataDir = "/var/db/postgresql/16";
in { in
{
options.bagel.services.postgres = with lib; { options.bagel.services.postgres = with lib; {
enable = mkEnableOption "PostgreSQL server"; enable = mkEnableOption "PostgreSQL server";
}; };

View file

@ -1,6 +1,11 @@
{ lib, config, ... }: { lib, config, ... }:
let let
inherit (lib) mkEnableOption mkIf tf genList; inherit (lib)
mkEnableOption
mkIf
tf
genList
;
cfg = config.bagel.gandi; cfg = config.bagel.gandi;
in in
{ {
@ -24,72 +29,102 @@ in
name = "forkos.org"; name = "forkos.org";
}; };
resource.gandi_livedns_record = let resource.gandi_livedns_record =
record = name: ttl: type: values: { let
inherit name ttl type values; record = name: ttl: type: values: {
}; inherit
name
ttl
type
values
;
};
proxyRecords = name: ttl: type: values: [ proxyRecords = name: ttl: type: values: [
# kurisu.lahfa.xyz running a sniproxy: # kurisu.lahfa.xyz running a sniproxy:
(record name ttl "A" ["163.172.69.160"]) (record name ttl "A" [ "163.172.69.160" ])
(record name ttl type values) (record name ttl type values)
]; ];
# Creates a extra *.p record pointing to the sniproxy # Creates a extra *.p record pointing to the sniproxy
dualProxyRecords = name: ttl: type: values: lib.flatten [ dualProxyRecords =
(record name ttl type values) name: ttl: type: values:
(proxyRecords "${name}.p" ttl type values) lib.flatten [
]; (record name ttl type values)
(proxyRecords "${name}.p" ttl type values)
];
# TODO: make less fragile and have actual unique and stable names
canonicalName =
record:
let
name =
builtins.replaceStrings
[
"."
"@"
]
[
"_"
"_root_"
]
record.name;
in
"forkos_org_${record.type}_${name}";
forkosRecords =
records:
builtins.listToAttrs (
map (record: {
name = canonicalName record;
value = record // {
zone = tf.ref "resource.gandi_livedns_domain.forkos_org.id";
};
}) (lib.flatten records)
);
# TODO: make less fragile and have actual unique and stable names
canonicalName = record: let
name = builtins.replaceStrings ["." "@"] ["_" "_root_"] record.name;
in in
"forkos_org_${record.type}_${name}"; forkosRecords (
[
# (record "@" 3600 "A" ["163.172.69.160"])
(record "@" 3600 "AAAA" [ "2001:bc8:38ee:100:1000::20" ])
forkosRecords = records: (dualProxyRecords "bagel-box.infra" 3600 "AAAA" [ "2001:bc8:38ee:100:100::1" ])
builtins.listToAttrs (map (record: { (dualProxyRecords "gerrit01.infra" 3600 "AAAA" [ "2001:bc8:38ee:100:1000::10" ])
name = canonicalName record; (dualProxyRecords "meta01.infra" 3600 "AAAA" [ "2001:bc8:38ee:100:1000::20" ])
value = record // { (dualProxyRecords "fodwatch.infra" 3600 "AAAA" [ "2001:bc8:38ee:100:1000::30" ])
zone = tf.ref "resource.gandi_livedns_domain.forkos_org.id"; # git.infra.forkos.org exposes opensshd
}; (dualProxyRecords "git.infra" 3600 "AAAA" [ "2001:bc8:38ee:100:1000::41" ])
}) (lib.flatten records)); # git.p.forkos.org exposes forgejo ssh server.
(proxyRecords "git.p" 3600 "AAAA" [ "2001:bc8:38ee:100:1000::40" ])
(dualProxyRecords "buildbot.infra" 3600 "AAAA" [ "2001:bc8:38ee:100:1000::50" ])
(dualProxyRecords "public01.infra" 3600 "AAAA" [ "2001:bc8:38ee:100:1000::60" ])
in forkosRecords ([ (record "cl" 3600 "CNAME" [ "gerrit01.infra.p" ])
# (record "@" 3600 "A" ["163.172.69.160"]) (record "fodwatch" 3600 "CNAME" [ "fodwatch.infra.p" ])
(record "@" 3600 "AAAA" ["2001:bc8:38ee:100:1000::20"]) # git.p.forkos.org is the proxy variant of the Forgejo server.
(record "git" 3600 "CNAME" [ "git.p" ])
(record "netbox" 3600 "CNAME" [ "meta01.infra.p" ])
(record "amqp" 3600 "CNAME" [ "bagel-box.infra.p" ])
(record "grafana" 3600 "CNAME" [ "meta01.infra.p" ])
(record "hydra" 3600 "CNAME" [ "bagel-box.infra.p" ])
(record "loki" 3600 "CNAME" [ "meta01.infra.p" ])
(record "mimir" 3600 "CNAME" [ "meta01.infra.p" ])
(record "matrix" 3600 "CNAME" [ "meta01.infra.p" ])
(record "alerts" 3600 "CNAME" [ "meta01.infra.p" ])
(record "buildbot" 3600 "CNAME" [ "buildbot.infra.p" ])
(record "b" 3600 "CNAME" [ "public01.infra.p" ])
(dualProxyRecords "bagel-box.infra" 3600 "AAAA" ["2001:bc8:38ee:100:100::1"]) # S3 in delroth's basement
(dualProxyRecords "gerrit01.infra" 3600 "AAAA" ["2001:bc8:38ee:100:1000::10"]) (record "cache" 3600 "CNAME" [ "smol.delroth.net." ])
(dualProxyRecords "meta01.infra" 3600 "AAAA" ["2001:bc8:38ee:100:1000::20"])
(dualProxyRecords "fodwatch.infra" 3600 "AAAA" ["2001:bc8:38ee:100:1000::30"])
# git.infra.forkos.org exposes opensshd
(dualProxyRecords "git.infra" 3600 "AAAA" ["2001:bc8:38ee:100:1000::41"])
# git.p.forkos.org exposes forgejo ssh server.
(proxyRecords "git.p" 3600 "AAAA" ["2001:bc8:38ee:100:1000::40"])
(dualProxyRecords "buildbot.infra" 3600 "AAAA" ["2001:bc8:38ee:100:1000::50"])
(dualProxyRecords "public01.infra" 3600 "AAAA" ["2001:bc8:38ee:100:1000::60"])
(record "cl" 3600 "CNAME" ["gerrit01.infra.p"]) (record "vpn-gw.wob01.infra" 3600 "AAAA" [ "2a01:584:11::2" ])
(record "fodwatch" 3600 "CNAME" ["fodwatch.infra.p"]) # TODO: do not hardcode, just reuse the Colmena hive module outputs to generate all the required details.
# git.p.forkos.org is the proxy variant of the Forgejo server. ]
(record "git" 3600 "CNAME" ["git.p"]) ++ map (
(record "netbox" 3600 "CNAME" ["meta01.infra.p"]) index:
(record "amqp" 3600 "CNAME" ["bagel-box.infra.p"]) record "builder-${toString index}.wob01.infra" 3600 "AAAA" [ "2a01:584:11::1:${toString index}" ]
(record "grafana" 3600 "CNAME" ["meta01.infra.p"]) ) (genList lib.id 12)
(record "hydra" 3600 "CNAME" ["bagel-box.infra.p"]) );
(record "loki" 3600 "CNAME" ["meta01.infra.p"])
(record "mimir" 3600 "CNAME" ["meta01.infra.p"])
(record "matrix" 3600 "CNAME" ["meta01.infra.p"])
(record "alerts" 3600 "CNAME" ["meta01.infra.p"])
(record "buildbot" 3600 "CNAME" ["buildbot.infra.p"])
(record "b" 3600 "CNAME" ["public01.infra.p"])
# S3 in delroth's basement
(record "cache" 3600 "CNAME" ["smol.delroth.net."])
(record "vpn-gw.wob01.infra" 3600 "AAAA" [ "2a01:584:11::2" ])
# TODO: do not hardcode, just reuse the Colmena hive module outputs to generate all the required details.
] ++ map (index: record "builder-${toString index}.wob01.infra" 3600 "AAAA" [ "2a01:584:11::1:${toString index}" ]) (genList lib.id 12));
}; };
} }

View file

@ -1,6 +1,12 @@
{ lib, config, ... }: { lib, config, ... }:
let let
inherit (lib) mkEnableOption mkIf types mkOption tf; inherit (lib)
mkEnableOption
mkIf
types
mkOption
tf
;
cfg = config.bagel.hydra; cfg = config.bagel.hydra;
in in
{ {