diff --git a/flake.lock b/flake.lock index 12e491e..937c1ac 100644 --- a/flake.lock +++ b/flake.lock @@ -39,6 +39,22 @@ "type": "github" } }, + "flake-compat_2": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "locked": { "lastModified": 1659877975, @@ -54,6 +70,68 @@ "type": "github" } }, + "hydra": { + "inputs": { + "nix": "nix", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1718119663, + "narHash": "sha256-36+umLoMsx0ZHNcuTNAhmRTw3JoyaIS9vOy9NnKRPhQ=", + "ref": "refs/heads/main", + "rev": "cbe527a3ee6256de0c5bde5b10821f5095b60e22", + "revCount": 4170, + "type": "git", + "url": "https://git.lix.systems/lix-project/hydra.git" + }, + "original": { + "type": "git", + "url": "https://git.lix.systems/lix-project/hydra.git" + } + }, + "nix": { + "inputs": { + "flake-compat": "flake-compat_2", + "nix2container": "nix2container", + "nixpkgs": [ + "hydra", + "nixpkgs" + ], + "nixpkgs-regression": "nixpkgs-regression", + "pre-commit-hooks": "pre-commit-hooks" + }, + "locked": { + "lastModified": 1718081112, + "narHash": "sha256-3cpIVHuyo6yz9n7U/7U/p2Lmwjj1xHdTJR2RkT5JntY=", + "ref": "refs/heads/main", + "rev": "8a3d063a494c4b8c767190a5ce3e4075a75f9d07", + "revCount": 15756, + "type": "git", + "url": "https://git@git.lix.systems/lix-project/lix" + }, + "original": { + "type": "git", + "url": "https://git@git.lix.systems/lix-project/lix" + } + }, + "nix2container": { + "flake": false, + "locked": { + "lastModified": 1712990762, + "narHash": "sha256-hO9W3w7NcnYeX8u8cleHiSpK2YJo7ecarFTUlbybl7k=", + "owner": "nlewo", + "repo": "nix2container", + "rev": "20aad300c925639d5d6cbe30013c8357ce9f2a2e", + "type": "github" + }, + "original": { + "owner": "nlewo", + "repo": "nix2container", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1718870667, @@ -70,9 +148,42 @@ "type": "github" } }, + "nixpkgs-regression": { + "locked": { + "lastModified": 1643052045, + "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", + "type": "github" + } + }, + "pre-commit-hooks": { + "flake": false, + "locked": { + "lastModified": 1712055707, + "narHash": "sha256-4XLvuSIDZJGS17xEwSrNuJLL7UjDYKGJSbK1WWX2AK8=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "e35aed5fda3cc79f88ed7f1795021e559582093a", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, "root": { "inputs": { "colmena": "colmena", + "hydra": "hydra", "nixpkgs": "nixpkgs" } }, diff --git a/flake.nix b/flake.nix index 8884729..a80cea6 100644 --- a/flake.nix +++ b/flake.nix @@ -6,6 +6,9 @@ colmena.url = "github:zhaofengli/colmena"; colmena.inputs.nixpkgs.follows = "nixpkgs"; + + hydra.url = "git+https://git.lix.systems/lix-project/hydra.git"; + hydra.inputs.nixpkgs.follows = "nixpkgs"; }; outputs = { nixpkgs, ... } @ inputs: { @@ -13,8 +16,16 @@ meta.nixpkgs = import nixpkgs { system = "x86_64-linux"; }; + meta.specialArgs.inputs = inputs; + bagel-box = { - imports = [ ./hosts/bagel-box ]; + imports = [ + inputs.hydra.nixosModules.hydra + + ./services + + ./hosts/bagel-box + ]; }; }; }; diff --git a/hosts/bagel-box/default.nix b/hosts/bagel-box/default.nix index 7d3f7e4..ba6de4a 100644 --- a/hosts/bagel-box/default.nix +++ b/hosts/bagel-box/default.nix @@ -34,6 +34,16 @@ firewall.allowPing = true; }; + bagel.services = { + postgres.enable = true; + + hydra.enable = true; + hydra.dbi = "dbi:Pg:dbname=hydra;user=hydra"; + }; + + security.acme.acceptTerms = true; + security.acme.defaults.email = "bagel@delroth.net"; + services.openssh.enable = true; users.users.root.openssh.authorizedKeys.keys = [ # delroth diff --git a/services/default.nix b/services/default.nix new file mode 100644 index 0000000..a2de4bf --- /dev/null +++ b/services/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./hydra + ./postgres + ]; +} diff --git a/services/hydra/default.nix b/services/hydra/default.nix new file mode 100644 index 0000000..e98f6cc --- /dev/null +++ b/services/hydra/default.nix @@ -0,0 +1,109 @@ +{ config, lib, ... }: + +let + cfg = config.bagel.services.hydra; + + narCacheDir = "/var/cache/hydra/nar-cache"; + port = 3000; + + mkCacheSettings = settings: builtins.concatStringsSep "&" ( + lib.mapAttrsToList (k: v: "${k}=${v}") settings + ); +in { + options.bagel.services.hydra = with lib; { + enable = mkEnableOption "Hydra coordinator"; + + dbi = mkOption { + type = types.str; + description = "DBI connection string for the Hydra postgres database"; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d /var/cache/hydra 0755 hydra hydra - -" + "d ${narCacheDir} 0755 hydra hydra 1d -" + ]; + + # XXX: Otherwise services.hydra-dev overwrites it to only hydra-queue-runner... + # + # Can be removed once this is added to some common config template. + nix.settings.trusted-users = [ "root" "@wheel" ]; + + services.hydra-dev = { + enable = true; + + listenHost = "localhost"; + port = port; + dbi = cfg.dbi; + + hydraURL = "https://hydra.bagel.delroth.net"; + useSubstitutes = false; + + notificationSender = "bagel@delroth.net"; + + extraConfig = '' + store_uri = s3://bagel-cache?${mkCacheSettings { + endpoint = "s3.delroth.net"; + region = "garage"; + + secret-key = "TODO"; + + compression = "zstd"; + log-compression = "br"; + ls-compression = "br"; + + write-nar-listing = "1"; + }} + + server_store_uri = https://bagel-cache.s3-web.delroth.net?local-nar-cache=${narCacheDir} + binary_cache_public_url = https://bagel-cache.s3-web.delroth.net + log_prefix = https://bagel-cache.s3-web.delroth.net + + upload_logs_to_binary_cache = true + + evaluator_workers = 4 + evaluator_max_memory_size = 4096 + max_concurrent_evals = 1 + + allow_import_from_derivation = false + + max_output_size = ${builtins.toString (3 * 1024 * 1024 * 1024)} + max_db_connections = 100 + ''; + }; + + services.nginx = { + enable = true; + enableReload = true; + + recommendedBrotliSettings = true; + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + recommendedZstdSettings = true; + + proxyTimeout = "900s"; + + appendConfig = '' + worker_processes auto; + ''; + + virtualHosts."hydra.bagel.delroth.net" = { + forceSSL = true; + enableACME = true; + + locations."/" = { + proxyPass = "http://127.0.0.1:${builtins.toString port}"; + }; + + locations."/static/" = { + alias = "${config.services.hydra-dev.package}/libexec/hydra/root/static/"; + }; + }; + }; + + networking.firewall.allowedTCPPorts = [ 80 443 ]; + }; +} diff --git a/services/postgres/default.nix b/services/postgres/default.nix new file mode 100644 index 0000000..4f5985f --- /dev/null +++ b/services/postgres/default.nix @@ -0,0 +1,48 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.bagel.services.postgres; + + dataDir = "/var/db/postgresql/16"; +in { + options.bagel.services.postgres = with lib; { + enable = mkEnableOption "PostgreSQL server"; + }; + + config = lib.mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d /var/db 0755 root root - -" + "d /var/db/postgresql 0770 postgres postgres - -" + "d ${dataDir} 0770 postgres postgres - -" + ]; + + services.postgresql = { + enable = true; + package = pkgs.postgresql_16; + dataDir = dataDir; + + # TODO: Where to put this to properly couple things? It doesn't belong + # here, but using it in services/hydra would require running on + # localhost. Probably needs to be replaced with some different way of + # ensuring the DB/user exist. + ensureDatabases = [ "hydra" ]; + ensureUsers = [ + { + name = "hydra"; + ensureDBOwnership = true; + } + ]; + identMap = '' + hydra-users hydra hydra + hydra-users hydra-queue-runner hydra + hydra-users hydra-www hydra + hydra-users root hydra + # The postgres user is used to create the pg_trgm extension for the hydra database + hydra-users postgres postgres + ''; + authentication = '' + local hydra all ident map=hydra-users + ''; + }; + }; +}