nix-config/modules/common/gitops.nix

141 lines
4.1 KiB
Nix

{ config, lib, pkgs, ... }:
let
cfg = config.homelab.gitops;
updateScript = pkgs.writeShellApplication {
name = "homelab-gitops-update";
runtimeInputs = [ pkgs.git pkgs.nixos-rebuild pkgs.jq pkgs.coreutils ];
text = ''
set -euo pipefail
REMOTE_URL="${cfg.repoUrl}"
BRANCH="${cfg.branch}"
echo "Checking remote hash for $REMOTE_URL branch $BRANCH..."
# Fetch remote hash, fallback to unknown if it fails
REMOTE_HASH=$(git ls-remote "$REMOTE_URL" "refs/heads/$BRANCH" | awk '{print $1}' || true)
if [ -z "$REMOTE_HASH" ]; then
echo "WARNING: Could not fetch remote hash. Forcing rebuild to be safe."
REMOTE_HASH="unknown_remote"
fi
LOCAL_HASH="unknown_local"
if [ -f /run/current-system/configurationRevision ]; then
LOCAL_HASH=$(cat /run/current-system/configurationRevision)
fi
echo "Remote hash: $REMOTE_HASH"
echo "Local hash: $LOCAL_HASH"
if [ "$REMOTE_HASH" = "$LOCAL_HASH" ] && [ "$REMOTE_HASH" != "unknown_remote" ] && [ "$LOCAL_HASH" != "unknown" ]; then
echo "Hashes match. No update needed."
exit 0
fi
echo "Hashes differ or unknown. Triggering nixos-rebuild..."
# Trigger the build and switch
nixos-rebuild switch --flake "git+$REMOTE_URL?ref=$BRANCH"
echo "Update successful."
'';
};
in {
options.homelab.gitops = {
enable = lib.mkEnableOption "Custom GitOps native deployment system";
repoUrl = lib.mkOption {
type = lib.types.str;
default = "https://git.depeuter.dev/Bos55/nix-config.git";
description = "The repository URL to pull configurations from.";
};
branch = lib.mkOption {
type = lib.types.str;
default = "v2";
description = "The branch to deploy.";
};
useBuilder = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to use the central Builder host to compile packages.";
};
};
config = lib.mkIf cfg.enable {
# 1. Systemd Service and Timer for polling
systemd.services.homelab-gitops = {
description = "Homelab GitOps Update Service";
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${updateScript}/bin/homelab-gitops-update";
# Must run as root to rebuild the system
User = "root";
};
};
systemd.timers.homelab-gitops = {
description = "Timer for Homelab GitOps Update Service";
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "5m";
OnUnitActiveSec = "5m";
RandomizedDelaySec = "30s";
};
};
# 2. Webhook listener for instant trigger
sops.secrets."webhook-secret" = {};
services.webhook = {
enable = true;
port = 9000;
hooks = {
gitops = {
execute-command = "${pkgs.systemd}/bin/systemctl";
pass-arguments-to-command = [
{ source = "string"; name = "start"; }
{ source = "string"; name = "homelab-gitops.service"; }
];
trigger-rule = {
match = {
type = "payload-hash-sha256";
secret = "{{ getenv \"WEBHOOK_SECRET\" }}";
parameter = {
source = "header";
name = "X-Forgejo-Signature";
};
};
};
};
};
};
# Inject the secret as an environment variable into the webhook service
systemd.services.webhook.serviceConfig.EnvironmentFile = config.sops.secrets."webhook-secret".path;
# 3. Builder Configuration
sops.secrets."builder-ssh-key" = lib.mkIf cfg.useBuilder {};
nix.buildMachines = lib.mkIf cfg.useBuilder [
{
hostName = "builder.depeuter.dev"; # Must be routable from nodes
system = "x86_64-linux";
sshUser = "builder";
sshKey = config.sops.secrets."builder-ssh-key".path;
maxJobs = 4;
speedFactor = 2;
supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ];
}
];
nix.distributedBuilds = lib.mkIf cfg.useBuilder true;
};
}