From 0d7d0909501158f4ac31d228135f83cebb89d9d2 Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Mon, 16 Feb 2026 23:06:25 +0300 Subject: [PATCH] nix/demo-vm: remove useless MOTD Signed-off-by: NotAShelf Change-Id: Ib80e6f2a568d7bfe7d7e7efc92f56f966a6a6964 --- nix/demo-vm.nix | 40 ++++------------------ nix/tests/e2e.nix | 86 ++++++++++++++++++++++++++++++----------------- 2 files changed, 62 insertions(+), 64 deletions(-) diff --git a/nix/demo-vm.nix b/nix/demo-vm.nix index 0296791..57f99de 100644 --- a/nix/demo-vm.nix +++ b/nix/demo-vm.nix @@ -3,6 +3,7 @@ pkgs, lib, }: let + inherit (lib.modules) mkForce; fc-packages = self.packages.${pkgs.stdenv.hostPlatform.system}; # Demo password file to demonstrate passwordFile option @@ -24,6 +25,7 @@ services.fc-ci = { enable = true; + package = fc-packages.fc-server; evaluatorPackage = fc-packages.fc-evaluator; queueRunnerPackage = fc-packages.fc-queue-runner; @@ -41,9 +43,9 @@ signing.enabled = false; server = { # Bind to all interfaces so port forwarding works - host = lib.mkForce "0.0.0.0"; + host = mkForce "0.0.0.0"; port = 3000; - cors_permissive = lib.mkForce true; + cors_permissive = mkForce true; }; }; @@ -113,7 +115,7 @@ ''; }; - # --- Useful tools inside the VM --- + # Useful tools inside the VM environment.systemPackages = with pkgs; [ curl jq @@ -124,42 +126,14 @@ zstd ]; - # --- Misc VM settings --- + # Misc VM settings networking.hostName = "fc-demo"; networking.firewall.allowedTCPPorts = [3000]; services.getty.autologinUser = "root"; - - # Show a helpful MOTD - environment.etc."motd".text = '' - ┌─────────────────────────────────────────────────────────────┐ - │ Dashboard: http://localhost:3000 │ - │ API: http://localhost:3000/api/v1 │ - │ │ - │ Web login: admin / AdminPassword123! (admin) │ - │ demo / DemoPassword123! (read-only) │ - │ Admin API key: fc_demo_admin_key │ - │ Read-only API key: fc_demo_readonly_key │ - │ │ - │ Useful commands: │ - │ $ systemctl status fc-server │ - │ $ journalctl -u fc-server -f │ - │ $ curl -sf localhost:3000/health | jq │ - │ $ curl -sf localhost:3000/metrics │ - │ │ - │ Press Ctrl-a x to quit QEMU. │ - └─────────────────────────────────────────────────────────────┘ - ''; - system.stateVersion = "26.11"; }); in pkgs.writeShellApplication { name = "run-fc-demo-vm"; - text = '' - echo "Starting FC CI demo VM..." - echo "Dashboard will be available at http://localhost:3000" - echo "Press Ctrl-a x to quit." - echo "" - exec ${nixos.config.system.build.vm}/bin/run-fc-demo-vm - ''; + text = "exec ${nixos.config.system.build.vm}/bin/run-fc-demo-vm"; } diff --git a/nix/tests/e2e.nix b/nix/tests/e2e.nix index d22bb70..1409812 100644 --- a/nix/tests/e2e.nix +++ b/nix/tests/e2e.nix @@ -49,6 +49,16 @@ pkgs.testers.nixosTest { ) ro_header = f"-H 'Authorization: Bearer {ro_token}'" + with subtest("PostgreSQL LISTEN/NOTIFY triggers are installed"): + result = machine.succeed( + "sudo -u fc psql -U fc -d fc -c \"SELECT tgname FROM pg_trigger WHERE tgname LIKE 'trg_%_notify'\" -t" + ) + assert "trg_builds_insert_notify" in result, f"Missing trg_builds_insert_notify in: {result}" + assert "trg_builds_status_notify" in result, f"Missing trg_builds_status_notify in: {result}" + assert "trg_jobsets_insert_notify" in result, f"Missing trg_jobsets_insert_notify in: {result}" + assert "trg_jobsets_update_notify" in result, f"Missing trg_jobsets_update_notify in: {result}" + assert "trg_jobsets_delete_notify" in result, f"Missing trg_jobsets_delete_notify in: {result}" + # Create a test flake inside the VM with subtest("Create bare git repo with test flake"): machine.succeed("mkdir -p /var/lib/fc/test-repos") @@ -101,7 +111,7 @@ pkgs.testers.nixosTest { f"curl -sf -X POST http://127.0.0.1:3000/api/v1/projects/{e2e_project_id}/jobsets " f"{auth_header} " "-H 'Content-Type: application/json' " - "-d '{\"name\": \"packages\", \"nix_expression\": \"packages\", \"flake_mode\": true, \"enabled\": true, \"check_interval\": 60}' " + "-d '{\"name\": \"packages\", \"nix_expression\": \"packages\", \"flake_mode\": true, \"enabled\": true, \"check_interval\": 10}' " "| jq -r .id" ) e2e_jobset_id = result.strip() @@ -149,8 +159,8 @@ pkgs.testers.nixosTest { before_count = machine.succeed( f"curl -sf 'http://127.0.0.1:3000/api/v1/evaluations?jobset_id={e2e_jobset_id}' | jq '.items | length'" ).strip() - # Wait a poll cycle - time.sleep(10) + # Wait longer than check_interval (10s) to ensure the evaluator re-checks + time.sleep(15) after_count = machine.succeed( f"curl -sf 'http://127.0.0.1:3000/api/v1/evaluations?jobset_id={e2e_jobset_id}' | jq '.items | length'" ).strip() @@ -361,6 +371,23 @@ pkgs.testers.nixosTest { ).strip() assert result == "failed", f"Expected failed for bad build, got '{result}'" + with subtest("LISTEN/NOTIFY: queue-runner reacts to new builds"): + # Insert a build directly via SQL and verify the queue-runner picks it up + # reactively (within seconds, not waiting for the full poll interval) + machine.succeed( + f"sudo -u fc psql -U fc -d fc -c \"" + "INSERT INTO builds (id, evaluation_id, job_name, drv_path, status, priority, retry_count, max_retries, is_aggregate, signed) " + f"VALUES (gen_random_uuid(), '{e2e_eval_id}', 'notify-build', '/nix/store/invalid-notify-test.drv', 'pending', 0, 0, 1, false, false);\"" + ) + # Queue-runner should pick it up quickly via NOTIFY (poll_interval is 3s in test, + # but LISTEN/NOTIFY wakes it immediately). The build will fail since the drv is + # invalid, but we just need to verify it was picked up (status changed from pending). + machine.wait_until_succeeds( + "curl -sf 'http://127.0.0.1:3000/api/v1/builds?job_name=notify-build' " + "| jq -e '.items[] | select(.status!=\"pending\")'", + timeout=10 + ) + with subtest("Notification run_command invoked on build completion"): # Write a notification script machine.succeed("mkdir -p /var/lib/fc") @@ -375,16 +402,15 @@ pkgs.testers.nixosTest { machine.succeed("chmod +x /var/lib/fc/notify.sh") machine.succeed("chown -R fc:fc /var/lib/fc") - # Update fc.toml to enable notifications + # Enable notifications via systemd drop-in override (adds env var directly to service unit) + machine.succeed("mkdir -p /run/systemd/system/fc-queue-runner.service.d") machine.succeed(""" - cat >> /etc/fc.toml << 'CONFIG' - - [notifications] - run_command = "/var/lib/fc/notify.sh" - CONFIG + cat > /run/systemd/system/fc-queue-runner.service.d/notify.conf << 'EOF' + [Service] + Environment=FC_NOTIFICATIONS__RUN_COMMAND=/var/lib/fc/notify.sh + EOF """) - - # Restart queue-runner to pick up new config + machine.succeed("systemctl daemon-reload") machine.succeed("systemctl restart fc-queue-runner") machine.wait_for_unit("fc-queue-runner.service", timeout=30) @@ -439,17 +465,16 @@ pkgs.testers.nixosTest { machine.succeed("chown -R fc:fc /var/lib/fc/keys") machine.succeed("chmod 600 /var/lib/fc/keys/signing-key") - # Update fc.toml to enable signing + # Enable signing via systemd drop-in override + machine.succeed("mkdir -p /run/systemd/system/fc-queue-runner.service.d") machine.succeed(""" - cat >> /etc/fc.toml << 'CONFIG' - - [signing] - enabled = true - key_file = "/var/lib/fc/keys/signing-key" - CONFIG + cat > /run/systemd/system/fc-queue-runner.service.d/signing.conf << 'EOF' + [Service] + Environment=FC_SIGNING__ENABLED=true + Environment=FC_SIGNING__KEY_FILE=/var/lib/fc/keys/signing-key + EOF """) - - # Restart queue-runner to pick up signing config + machine.succeed("systemctl daemon-reload") machine.succeed("systemctl restart fc-queue-runner") machine.wait_for_unit("fc-queue-runner.service", timeout=30) @@ -503,19 +528,18 @@ pkgs.testers.nixosTest { machine.succeed(f"nix store verify --sigs-needed 1 {output_path}") with subtest("GC roots are created for build products"): - # Enable GC in config + # Enable GC via systemd drop-in override + machine.succeed("mkdir -p /run/systemd/system/fc-queue-runner.service.d") machine.succeed(""" - cat >> /etc/fc.toml << 'CONFIG' - - [gc] - enabled = true - gc_roots_dir = "/nix/var/nix/gcroots/per-user/fc" - max_age_days = 30 - cleanup_interval = 3600 - CONFIG + cat > /run/systemd/system/fc-queue-runner.service.d/gc.conf << 'EOF' + [Service] + Environment=FC_GC__ENABLED=true + Environment=FC_GC__GC_ROOTS_DIR=/nix/var/nix/gcroots/per-user/fc + Environment=FC_GC__MAX_AGE_DAYS=30 + Environment=FC_GC__CLEANUP_INTERVAL=3600 + EOF """) - - # Restart queue-runner to enable GC + machine.succeed("systemctl daemon-reload") machine.succeed("systemctl restart fc-queue-runner") machine.wait_for_unit("fc-queue-runner.service", timeout=30)