From f2d5ac43b9f248f88a2da123906d88ac1ab58ce2 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Sat, 13 Jan 2024 18:18:21 +0100 Subject: [PATCH] treewide: add support for unix sockets --- synapse-module/default.nix | 61 ++++++++++++++++++++++++++---- synapse-module/nginx.nix | 4 +- synapse-module/workers.nix | 77 +++++++++++++++++++++++++++++--------- 3 files changed, 116 insertions(+), 26 deletions(-) diff --git a/synapse-module/default.nix b/synapse-module/default.nix index 45eb879..a523bb0 100644 --- a/synapse-module/default.nix +++ b/synapse-module/default.nix @@ -10,7 +10,9 @@ let wcfgText = "config.services.matrix-synapse-next.workers"; format = pkgs.formats.yaml {}; - matrix-synapse-common-config = format.generate "matrix-synapse-common-config.yaml" cfg.settings; + matrix-synapse-common-config = format.generate "matrix-synapse-common-config.yaml" (cfg.settings // { + listeners = map (lib.filterAttrsRecursive (_: v: v != null)) cfg.settings.listeners; + }); # TODO: Align better with the upstream module wrapped = cfg.package.override { @@ -79,6 +81,15 @@ in ''; }; + socketDir = mkOption { + type = types.path; + default = "/run/matrix-synapse"; + description = '' + The directory where matrix-synapse by default stores the sockets of + all listeners that bind to UNIX sockets. + ''; + }; + enableNginx = mkEnableOption "The synapse module managing nginx"; public_baseurl = mkOption { @@ -135,14 +146,42 @@ in type = types.listOf (types.submodule { options = { port = mkOption { - type = types.port; - description = "The TCP port to bind to"; + type = with types; nullOr types.port; + default = null; + description = '' + The TCP port to bind to. + + ::: {.note} + This option will be ignored if {option}`path` is set to a non-null value. + ::: + ''; example = 8448; }; + path = mkOption { + type = with types; nullOr path; + default = null; + description = '' + The UNIX socket to bind to. + + ::: {.note} + This option will override {option}`bind_addresses` and {option}`port` + if set to a non-null value. + ::: + ''; + example = literalExpression ''''${${cfgText}.socketDir}/matrix-synapse.sock''; + }; + bind_addresses = mkOption { type = types.listOf types.str; - description = "A list of local addresses to listen on"; + default = [ ]; + description = '' + A list of local addresses to listen on. + + ::: {.note} + This option will be ignored if {option}`path` is set to a non-null value. + ::: + ''; }; type = mkOption { @@ -201,16 +240,14 @@ in # TODO: add defaultText default = [ { - port = 8008; - bind_addresses = [ "127.0.0.1" ]; + path = "${cfg.socketDir}/matrix-synapse.sock"; resources = [ { names = [ "client" ]; compress = true; } { names = [ "federation" ]; compress = false; } ]; } (mkIf (wcfg.instances != { }) { - port = 9093; - bind_addresses = [ "127.0.0.1" ]; + path = "${cfg.socketDir}/matrix-synapse-replication.sock"; resources = [ { names = [ "replication" ]; } ]; @@ -352,6 +389,12 @@ in }; config = mkIf cfg.enable { + assertions = [ ] + ++ (map (l: { + assertion = l.path == null -> (l.bind_addresses != [ ] && l.port != null); + message = "Some listeners are missing either a socket path or a bind_address + port to listen on"; + }) cfg.settings.listeners); + users.users.matrix-synapse = { group = "matrix-synapse"; home = cfg.dataDir; @@ -396,6 +439,8 @@ in Group = "matrix-synapse"; Slice = "system-matrix-synapse.slice"; WorkingDirectory = cfg.dataDir; + StateDirectory = "matrix-synapse"; + RuntimeDirectory = "matrix-synapse"; ExecStart = let flags = lib.cli.toGNUCommandLineShell {} { config-path = [ matrix-synapse-common-config ] ++ cfg.extraConfigFiles; diff --git a/synapse-module/nginx.nix b/synapse-module/nginx.nix index 163f76d..53a105a 100644 --- a/synapse-module/nginx.nix +++ b/synapse-module/nginx.nix @@ -40,7 +40,9 @@ let # Convert listeners to upstream URIs (lib.mapAttrs (_: listeners: lib.pipe listeners [ (lib.concatMap (listener: - (map (addr: "${addr}:${toString listener.port}") listener.bind_addresses) + if listener.path != null + then [ "unix:${listener.path}" ] + else (map (addr: "${addr}:${toString listener.port}") listener.bind_addresses) )) (uris: lib.genAttrs uris (_: { })) ])) diff --git a/synapse-module/workers.nix b/synapse-module/workers.nix index 4c5fd2c..ed60628 100644 --- a/synapse-module/workers.nix +++ b/synapse-module/workers.nix @@ -86,10 +86,17 @@ in { }; port = mkOption { - type = types.port; + type = with types; nullOr port; + default = null; description = "The TCP port to bind to"; }; + path = mkOption { + type = with types; nullOr path; + default = null; + description = "The UNIX socket to bind to"; + }; + bind_addresses = mkOption { type = with types; listOf str; description = "A list of local addresses to listen on"; @@ -161,7 +168,7 @@ in { }; in { mainReplicationHost = mkOption { - type = types.str; + type = with types; nullOr str; default = let host = (matrix-lib.connectionInfo mainReplicationListener).host; in @@ -174,18 +181,32 @@ in { }; mainReplicationPort = mkOption { - type = types.port; + type = with types; nullOr port; default = mainReplicationListener.port; # TODO: add defaultText description = "Port for the main synapse instance's replication listener"; }; + mainReplicationPath = mkOption { + type = with types; nullOr path; + default = mainReplicationListener.path; + # TODO: add defaultText + description = "Path to the UNIX socket of the main synapse instance's replication listener"; + }; + defaultListenerAddress = mkOption { type = types.str; default = "127.0.0.1"; description = "The default listener address for the worker"; }; + workersUsePath = mkOption { + type = types.bool; + description = "Whether to enable UNIX sockets for all automatically generated workers"; + default = true; + example = false; + }; + workerStartingPort = mkOption { type = types.port; description = "What port should the automatically configured workers start enumerating from"; @@ -233,22 +254,32 @@ in { }; config = { + assertions = [ ] + ++ (lib.concatMap (worker: + (map (l: { + assertion = l.path == null -> (l.bind_addresses != [ ] && l.port != null); + message = "At least one worker listener is missing either a socket path or a bind_address + port to listen on"; + }) worker.settings.worker_listeners) + ) (lib.attrValues wcfg.instances)); + services.matrix-synapse-next.settings = { federation_sender_instances = lib.genList (i: "auto-fed-sender${toString (i + 1)}") wcfg.federationSenders; instance_map = (lib.mkIf (cfg.workers.instances != { }) ({ - main = let - host = lib.head mainReplicationListener.bind_addresses; - in { - host = if builtins.elem host [ "0.0.0.0" "::"] then "127.0.0.1" else host; - port = mainReplicationListener.port; + main = if wcfg.mainReplicationPath != null then { + path = wcfg.mainReplicationPath; + } else { + host = wcfg.mainReplicationHost; + port = wcfg.mainReplicationPort; }; } // genAttrs' (lib.lists.range 1 wcfg.eventPersisters) (i: "auto-event-persist${toString i}") (i: let wRL = matrix-lib.firstListenerOfType "replication" wcfg.instances."auto-event-persist${toString i}".settings.worker_listeners; - in matrix-lib.connectionInfo wRL))); + in if wRL.path != null then { + inherit (wRL) path; + } else matrix-lib.connectionInfo wRL))); stream_writers.events = mkIf (wcfg.eventPersisters > 0) @@ -260,10 +291,15 @@ in { services.matrix-synapse-next.workers.instances = let sum = lib.foldl lib.add 0; - workerListenersWithMetrics = portOffset: - lib.singleton ({ - port = wcfg.workerStartingPort + portOffset - 1; - }) + workerListenersWithMetrics = portOffset: name: + [(if wcfg.workersUsePath + then { + path = "${cfg.socketDir}/matrix-synapse-worker-${name}.sock"; + } + else { + port = wcfg.workerStartingPort + portOffset - 1; + } + )] ++ lib.optional wcfg.enableMetrics { port = wcfg.metricsStartingPort + portOffset; resources = [ { names = [ "metrics" ]; } ]; @@ -274,7 +310,7 @@ in { numberOfWorkers, portOffset ? 0, nameFn ? i: "auto-${type}${toString i}", - workerListenerFn ? i: workerListenersWithMetrics (portOffset + i) + workerListenerFn ? i: name: workerListenersWithMetrics (portOffset + i) name }: genAttrs' (lib.lists.range 1 numberOfWorkers) nameFn @@ -282,7 +318,7 @@ in { isAuto = true; inherit type; index = i; - settings.worker_listeners = workerListenerFn i; + settings.worker_listeners = workerListenerFn i (nameFn i); }); workerInstances = { @@ -323,8 +359,13 @@ in { systemd.services = let workerList = lib.mapAttrsToList lib.nameValuePair wcfg.instances; - workerConfig = worker: format.generate "matrix-synapse-worker-${worker.name}-config.yaml" - (worker.value.settings // { worker_name = worker.name; }); + workerConfig = worker: + format.generate "matrix-synapse-worker-${worker.name}-config.yaml" + (worker.value.settings // { + worker_name = worker.name; + worker_listeners = + map (lib.filterAttrsRecursive (_: v: v != null)) worker.value.settings.worker_listeners; + }); in builtins.listToAttrs (lib.flip map workerList (worker: { name = "matrix-synapse-worker-${worker.name}"; value = { @@ -339,6 +380,8 @@ in { Group = "matrix-synapse"; Slice = "system-matrix-synapse.slice"; WorkingDirectory = cfg.dataDir; + RuntimeDirectory = "matrix-synapse"; + StateDirectory = "matrix-synapse"; ExecStartPre = pkgs.writers.writeBash "wait-for-synapse" '' # From https://md.darmstadt.ccc.de/synapse-at-work while ! systemctl is-active -q matrix-synapse.service; do