treewide: add support for unix sockets

This commit is contained in:
Oystein Kristoffer Tveit 2024-01-13 18:18:21 +01:00
parent a56bfd12fa
commit f2d5ac43b9
Signed by untrusted user: oysteikt
GPG Key ID: 9F2F7D8250F35146
3 changed files with 116 additions and 26 deletions

View File

@ -10,7 +10,9 @@ let
wcfgText = "config.services.matrix-synapse-next.workers"; wcfgText = "config.services.matrix-synapse-next.workers";
format = pkgs.formats.yaml {}; 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 # TODO: Align better with the upstream module
wrapped = cfg.package.override { 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"; enableNginx = mkEnableOption "The synapse module managing nginx";
public_baseurl = mkOption { public_baseurl = mkOption {
@ -135,14 +146,42 @@ in
type = types.listOf (types.submodule { type = types.listOf (types.submodule {
options = { options = {
port = mkOption { port = mkOption {
type = types.port; type = with types; nullOr types.port;
description = "The TCP port to bind to"; 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; 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 { bind_addresses = mkOption {
type = types.listOf types.str; 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 { type = mkOption {
@ -201,16 +240,14 @@ in
# TODO: add defaultText # TODO: add defaultText
default = [ default = [
{ {
port = 8008; path = "${cfg.socketDir}/matrix-synapse.sock";
bind_addresses = [ "127.0.0.1" ];
resources = [ resources = [
{ names = [ "client" ]; compress = true; } { names = [ "client" ]; compress = true; }
{ names = [ "federation" ]; compress = false; } { names = [ "federation" ]; compress = false; }
]; ];
} }
(mkIf (wcfg.instances != { }) { (mkIf (wcfg.instances != { }) {
port = 9093; path = "${cfg.socketDir}/matrix-synapse-replication.sock";
bind_addresses = [ "127.0.0.1" ];
resources = [ resources = [
{ names = [ "replication" ]; } { names = [ "replication" ]; }
]; ];
@ -352,6 +389,12 @@ in
}; };
config = mkIf cfg.enable { 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 = { users.users.matrix-synapse = {
group = "matrix-synapse"; group = "matrix-synapse";
home = cfg.dataDir; home = cfg.dataDir;
@ -396,6 +439,8 @@ in
Group = "matrix-synapse"; Group = "matrix-synapse";
Slice = "system-matrix-synapse.slice"; Slice = "system-matrix-synapse.slice";
WorkingDirectory = cfg.dataDir; WorkingDirectory = cfg.dataDir;
StateDirectory = "matrix-synapse";
RuntimeDirectory = "matrix-synapse";
ExecStart = let ExecStart = let
flags = lib.cli.toGNUCommandLineShell {} { flags = lib.cli.toGNUCommandLineShell {} {
config-path = [ matrix-synapse-common-config ] ++ cfg.extraConfigFiles; config-path = [ matrix-synapse-common-config ] ++ cfg.extraConfigFiles;

View File

@ -40,7 +40,9 @@ let
# Convert listeners to upstream URIs # Convert listeners to upstream URIs
(lib.mapAttrs (_: listeners: lib.pipe listeners [ (lib.mapAttrs (_: listeners: lib.pipe listeners [
(lib.concatMap (listener: (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 (_: { })) (uris: lib.genAttrs uris (_: { }))
])) ]))

View File

@ -86,10 +86,17 @@ in {
}; };
port = mkOption { port = mkOption {
type = types.port; type = with types; nullOr port;
default = null;
description = "The TCP port to bind to"; 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 { bind_addresses = mkOption {
type = with types; listOf str; type = with types; listOf str;
description = "A list of local addresses to listen on"; description = "A list of local addresses to listen on";
@ -161,7 +168,7 @@ in {
}; };
in { in {
mainReplicationHost = mkOption { mainReplicationHost = mkOption {
type = types.str; type = with types; nullOr str;
default = let default = let
host = (matrix-lib.connectionInfo mainReplicationListener).host; host = (matrix-lib.connectionInfo mainReplicationListener).host;
in in
@ -174,18 +181,32 @@ in {
}; };
mainReplicationPort = mkOption { mainReplicationPort = mkOption {
type = types.port; type = with types; nullOr port;
default = mainReplicationListener.port; default = mainReplicationListener.port;
# TODO: add defaultText # TODO: add defaultText
description = "Port for the main synapse instance's replication listener"; 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 { defaultListenerAddress = mkOption {
type = types.str; type = types.str;
default = "127.0.0.1"; default = "127.0.0.1";
description = "The default listener address for the worker"; 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 { workerStartingPort = mkOption {
type = types.port; type = types.port;
description = "What port should the automatically configured workers start enumerating from"; description = "What port should the automatically configured workers start enumerating from";
@ -233,22 +254,32 @@ in {
}; };
config = { 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 = { services.matrix-synapse-next.settings = {
federation_sender_instances = federation_sender_instances =
lib.genList (i: "auto-fed-sender${toString (i + 1)}") wcfg.federationSenders; lib.genList (i: "auto-fed-sender${toString (i + 1)}") wcfg.federationSenders;
instance_map = (lib.mkIf (cfg.workers.instances != { }) ({ instance_map = (lib.mkIf (cfg.workers.instances != { }) ({
main = let main = if wcfg.mainReplicationPath != null then {
host = lib.head mainReplicationListener.bind_addresses; path = wcfg.mainReplicationPath;
in { } else {
host = if builtins.elem host [ "0.0.0.0" "::"] then "127.0.0.1" else host; host = wcfg.mainReplicationHost;
port = mainReplicationListener.port; port = wcfg.mainReplicationPort;
}; };
} // genAttrs' (lib.lists.range 1 wcfg.eventPersisters) } // genAttrs' (lib.lists.range 1 wcfg.eventPersisters)
(i: "auto-event-persist${toString i}") (i: "auto-event-persist${toString i}")
(i: let (i: let
wRL = matrix-lib.firstListenerOfType "replication" wcfg.instances."auto-event-persist${toString i}".settings.worker_listeners; 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 = stream_writers.events =
mkIf (wcfg.eventPersisters > 0) mkIf (wcfg.eventPersisters > 0)
@ -260,10 +291,15 @@ in {
services.matrix-synapse-next.workers.instances = let services.matrix-synapse-next.workers.instances = let
sum = lib.foldl lib.add 0; sum = lib.foldl lib.add 0;
workerListenersWithMetrics = portOffset: workerListenersWithMetrics = portOffset: name:
lib.singleton ({ [(if wcfg.workersUsePath
then {
path = "${cfg.socketDir}/matrix-synapse-worker-${name}.sock";
}
else {
port = wcfg.workerStartingPort + portOffset - 1; port = wcfg.workerStartingPort + portOffset - 1;
}) }
)]
++ lib.optional wcfg.enableMetrics { ++ lib.optional wcfg.enableMetrics {
port = wcfg.metricsStartingPort + portOffset; port = wcfg.metricsStartingPort + portOffset;
resources = [ { names = [ "metrics" ]; } ]; resources = [ { names = [ "metrics" ]; } ];
@ -274,7 +310,7 @@ in {
numberOfWorkers, numberOfWorkers,
portOffset ? 0, portOffset ? 0,
nameFn ? i: "auto-${type}${toString i}", nameFn ? i: "auto-${type}${toString i}",
workerListenerFn ? i: workerListenersWithMetrics (portOffset + i) workerListenerFn ? i: name: workerListenersWithMetrics (portOffset + i) name
}: genAttrs' }: genAttrs'
(lib.lists.range 1 numberOfWorkers) (lib.lists.range 1 numberOfWorkers)
nameFn nameFn
@ -282,7 +318,7 @@ in {
isAuto = true; isAuto = true;
inherit type; inherit type;
index = i; index = i;
settings.worker_listeners = workerListenerFn i; settings.worker_listeners = workerListenerFn i (nameFn i);
}); });
workerInstances = { workerInstances = {
@ -323,8 +359,13 @@ in {
systemd.services = let systemd.services = let
workerList = lib.mapAttrsToList lib.nameValuePair wcfg.instances; workerList = lib.mapAttrsToList lib.nameValuePair wcfg.instances;
workerConfig = worker: format.generate "matrix-synapse-worker-${worker.name}-config.yaml" workerConfig = worker:
(worker.value.settings // { worker_name = worker.name; }); 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: { in builtins.listToAttrs (lib.flip map workerList (worker: {
name = "matrix-synapse-worker-${worker.name}"; name = "matrix-synapse-worker-${worker.name}";
value = { value = {
@ -339,6 +380,8 @@ in {
Group = "matrix-synapse"; Group = "matrix-synapse";
Slice = "system-matrix-synapse.slice"; Slice = "system-matrix-synapse.slice";
WorkingDirectory = cfg.dataDir; WorkingDirectory = cfg.dataDir;
RuntimeDirectory = "matrix-synapse";
StateDirectory = "matrix-synapse";
ExecStartPre = pkgs.writers.writeBash "wait-for-synapse" '' ExecStartPre = pkgs.writers.writeBash "wait-for-synapse" ''
# From https://md.darmstadt.ccc.de/synapse-at-work # From https://md.darmstadt.ccc.de/synapse-at-work
while ! systemctl is-active -q matrix-synapse.service; do while ! systemctl is-active -q matrix-synapse.service; do