nix: avoid sending nixpkgs on non-builder target
[sourcephile-nix.git] / nixos / modules / services / misc / sourcehut / service.nix
index 38bd78a54284acf7a0571751d28bc823d894edad..b3c0efc07ddfd453851acddf78d7cfe3a596dceb 100644 (file)
@@ -13,7 +13,8 @@ srv:
 
 with lib;
 let
-  inherit (config.services) postgresql redis;
+  inherit (config.services) postgresql;
+  redis = config.services.redis.servers."sourcehut-${srvsrht}";
   inherit (config.users) users;
   cfg = config.services.sourcehut;
   configIni = configIniOfService srv;
@@ -23,12 +24,12 @@ let
     rootDir = "/run/sourcehut/chroots/${serviceName}";
     in
     mkMerge [ extraService {
-    after = [ "network.target" ]
-      ++ optional cfg.postgresql.enable "postgresql.service"
-      ++ optional cfg.redis.enable "redis.service";
+    after = [ "network.target" ] ++
+      optional cfg.postgresql.enable "postgresql.service" ++
+      optional cfg.redis.enable "redis-sourcehut-${srvsrht}.service";
     requires =
-         optional cfg.postgresql.enable "postgresql.service"
-      ++ optional cfg.redis.enable "redis.service";
+      optional cfg.postgresql.enable "postgresql.service" ++
+      optional cfg.redis.enable "redis-sourcehut-${srvsrht}.service";
     path = [ pkgs.gawk ];
     environment.HOME = runDir;
     serviceConfig = {
@@ -36,6 +37,8 @@ let
       Group = mkDefault srvCfg.group;
       RuntimeDirectory = [
         "sourcehut/${serviceName}"
+        # Used by *srht-keys which reads ../config.ini
+        "sourcehut/${serviceName}/subdir"
         "sourcehut/chroots/${serviceName}"
       ];
       RuntimeDirectoryMode = "2750";
@@ -61,7 +64,7 @@ let
         "/run/systemd"
         ] ++
         optional cfg.postgresql.enable "/run/postgresql" ++
-        optional cfg.redis.enable "/run/redis";
+        optional cfg.redis.enable "/run/redis-sourcehut-${srvsrht}";
       # LoadCredential= are unfortunately not available in ExecStartPre=
       # Hence this one is run as root (the +) with RootDirectoryStartOnly=
       # to reach credentials wherever they are.
@@ -142,6 +145,20 @@ in
       '';
     };
 
+    redis = {
+      host = mkOption {
+        type = types.str;
+        default = "unix:/run/redis-sourcehut-${srvsrht}/redis.sock?db=0";
+        example = "redis://shared.wireguard:6379/0";
+        description = ''
+          The redis host URL. This is used for caching and temporary storage, and must
+          be shared between nodes (e.g. git1.sr.ht and git2.sr.ht), but need not be
+          shared between services. It may be shared between services, however, with no
+          ill effect, if this better suits your infrastructure.
+        '';
+      };
+    };
+
     postgresql = {
       database = mkOption {
         type = types.str;
@@ -152,6 +169,27 @@ in
         '';
       };
     };
+
+    gunicorn = {
+      extraArgs = mkOption {
+        type = with types; listOf str;
+        default = ["--timeout 120" "--workers 1" "--log-level=info"];
+        description = "Extra arguments passed to Gunicorn.";
+      };
+    };
+  } // optionalAttrs webhooks {
+    webhooks = {
+      extraArgs = mkOption {
+        type = with types; listOf str;
+        default = ["--loglevel DEBUG" "--pool eventlet" "--without-heartbeat"];
+        description = "Extra arguments passed to the Celery responsible for webhooks.";
+      };
+      celeryConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = "Content of the <literal>celeryconfig.py</literal> used by the Celery responsible for webhooks.";
+      };
+    };
   };
 
   config = lib.mkIf (cfg.enable && srvCfg.enable) (mkMerge [ extraConfig {
@@ -168,6 +206,9 @@ in
       } // optionalAttrs (cfg.postgresql.enable
         && hasSuffix "0" (postgresql.settings.unix_socket_permissions or "")) {
         "postgres".members = [ srvCfg.user ];
+      } // optionalAttrs (cfg.redis.enable
+        && hasSuffix "0" (redis.settings.unixsocketperm or "")) {
+        "redis-sourcehut-${srvsrht}".members = [ srvCfg.user ];
       };
     };
 
