nix-config/flake.nix

738 lines
23 KiB
Nix

{
description = "C3D2 NixOS configurations";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-22.05";
nixpkgs-mobilizon.url = "github:minijackson/nixpkgs/init-mobilizon";
nixpkgs-openwebrx.url = "github:astro/nixpkgs/openwebrx";
nixos-hardware.url = "github:nixos/nixos-hardware";
fenix = {
url = "github:nix-community/fenix";
inputs.nixpkgs.follows = "nixpkgs";
};
heliwatch = {
url = "git+https://gitea.c3d2.de/astro/heliwatch.git";
inputs = {
fenix.follows = "fenix";
nixpkgs.follows = "nixpkgs";
naersk.follows = "naersk";
};
};
hydra.url = "github:nixos/hydra";
hydra-ca.url = "github:thufschmitt/hydra/nix-ca";
microvm = {
url = "github:astro/microvm.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
naersk = {
url = "github:nix-community/naersk";
inputs.nixpkgs.follows = "nixpkgs";
};
oparl-scraper = {
url = "github:offenesdresden/ratsinfo-scraper/oparl";
flake = false;
};
openwrt = {
url = "git+https://git.openwrt.org/openwrt/openwrt.git?ref=openwrt-21.02";
flake = false;
};
openwrt-imagebuilder = {
url = "github:astro/nix-openwrt-imagebuilder";
inputs = {
nixpkgs.follows = "nixpkgs";
openwrt.follows = "openwrt";
};
};
scrapers = {
url = "git+https://gitea.c3d2.de/astro/scrapers.git";
flake = false;
};
secrets = {
url = "git+ssh://gitea@gitea.c3d2.de/c3d2-admins/secrets.git";
inputs = {
nixpkgs.follows = "nixpkgs";
sops-nix.follows = "sops-nix";
};
};
sops-nix = {
url = "github:Mic92/sops-nix";
inputs = {
nixpkgs.follows = "nixpkgs";
};
};
spacemsg = {
url = "github:astro/spacemsg";
flake = false;
};
ticker = {
url = "git+https://gitea.c3d2.de/astro/ticker.git";
inputs.nixpkgs.follows = "nixpkgs";
};
tigger = {
url = "github:astro/tigger";
flake = false;
};
yammat = {
url = "git+https://gitea.c3d2.de/C3D2/yammat.git?ref=nix";
inputs.nixpkgs.follows = "nixpkgs";
};
zentralwerk = {
url = "git+https://gitea.c3d2.de/zentralwerk/network.git";
inputs = {
nixpkgs.follows = "nixpkgs";
nixpkgs-master.follows = "nixpkgs";
openwrt.follows = "openwrt";
openwrt-imagebuilder.follows = "openwrt-imagebuilder";
};
};
riscv64 = {
url = "github:zhaofengli/nixos-riscv64";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = inputs@{ self, nixpkgs, secrets, nixos-hardware, zentralwerk, yammat, scrapers, spacemsg, tigger, ticker, heliwatch, sops-nix, naersk, fenix, microvm, riscv64, oparl-scraper, ... }:
let
inherit (nixpkgs) lib;
forAllSystems = lib.genAttrs [ "aarch64-linux" "x86_64-linux" ];
extractZwHosts = { hosts4, hosts6, ... }:
lib.recursiveUpdate (
builtins.foldl' (result: name:
lib.recursiveUpdate result {
"${name}".ip4 = hosts4."${name}";
}
) {} (builtins.attrNames hosts4)
) (
builtins.foldl' (result: ctx:
builtins.foldl' (result: name:
lib.recursiveUpdate result {
"${name}".ip6 = hosts6."${ctx}"."${name}";
}
) result (builtins.attrNames hosts6."${ctx}")
) {} (builtins.attrNames hosts6)
);
zwHostRegistry = {
hosts =
builtins.foldl' (result: net:
lib.recursiveUpdate result (extractZwHosts zentralwerk.lib.config.site.net."${net}")
) {} [ "core" "c3d2" "serv" ];
};
extraHostRegistry.hosts = import ./host-registry.nix;
hostRegistry = lib.recursiveUpdate zwHostRegistry extraHostRegistry;
getHostAddr = name:
let
hostConf = hostRegistry.hosts."${name}";
in
if hostConf ? ip6
then hostConf.ip6
else if hostConf ? ip4
then hostConf.ip4
else throw "Host ${name} has no ip4 or ip6 address";
in {
overlay = import ./overlay;
legacyPackages = lib.attrsets.mapAttrs
(system: pkgs: pkgs.appendOverlays
[ fenix.overlay naersk.overlay self.overlay ])
nixpkgs.legacyPackages;
packages = lib.attrsets.mapAttrs (system: pkgs:
let overlayPkgs = builtins.intersectAttrs (self.overlay {} {}) pkgs;
in overlayPkgs //
{
list-upgradable = pkgs.writeScriptBin "list-upgradable" ''
#! ${pkgs.runtimeShell}
NORMAL="\033[0m"
RED="\033[0;31m"
YELLOW="\033[0;33m"
GREEN="\033[0;32m"
${pkgs.lib.concatMapStringsSep "\n" (name:
let
addr = getHostAddr name;
in nixpkgs.lib.optionalString (addr != null) ''
echo -n -e "${name}: $RED"
RUNNING=$(ssh -o PreferredAuthentications=publickey -o StrictHostKeyChecking=accept-new root@"${addr}" "readlink /run/current-system")
if [ $? = 0 ] && [ -n "$RUNNING" ]; then
CURRENT=$(nix eval --raw ".#nixosConfigurations.${name}.config.system.build.toplevel" 2>/dev/null)
RUNNING_VER=$(basename $RUNNING|rev|cut -d - -f 1|rev)
RUNNING_DATE=$(echo $RUNNING_VER|cut -d . -f 3)
CURRENT_VER=$(basename $CURRENT|rev|cut -d - -f 1|rev)
CURRENT_DATE=$(echo $CURRENT_VER|cut -d . -f 3)
if [ "$RUNNING" = "$CURRENT" ]; then
echo -e "$GREEN"current"$NORMAL $RUNNING_VER"
elif [ $RUNNING_DATE -gt $CURRENT_DATE ]; then
echo -e "$GREEN"newer"$NORMAL $RUNNING_VER > $CURRENT_VER"
elif [ "$RUNNING_VER" = "$CURRENT_VER" ]; then
echo -e "$YELLOW"modified"$NORMAL $RUNNING_VER"
elif [ -n "$RUNNING_VER" ]; then
echo -e "$RED"outdated"$NORMAL $RUNNING_VER < $CURRENT_VER"
else
echo -e "$RED"error"$NORMAL $RUNNING_VER"
fi
fi
echo -n -e "$NORMAL"
'') (builtins.attrNames self.nixosConfigurations)}
'';
prebuild-all = pkgs.runCommandNoCC "prebuild-all" {
preferLocalBuild = true;
} ''
mkdir $out
${pkgs.lib.concatMapStrings (name: ''
ln -s ${self.nixosConfigurations."${name}".config.system.build.toplevel} name
'') (builtins.attrNames self.nixosConfigurations)}
'';
prebuild-all-remote = pkgs.writeScriptBin "prebuild-all" ''
#!${pkgs.runtimeShell} -e
nix copy --to ssh://$1 ${secrets}
nix copy --to ssh://$1 ${self}
set -x
ssh $1 -- nix build -L --no-link ${
pkgs.lib.concatMapStringsSep " " (name:
"${self}#nixosConfigurations.${name}.config.system.build.toplevel"
) (builtins.attrNames self.nixosConfigurations)
}
'';
} //
builtins.foldl' (result: host: result // {
# TODO: check if the ethernet address is reachable and if not,
# execute wol on a machine in HQ.
"${host}-wake" = pkgs.writeScriptBin "${host}-wake" ''
#!${pkgs.runtimeShell}
exec ${pkgs.wol}/bin/wol ${hostRegistry.hosts."${host}".ether}
'';
}) {} (builtins.attrNames (nixpkgs.lib.filterAttrs (_: { wol ? false, ... }: wol) hostRegistry.hosts)) //
builtins.foldl' (result: name:
let
host = getHostAddr name;
target = ''root@"${host}"'';
rebuildArg = "--flake ${self}#${name}";
hostConfig = self.nixosConfigurations."${name}".config;
profile = hostConfig.system.build.toplevel;
# let /var/lib/microvm/*/flake point to the flake-update branch so that
# `microvm -u $NAME` updates to what hydra built today.
selfRef = "git+https://gitea.c3d2.de/c3d2/nix-config?ref=flake-update";
in result // {
# Generate a small script for copying this flake to the
# remote machine and bulding and switching there.
# Can be run with `nix run c3d2#…-nixos-rebuild switch`
"${name}-nixos-rebuild" = pkgs.writeScriptBin "${name}-nixos-rebuild" ''
#!${pkgs.runtimeShell} -ex
[[ $(ssh ${target} cat /etc/hostname) == ${name} ]]
nix copy --to ssh://${target} ${secrets}
nix copy --to ssh://${target} ${self}
ssh ${target} nixos-rebuild ${rebuildArg} "$@"
'';
"${name}-nixos-rebuild-local" = pkgs.writeScriptBin "${name}-nixos-rebuild" ''
#!${pkgs.runtimeShell} -ex
[[ $(ssh ${target} cat /etc/hostname) == ${name} ]]
nix copy --to ssh://${target} ${profile}
ssh ${target} "${profile}/bin/switch-to-configuration $*"
'';
"${name}-cleanup" = pkgs.writeScriptBin "${name}-cleanup" ''
#!${pkgs.runtimeShell} -ex
ssh ${target} "time nix-collect-garbage -d && time nix-store --optimise"
'';
} // lib.optionalAttrs (hostConfig ? c3d2.deployment.server) {
"microvm-update-${name}" = pkgs.writeScriptBin "microvm-update-${name}" ''
#!${pkgs.runtimeShell} -e
${hostConfig.system.build.copyToServer} ${self} ${secrets}
${hostConfig.system.build.runOnServer} bash -e <<END
mkdir -p /var/lib/microvms/${name}
cd /var/lib/microvms/${name}
chown root:kvm .
chmod 0775 .
rm -f old
[ -e current ] && mv current old
nix build -L \
-o current \
${self}#nixosConfigurations.${name}.config.microvm.declaredRunner
echo '${selfRef}' > flake
[ -e old ] && nix store diff-closures ./old ./current
systemctl restart microvm@${name}.service
END
'';
"microvm-update-${name}-local" = pkgs.writeScriptBin "microvm-update-${name}" ''
#!${pkgs.runtimeShell} -e
${hostConfig.system.build.copyToServer} ${hostConfig.microvm.declaredRunner}
${hostConfig.system.build.runOnServer} bash -e <<END
mkdir -p /var/lib/microvms/${name}
cd /var/lib/microvms/${name}
chown root:kvm .
chmod 0775 .
rm -f old
[ -e current ] && mv current old
ln -s ${hostConfig.microvm.declaredRunner} current
echo '${selfRef}' > flake
[ -e old ] && nix store diff-closures ./old ./current
systemctl restart microvm@${name}.service
END
'';
}) {} (builtins.attrNames self.nixosConfigurations) //
builtins.foldl' (result: host:
let
inherit (self.nixosConfigurations.${host}) config;
in
result //
nixpkgs.lib.optionalAttrs (config.system.build ? vm) {
# boot any machine in a microvm
"${host}-vm" = (self.nixosConfigurations.${host}
.extendModules {
modules = [
microvm.nixosModules.microvm
{
microvm = {
mem = nixpkgs.lib.mkForce 2048;
hypervisor = nixpkgs.lib.mkForce "qemu";
socket = nixpkgs.lib.mkForce null;
shares = [ {
tag = "ro-store";
source = "/nix/store";
mountPoint = "/nix/.ro-store";
} ];
};
boot.isContainer = lib.mkForce false;
users.users.root.password = "";
fileSystems."/".fsType = lib.mkForce "tmpfs";
services.getty.helpLine = ''
Log in as "root" with an empty password.
Use "reboot" to shut qemu down.
'';
}
];
})
.config.microvm.declaredRunner;
} //
nixpkgs.lib.optionalAttrs (config.system.build ? tftproot) {
"${host}-tftproot" = config.system.build.tftproot;
}
) {} (builtins.attrNames self.nixosConfigurations)
) self.legacyPackages;
nixosConfigurations = let
nixosSystem' =
# Our custom NixOS builder
{ nixpkgs ? inputs.nixpkgs, modules, extraArgs ? {}, specialArgs ? { }, system ? "x86_64-linux" }:
nixpkgs.lib.nixosSystem {
inherit specialArgs system;
modules = [
({ pkgs, ... }: {
_module.args = extraArgs // {
inherit hostRegistry inputs zentralwerk;
};
nixpkgs = {
overlays = [ self.overlay ];
};
})
self.nixosModules.c3d2
./config/audio-server
./config/c3d2.nix
./config/stats.nix
./modules/pi-sensors.nix
] ++ modules;
};
in {
freifunk = nixosSystem' {
modules = [
self.nixosModules.microvm
./hosts/containers/freifunk
{
nixpkgs.overlays = with secrets.overlays; [
freifunk ospf
];
sops.defaultSopsFile = "${secrets}/hosts/freifunk/secrets.yaml";
}
];
};
gitea = nixosSystem' {
modules = [
self.nixosModules.microvm
./hosts/containers/gitea
];
};
glotzbert = nixosSystem' {
modules = [
./hosts/glotzbert
nixos-hardware.nixosModules.common-cpu-intel
nixos-hardware.nixosModules.common-pc-ssd
secrets.nixosModules.admins
{
sops.defaultSopsFile = "${secrets}/hosts/glotzbert/secrets.yaml";
}
];
};
hedgedoc = nixosSystem' {
modules = [
self.nixosModules.microvm
{
sops.defaultSopsFile = "${secrets}/hosts/hedgedoc/secrets.yaml";
}
./hosts/containers/hedgedoc
];
};
pulsebert = nixosSystem' {
modules = [
./hosts/pulsebert
];
system = "aarch64-linux";
};
radiobert = nixosSystem' {
modules = [
({ modulesPath, ... }:
{
nixpkgs.overlays = [ heliwatch.overlay ];
sops.defaultSopsFile = "${secrets}/hosts/radiobert/secrets.yaml";
})
./hosts/radiobert
];
system = "aarch64-linux";
};
nncp = nixosSystem' {
modules = [
self.nixosModules.microvm
self.nixosModules.nncp
./hosts/containers/nncp
];
};
dacbert = nixosSystem' {
modules = [
nixos-hardware.nixosModules.raspberry-pi-4
self.nixosModules.rpi-netboot
./hosts/dacbert
];
system = "aarch64-linux";
};
rpi-netboot = nixosSystem' {
modules = [
{ _module.args = { inherit nixpkgs; }; }
nixos-hardware.nixosModules.raspberry-pi-4
self.nixosModules.rpi-netboot
./hosts/rpi-netboot
];
system = "aarch64-linux";
};
matemat = nixosSystem' {
modules = [
self.nixosModules.microvm
./hosts/containers/matemat
yammat.nixosModule
secrets.nixosModules.admins
{ nixpkgs.overlays = [ secrets.overlays.matemat ]; }
];
};
scrape = nixosSystem' {
modules = [
self.nixosModules.microvm
./hosts/containers/scrape
{
nixpkgs.overlays = [ secrets.overlays.scrape ];
_module.args = { inherit scrapers; };
}
];
};
dn42 = nixosSystem' {
modules = [
self.nixosModules.microvm
./hosts/containers/dn42
{
nixpkgs.overlays = [ secrets.overlays.dn42 ];
sops.defaultSopsFile = "${secrets}/hosts/dn42/secrets.yaml";
}
];
};
grafana = nixosSystem' {
modules = [
self.nixosModules.microvm
./hosts/containers/grafana
];
};
hydra = nixosSystem' {
modules = [
inputs.hydra.nixosModules.hydra
./hosts/hydra
{
sops.defaultSopsFile = "${secrets}/hosts/hydra/secrets.yaml";
}
];
specialArgs = {
hydra-ca = inputs.hydra-ca;
};
};
mucbot = nixosSystem' {
modules = [
{ _module.args = { inherit tigger; }; }
self.nixosModules.microvm
"${tigger}/module.nix"
{ nixpkgs.overlays = [ secrets.overlays.mucbot ]; }
./hosts/containers/mucbot
];
};
kibana = nixosSystem' {
modules = [
./config/lxc-container.nix
./hosts/containers/kibana
];
};
public-access-proxy = nixosSystem' {
modules = [
self.nixosModules.microvm
./hosts/containers/public-access-proxy
];
};
ticker = nixosSystem' {
modules = [
self.nixosModules.microvm
ticker.nixosModules.ticker
./hosts/containers/ticker
];
};
spaceapi = nixosSystem' {
modules = [
self.nixosModules.microvm
"${spacemsg}/spaceapi/module.nix"
./hosts/containers/spaceapi
];
};
stream = nixosSystem' {
modules = [
./config/lxc-container.nix
./hosts/containers/stream
];
};
mobilizon = nixosSystem' {
# TODO: pending https://github.com/NixOS/nixpkgs/pull/119132
nixpkgs = inputs.nixpkgs-mobilizon;
modules = [
self.nixosModules.microvm
./hosts/containers/mobilizon
];
};
mail = nixosSystem' {
modules = [
./config/lxc-container.nix
./hosts/containers/mail
];
};
logging = nixosSystem' {
modules = [
./config/lxc-container.nix
./hosts/containers/logging
];
};
# TODO: requires config cleanup for nixos-22.05
# keycloak = nixosSystem' {
# modules = [
# ./config/lxc-container.nix
# ./hosts/containers/keycloak
# { nixpkgs.overlays = with secrets.overlays; [ keycloak ]; }
# ];
# };
c3d2-web = nixosSystem' {
modules = [
{ _module.args = { inherit nixpkgs; }; }
self.nixosModules.microvm
./hosts/containers/c3d2-web
{ nixpkgs.overlays = [ secrets.overlays.c3d2-web ]; }
];
};
sdrweb = nixosSystem' {
modules = [
self.nixosModules.microvm
{ nixpkgs.overlays = [ secrets.overlays.mucbot ]; }
heliwatch.nixosModules.heliwatch
./hosts/containers/sdrweb
];
};
bind = nixosSystem' {
modules = [
{ nixpkgs.overlays = with secrets.overlays; [ bind ]; }
self.nixosModules.microvm
./hosts/containers/bind
];
};
jabber = nixosSystem' {
modules = [
{ nixpkgs.overlays = with secrets.overlays; [ jabber ]; }
self.nixosModules.microvm
./hosts/containers/jabber
];
};
blogs = nixosSystem' {
modules = [
self.nixosModules.plume
self.nixosModules.microvm
./hosts/containers/blogs
{ sops.defaultSopsFile = "${secrets}/hosts/blogs/secrets.yaml"; }
];
};
server9 = nixosSystem' {
modules = [
./hosts/server9
microvm.nixosModules.host
self.nixosModules.cluster-network
{ _module.args = { inherit self; }; }
];
};
server10 = nixosSystem' {
modules = [
./hosts/server10
microvm.nixosModules.host
self.nixosModules.cluster-network
{ _module.args = { inherit self; }; }
];
};
oparl = nixosSystem' {
modules = [
self.nixosModules.microvm
./hosts/containers/oparl
{
_module.args = { inherit oparl-scraper; };
sops.defaultSopsFile = "${secrets}/hosts/oparl/secrets.yaml";
}
];
};
leon = nixosSystem' {
modules = [
self.nixosModules.microvm
./hosts/containers/leon
];
};
nfsroot = nixosSystem' {
modules = [
self.nixosModules.microvm
./hosts/containers/nfsroot
{
_module.args.tftproots = nixpkgs.lib.filterAttrs (name: _:
builtins.match ".+-tftproot" name != null
) self.packages.x86_64-linux;
} ];
};
riscbert = nixosSystem' {
modules = [
riscv64.nixosModules.visionfive
./hosts/riscbert
];
system = "riscv64-linux";
};
direkthilfe = nixosSystem' {
modules = [
self.nixosModules.microvm
./hosts/containers/direkthilfe
];
};
mediawiki = nixosSystem' {
modules = [
self.nixosModules.microvm
./hosts/containers/mediawiki
];
};
};
nixosModule = self.nixosModules.c3d2;
nixosModules = {
c3d2 = {
imports = [
sops-nix.nixosModule
./modules/c3d2.nix
./modules/nncp.nix
./modules/autoupdate.nix
];
c3d2.hosts = hostRegistry.hosts;
c3d2.users = import ./users.nix;
c3d2.nncp.neigh = import ./config/nncp-relays.nix;
};
cluster-network = ./modules/cluster-network.nix;
microvm.imports = [
microvm.nixosModules.microvm
./modules/microvm.nix
];
nncp = ./modules/nncp.nix;
plume = {
imports = [ ./modules/plume.nix ];
nixpkgs.overlays = [ fenix.overlay naersk.overlay ];
};
rpi-netboot = ./modules/rpi-netboot.nix;
};
hydraJobs =
builtins.mapAttrs (_: nixpkgs.lib.hydraJob) (
builtins.mapAttrs (_: nixosSystem:
if nixosSystem.config ? microvm.declaredRunner
then nixosSystem.config.microvm.declaredRunner
else nixosSystem.config.system.build.toplevel
) self.nixosConfigurations
//
nixpkgs.lib.filterAttrs (name: _:
builtins.match ".+-tftproot" name != null
) self.packages.aarch64-linux
);
};
}