noisebell/flake.nix

258 lines
7.3 KiB
Nix

{
description = "Noisebell - door monitor system";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
agenix = {
url = "github:ryantm/agenix";
inputs.nixpkgs.follows = "nixpkgs";
};
crane.url = "github:ipetkov/crane";
rust-overlay = {
url = "github:oxalica/rust-overlay";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
{
self,
nixpkgs,
agenix,
crane,
rust-overlay,
}:
let
system = "x86_64-linux";
pkgs = import nixpkgs {
inherit system;
overlays = [ rust-overlay.overlays.default ];
};
rustToolchain = pkgs.rust-bin.stable.latest.default;
craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain;
src = pkgs.lib.cleanSourceWith {
src = ./.;
filter =
path: type: (builtins.match ".*\.png$" path != null) || (craneLib.filterCargoSources path type);
};
remoteArgs = {
inherit src;
pname = "noisebell";
version = "0.1.0";
strictDeps = true;
doCheck = false;
};
remoteArtifacts = craneLib.buildDepsOnly remoteArgs;
buildRemoteMember =
name:
craneLib.buildPackage (
remoteArgs
// {
cargoArtifacts = remoteArtifacts;
cargoExtraArgs = "-p ${name}";
}
);
noisebell-cache = buildRemoteMember "noisebell-cache";
noisebell-discord = buildRemoteMember "noisebell-discord";
crossPkgs = import nixpkgs {
inherit system;
crossSystem.config = "aarch64-unknown-linux-gnu";
overlays = [ rust-overlay.overlays.default ];
};
piRustToolchain = pkgs.rust-bin.stable.latest.default.override {
targets = [ "aarch64-unknown-linux-gnu" ];
};
piCraneLib = (crane.mkLib pkgs).overrideToolchain piRustToolchain;
piArgs = {
inherit src;
pname = "noisebell-pi";
version = "0.1.0";
strictDeps = true;
doCheck = false;
CARGO_BUILD_TARGET = "aarch64-unknown-linux-gnu";
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER = "${crossPkgs.stdenv.cc.targetPrefix}cc";
TARGET_CC = "${crossPkgs.stdenv.cc.targetPrefix}cc";
CC_aarch64_unknown_linux_gnu = "${crossPkgs.stdenv.cc.targetPrefix}cc";
HOST_CC = "${pkgs.stdenv.cc.nativePrefix}cc";
depsBuildBuild = [ crossPkgs.stdenv.cc ];
cargoExtraArgs = "-p noisebell";
};
piArtifacts = piCraneLib.buildDepsOnly piArgs;
noisebell-pi = piCraneLib.buildPackage (
piArgs
// {
cargoArtifacts = piArtifacts;
}
);
flash-pi-sd = pkgs.writeShellApplication {
name = "flash-pi-sd";
runtimeInputs = [
agenix.packages.${system}.default
pkgs.coreutils
pkgs.nix
pkgs.parted
pkgs.systemd
pkgs.util-linux
pkgs.zstd
];
text = ''
set -euo pipefail
PARTPROBE=${pkgs.parted}/bin/partprobe
MOUNT=${pkgs.util-linux}/bin/mount
UMOUNT=${pkgs.util-linux}/bin/umount
MOUNTPOINT=${pkgs.util-linux}/bin/mountpoint
FINDMNT=${pkgs.util-linux}/bin/findmnt
UDEVADM=${pkgs.systemd}/bin/udevadm
ZSTD=${pkgs.zstd}/bin/zstd
if [ "$#" -ne 1 ]; then
echo "usage: flash-pi-sd /dev/sdX" >&2
exit 1
fi
device="$1"
flake_path=${builtins.toString ./.}
image_link="$(mktemp -u /tmp/noisebell-sd-image.XXXXXX)"
mount_dir="$(mktemp -d)"
secrets_dir="${builtins.toString ./secrets}"
key_name="bootstrap-identity.age"
rules_file="${builtins.toString ./secrets/secrets.nix}"
cleanup() {
if "$MOUNTPOINT" -q "$mount_dir"; then
sudo "$UMOUNT" "$mount_dir"
fi
rm -rf "$mount_dir"
rm -f "$image_link"
}
trap cleanup EXIT
if [ ! -b "$device" ]; then
echo "not a block device: $device" >&2
exit 1
fi
boot_part="''${device}1"
case "$device" in
*[0-9]) boot_part="''${device}p1" ;;
esac
echo "Building bootstrap SD image..."
nix build "$flake_path#nixosConfigurations.bootstrap.config.system.build.sdImage" -o "$image_link"
image="$(echo "$image_link"/sd-image/*.img*)"
if [ ! -f "$image" ]; then
echo "failed to locate SD image under $image_link/sd-image" >&2
exit 1
fi
echo "Flashing $image to $device..."
if [ "''${image##*.}" = "zst" ]; then
"$ZSTD" -d --stdout "$image" | sudo dd of="$device" bs=4M conv=fsync status=progress
else
sudo dd if="$image" of="$device" bs=4M conv=fsync status=progress
fi
sync
sudo "$PARTPROBE" "$device"
sudo "$UDEVADM" settle
if "$FINDMNT" -rn "$boot_part" >/dev/null 2>&1; then
sudo "$UMOUNT" "$boot_part"
fi
echo "Installing bootstrap age identity onto $boot_part..."
sudo "$MOUNT" "$boot_part" "$mount_dir"
(
cd "$secrets_dir"
RULES="$rules_file" agenix -d "$key_name"
) | sudo tee "$mount_dir/noisebell-bootstrap.agekey" >/dev/null
sudo chmod 600 "$mount_dir/noisebell-bootstrap.agekey"
sync
echo "Done. You can now move the card to the Pi and boot it."
'';
};
in
{
packages.${system} = {
inherit noisebell-cache noisebell-discord flash-pi-sd;
default = noisebell-cache;
};
packages.aarch64-linux = {
noisebell = noisebell-pi;
default = noisebell-pi;
};
nixosModules = {
cache = import ./remote/cache-service/module.nix noisebell-cache;
discord = import ./remote/discord-bot/module.nix noisebell-discord;
default = {
imports = [
(import ./remote/cache-service/module.nix noisebell-cache)
(import ./remote/discord-bot/module.nix noisebell-discord)
];
};
};
nixosConfigurations.pi = nixpkgs.lib.nixosSystem {
system = "aarch64-linux";
modules = [
agenix.nixosModules.default
(import ./pi/module.nix {
pkg = noisebell-pi;
rev = self.shortRev or "dirty";
})
./pi/configuration.nix
./pi/hardware-configuration.nix
];
};
nixosConfigurations.bootstrap = nixpkgs.lib.nixosSystem {
system = "aarch64-linux";
modules = [
agenix.nixosModules.default
(import ./pi/module.nix {
pkg = noisebell-pi;
rev = self.shortRev or "dirty";
})
./pi/bootstrap.nix
];
};
devShells.${system}.default = craneLib.devShell {
packages = [
flash-pi-sd
pkgs.nix
pkgs.parted
pkgs.rust-analyzer
pkgs.systemd
pkgs.util-linux
pkgs.zstd
agenix.packages.${system}.default
];
};
apps.${system}.flash-pi-sd = {
type = "app";
program = "${flash-pi-sd}/bin/flash-pi-sd";
};
};
}