@@ -187,16 +228,12 @@ in
     services.postgresql = mkIf cfg.postgresql.enable {
       authentication = ''
         local ${srvCfg.postgresql.database} ${srvCfg.user} trust
-      ''
-      # shrt-keys stores SSH keys in the PostgreSQL database of the service calling it
-      + optionalString (elem srv ["builds" "git" "hg"]) ''
-        local ${srvCfg.postgresql.database} ${users."sshsrht".name} trust
       '';
       ensureDatabases = [ srvCfg.postgresql.database ];
       ensureUsers = map (name: {
           inherit name;
           ensurePermissions = { "DATABASE \"${srvCfg.postgresql.database}\"" = "ALL PRIVILEGES"; };
-        }) ([srvCfg.user] ++ optional (elem srv ["builds" "git" "hg"]) users."sshsrht".name);
+        }) [srvCfg.user];
     };
 
     services.sourcehut.services = mkDefault (filter (s: cfg.${s}.enable)
@@ -204,9 +241,7 @@ in
 
     services.sourcehut.settings = mkMerge [
       {
-        "${srv}.sr.ht" = {
-          origin = mkDefault "https://${srv}.${cfg.settings."sr.ht".global-domain}";
-        };
+        "${srv}.sr.ht".origin = mkDefault "https://${srv}.${cfg.settings."sr.ht".global-domain}";
       }
 
       (mkIf cfg.postgresql.enable {
@@ -214,6 +249,19 @@ in
       })
     ];
 
+    services.redis.servers."sourcehut-${srvsrht}" = mkIf cfg.redis.enable {
+      enable = true;
+      databases = 3;
+      syslog = true;
+      # TODO: set a more informed value
+      save = mkDefault [ [1800 10] [300 100] ];
+      settings = {
+        # TODO: set a more informed value
+        maxmemory = "128MB";
+        maxmemory-policy = "volatile-ttl";
+      };
+    };
+
     systemd.services = mkMerge [
       {
         "${srvsrht}" = baseService srvsrht { allowStripe = srv == "meta"; } (mkMerge [
@@ -231,7 +279,7 @@ in
             #RestartSec = mkDefault "2min";
             StateDirectory = [ "sourcehut/${srvsrht}" ];
             StateDirectoryMode = "2750";
-            ExecStart = "${cfg.python}/bin/gunicorn ${srvsrht}.app:app -b ${cfg.listenAddress}:${toString srvCfg.port}";
+            ExecStart = "${cfg.python}/bin/gunicorn ${srvsrht}.app:app --name ${srvsrht} --bind ${cfg.listenAddress}:${toString srvCfg.port} " + concatStringsSep " " srvCfg.gunicorn.extraArgs;
           };
           preStart = let
             version = pkgs.sourcehut.${srvsrht}.version;
@@ -272,16 +320,19 @@ in
         "${srvsrht}-webhooks" = baseService "${srvsrht}-webhooks" {}
           {
             description = "sourcehut ${srv}.sr.ht webhooks service";
-            before = [ "${srvsrht}.service" ];
-            requiredBy = [ "${srvsrht}.service" ];
+            after = [ "${srvsrht}.service" ];
+            wantedBy = [ "${srvsrht}.service" ];
+            partOf = [ "${srvsrht}.service" ];
+            preStart = ''
+              cp ${pkgs.writeText "${srvsrht}-webhooks-celeryconfig.py" srvCfg.webhooks.celeryConfig} \
+                 /run/sourcehut/${srvsrht}-webhooks/celeryconfig.py
+            '';
             serviceConfig = {
               Type = "simple";
               Restart = "always";
-              # --queues enables sharing the Redis database amongst different celery workers
-              ExecStart = "${cfg.python}/bin/celery -A ${srvsrht}.webhooks worker --queues sourcehut.${srvsrht}-webhooks --loglevel INFO --pool eventlet";
+              ExecStart = "${cfg.python}/bin/celery --app ${srvsrht}.webhooks worker --hostname ${srvsrht}-webhooks@%%h " + concatStringsSep " " srvCfg.webhooks.extraArgs;
               # Avoid crashing: os.getloadavg()
               ProcSubset = mkForce "all";
-              InaccessiblePaths = [ "-+/run/postgresql" ];
             };
           };
       })
@@ -303,7 +354,8 @@ in
           description = "sourcehut ${serviceName} service";
           # So that extraServices have the PostgreSQL database initialized.
           after = [ "${srvsrht}.service" ];
-          requiredBy = [ "${srvsrht}.service" ];
+          wantedBy = [ "${srvsrht}.service" ];
+          partOf = [ "${srvsrht}.service" ];
           serviceConfig = {
             Type = "simple";
             Restart = mkDefault "always";