{ pkgs, config, lib, ... }: let inherit (lib) mkIf mkMerge; cfg = config.bagel.services.ofborg; amqpHost = "amqp.forkos.org"; amqpPort = 5671; generators = pkgs.formats.json { }; configFile = generators.generate "ofborg-config.json" config.bagel.services.ofborg.settings; mkOfborgWorker = binaryName: extra: extra // { wantedBy = [ "multi-user.target" ]; description = "ofborg CI service - ${binaryName} worker"; after = [ "rabbitmq.service" ]; serviceConfig = { DynamicUser = true; ExecStart = "${cfg.package}/bin/${binaryName} ${configFile}"; # TODO: more hardening. StateDirectory = "ofborg"; LogsDirectory = "ofborg"; WorkingDirectory = "/var/lib/ofborg"; LoadCredential = [ "rabbitmq-password:${config.age.secrets.rabbitmq-password.path}" ]; }; }; in { options.bagel.services.ofborg = with lib; { rabbitmq.enable = mkEnableOption "ofborg AMQP queue"; builder.enable = mkEnableOption "ofborg builder worker"; pastebin.enable = mkEnableOption "ofborg pastebin service"; stats.enable = mkEnableOption "ofborg prometheus worker"; package = mkPackageOption pkgs "ofborg" { }; settings = mkOption { type = generators.type; }; }; config = mkMerge [ { age.secrets.rabbitmq-password.file = ../../secrets/floral/rabbitmq-password.age; # TODO: move this to global. bagel.services.ofborg.settings = { rabbitmq = { ssl = true; host = "amqp.forkos.org"; virtualhost = "amqp.forkos.org"; username = "worker"; password_file = "$CREDENTIALS_DIRECTORY/rabbitmq-password"; }; feedback.full_logs = lib.mkDefault true; log_storage.path = lib.mkDefault "/var/log/ofborg"; runner = { identity = config.networking.fqdn; repos = lib.mkDefault [ "nixpkgs" "ofborg" ]; disable_trusted_users = true; }; checkout.root = lib.mkDefault "/var/lib/ofborg/checkouts"; nix = { system = "x86_64-linux"; remote = "daemon"; build_timeout_seconds = 3600; initial_heap_size = "4g"; }; pastebin = { root = "$STATE_DIRECTORY/pastebins"; db = "$STATE_DIRECTORY/db.json"; }; }; } (mkIf cfg.rabbitmq.enable { services.nginx.enable = true; services.rabbitmq = { enable = true; configItems = { "listeners.tcp" = "none"; "listeners.ssl.default" = builtins.toString amqpPort; "ssl_options.certfile" = "${config.security.acme.certs.${amqpHost}.directory}/cert.pem"; "ssl_options.keyfile" = "${config.security.acme.certs.${amqpHost}.directory}/key.pem"; }; }; security.acme.certs.${amqpHost} = { webroot = "/var/lib/acme/.challenges"; group = "rabbitmq"; }; services.nginx.virtualHosts.${amqpHost}.locations."/.well-known/acme-challenge".root = "/var/lib/acme/.challenges"; systemd.services.rabbitmq.requires = ["acme-finished-${amqpHost}.target"]; networking.firewall.allowedTCPPorts = [ amqpPort ]; }) (mkIf cfg.pastebin.enable { systemd.services.ofborg-pastebin = mkOfborgWorker "pastebin-worker" { }; }) (mkIf cfg.builder.enable { systemd.services.ofborg-builder = mkOfborgWorker "builder" { }; }) (mkIf cfg.stats.enable { systemd.services.ofborg-stats = mkOfborgWorker "stats" { }; }) ]; # systemd.services.ofborg-log-message-collector = {}; # systemd.services.ofborg-evaluation-filter = {}; # systemd.services.ofborg-vcs-comment-filter = {}; # systemd.services.ofborg-vcs-comment-poster = {}; # systemd.services.ofborg-mass-rebuilder = {}; }