diff --git a/nixos/flake.nix b/nixos/flake.nix index 53487fa..bd6a5d1 100644 --- a/nixos/flake.nix +++ b/nixos/flake.nix @@ -71,7 +71,6 @@ hosts = { izanagi.modules = [ ./hosts/izanagi ]; - Gitea.modules = [ ./hosts/Gitea ]; }; }; } diff --git a/nixos/modules/apps/gitea/default.nix b/nixos/modules/apps/gitea/default.nix index 0048728..eeec8b6 100644 --- a/nixos/modules/apps/gitea/default.nix +++ b/nixos/modules/apps/gitea/default.nix @@ -21,50 +21,6 @@ in { options.homelab.apps.gitea.enable = lib.mkEnableOption "Gitea"; config = lib.mkIf cfg.enable { - services.nats = { - enable = true; - listenAddress = "0.0.0.0"; - port = 4222; - jetstream = true; - }; - - networking.firewall.allowedTCPPorts = [ 4222 9000 ]; - - systemd.services.gitea-webhook-bridge = { - description = "Gitea Webhook Bridge to NATS JetStream"; - after = [ "network.target" "nats.service" ]; - wants = [ "nats.service" ]; - wantedBy = [ "multi-user.target" ]; - path = with pkgs; [ natscli python3 ]; - script = '' - python3 -c ' -import http.server -import subprocess -import sys - -class WebhookHandler(http.server.BaseHTTPRequestHandler): - def do_POST(self): - content_length = int(self.headers.get("Content-Length", 0)) - body = self.rfile.read(content_length) - try: - subprocess.run(["nats", "pub", "--server=nats://127.0.0.1:4222", "forgejo.staging"], input=body, check=True) - self.send_response(200) - self.end_headers() - self.wfile.write(b"OK\n") - except Exception as e: - self.send_response(500) - self.end_headers() - self.wfile.write(str(e).encode("utf-8")) - - def log_message(self, format, *args): - sys.stderr.write("%s - - [%s] %s\n" % (self.client_address[0], self.log_date_time_string(), format%args)) - -server = http.server.ThreadingHTTPServer(("0.0.0.0", 9000), WebhookHandler) -server.serve_forever() -' - ''; - }; - homelab = { users = { apps.enable = true; @@ -482,7 +438,6 @@ server.serve_forever() # ... oath2_client # ... webhook - FORGEJO__webhook__ALLOWED_HOST_LIST = "192.168.0.0/16,127.0.0.0/8,host.docker.internal,*"; FORGEJO__mailer__ENABLED = "true"; # Buffer length of channel, keep it as it is if you don't know what it is. diff --git a/nixos/modules/services/hypervisor-gitops/default.nix b/nixos/modules/services/hypervisor-gitops/default.nix index 2d9d05b..ac8f49f 100644 --- a/nixos/modules/services/hypervisor-gitops/default.nix +++ b/nixos/modules/services/hypervisor-gitops/default.nix @@ -10,36 +10,6 @@ let runtimeInputs = with pkgs; [ git opentofu coreutils ]; text = builtins.readFile ../../../../scripts/hypervisor-sync.sh; }; - - stagingSyncScript = pkgs.writeShellApplication { - name = "staging-sync"; - runtimeInputs = with pkgs; [ opentofu coreutils jq curl ]; - text = builtins.readFile ../../../../scripts/staging-sync.sh; - }; - - natsConsumerScript = pkgs.writeShellApplication { - name = "nats-consumer"; - runtimeInputs = with pkgs; [ natscli jq stagingSyncScript ]; - text = '' - set -euo pipefail - - NATS_URL=''${NATS_URL:-"nats://192.168.0.20:4222"} - - echo "Starting NATS JetStream consumer for staging env..." - - # Try to create stream and consumer if they don't exist - nats --server "$NATS_URL" stream add FORGEJO_EVENTS --subjects "forgejo.staging" --ack --max-msgs=-1 --max-bytes=-1 --max-age=1y --storage file -f || true - nats --server "$NATS_URL" consumer add FORGEJO_EVENTS STAGING --pull --ack explicit --filter forgejo.staging --deliver all -f || true - - echo "Listening for messages..." - while true; do - # We use a simple sub to pull messages. In a real environment, - # a dedicated Go/Python client is better for manual explicit acks. - # This will auto-ack upon receipt and pass to the staging script. - nats --server "$NATS_URL" sub "forgejo.staging" | awk '/\[#.*\]/{flag=1; next} flag' | staging-sync || true - done - ''; - }; in { options.homelab.services.hypervisor-gitops = { enable = mkEnableOption "Hypervisor GitOps Service"; @@ -61,8 +31,6 @@ in { environment.systemPackages = with pkgs; [ git opentofu - natscli - jq ]; systemd.services.hypervisor-gitops = { @@ -92,27 +60,5 @@ in { Persistent = true; }; }; - - systemd.services.staging-sync = { - description = "Staging Environment NATS Consumer"; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - - serviceConfig = { - Type = "simple"; - User = "root"; # Needs root to read SOPS secrets - Restart = "always"; - RestartSec = "10s"; - - StateDirectory = "hypervisor-gitops"; - WorkingDirectory = "/var/lib/hypervisor-gitops"; - - # We assume TRUENAS_API_KEY is provided via a sops EnvironmentFile - # EnvironmentFile = config.sops.secrets."truenas-api-key".path; - - ExecStart = "${natsConsumerScript}/bin/nats-consumer"; - }; - }; }; } diff --git a/opentofu/staging-env/main.tf b/opentofu/staging-env/main.tf index 9538523..b77ee4a 100644 --- a/opentofu/staging-env/main.tf +++ b/opentofu/staging-env/main.tf @@ -4,10 +4,6 @@ terraform { source = "bpg/proxmox" version = "~> 0.61.0" } - truenas = { - source = "deevus/truenas" - version = "~> 0.1.0" - } } } @@ -21,25 +17,10 @@ variable "pr_number" { type = string } -variable "truenas_snapshot_id" { - description = "The ID of the TrueNAS snapshot to clone" - type = string -} - provider "proxmox" { # Relies on PROXMOX_VE_ENDPOINT and PROXMOX_VE_API_TOKEN environment variables } -provider "truenas" { - # Relies on TRUENAS_API_KEY and TRUENAS_BASE_URL environment variables -} - -resource "truenas_dataset" "staging_clone" { - pool = "tank" - path = "production/staging-pr-${var.pr_number}" - snapshot_id = var.truenas_snapshot_id -} - resource "proxmox_virtual_environment_vm" "staging_vm" { name = "staging-pr-${var.pr_number}" description = "Ephemeral staging environment for PR #${var.pr_number}" diff --git a/scripts/staging-sync.sh b/scripts/staging-sync.sh deleted file mode 100644 index eca15b5..0000000 --- a/scripts/staging-sync.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env bash - -# This script is triggered by the NATS JetStream consumer on the Control Center. -# It reads a Forgejo webhook JSON payload from STDIN and orchestrates the -# Staging VM OpenTofu lifecycle. - -set -euo pipefail - -# Read JSON payload from STDIN -PAYLOAD=$(cat) - -# Extract fields using jq -ACTION=$(echo "$PAYLOAD" | jq -r '.action // empty') -PR_NUMBER=$(echo "$PAYLOAD" | jq -r '.pull_request.number // empty') - -if [ -z "$ACTION" ] || [ -z "$PR_NUMBER" ] || [ "$PR_NUMBER" == "null" ]; then - printf "Invalid or missing action/pr_number in payload. Exiting.\n" - exit 0 -fi - -# We only care about PR events -if [[ "$ACTION" != "opened" && "$ACTION" != "reopened" && "$ACTION" != "synchronized" && "$ACTION" != "closed" ]]; then - printf "Ignoring PR action: %%s\n" "$ACTION" - exit 0 -fi - -# Ensure workspace directory exists for this PR -WORKSPACE="/var/lib/hypervisor-gitops/staging-pr-${PR_NUMBER}" -OPENTOFU_SRC="/var/lib/hypervisor-gitops/nix-config/opentofu/staging-env" - -# TrueNAS API variables -TRUENAS_URL=${TRUENAS_URL:-"https://192.168.0.11"} -TRUENAS_API_KEY=${TRUENAS_API_KEY:-""} -ZFS_DATASET=${ZFS_DATASET:-"tank/production"} - -get_latest_snapshot() { - # Fetch the latest snapshot for the dataset from TrueNAS API - # Assumes TRUENAS_API_KEY is exported in the environment by SOPS - curl -sS -k -X GET \ - -H "Authorization: Bearer ${TRUENAS_API_KEY}" \ - -H "Accept: application/json" \ - "${TRUENAS_URL}/api/v2.0/zfs/snapshot?id~=${ZFS_DATASET}%%25&limit=1&sort=-creation" | jq -r '.[0].id' -} - -printf "Processing PR #%%s (Action: %%s)\n" "$PR_NUMBER" "$ACTION" - -if [[ "$ACTION" == "closed" ]]; then - if [ ! -d "$WORKSPACE" ]; then - printf "Workspace %%s does not exist. Nothing to destroy.\n" "$WORKSPACE" - exit 0 - fi - printf "Destroying Staging Environment for PR #%%s...\n" "$PR_NUMBER" - cd "$WORKSPACE" - tofu destroy -var="pr_number=${PR_NUMBER}" -auto-approve - - # Cleanup - cd / - rm -rf "$WORKSPACE" - printf "Staging Environment Destroyed.\n" - exit 0 -fi - -# Provisioning (opened, reopened, synchronized) -printf "Setting up Staging Environment for PR #%%s...\n" "$PR_NUMBER" - -if [ ! -d "$WORKSPACE" ]; then - mkdir -p "$WORKSPACE" - cp -r "$OPENTOFU_SRC"/* "$WORKSPACE"/ -fi - -cd "$WORKSPACE" - -# Fetch latest TrueNAS snapshot dynamically -LATEST_SNAPSHOT=$(get_latest_snapshot) - -if [ -z "$LATEST_SNAPSHOT" ] || [ "$LATEST_SNAPSHOT" == "null" ]; then - printf "Failed to retrieve the latest TrueNAS snapshot. Aborting.\n" - exit 1 -fi - -printf "Latest Snapshot ID: %%s\n" "$LATEST_SNAPSHOT" - -# Apply OpenTofu -tofu init -upgrade -tofu apply -var="pr_number=${PR_NUMBER}" -var="truenas_snapshot_id=${LATEST_SNAPSHOT}" -auto-approve - -printf "Staging Environment Provisioned successfully.\n"