1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7let
8 inherit (pkgs) glusterfs rsync;
9
10 tlsCmd =
11 if (cfg.tlsSettings != null) then
12 ''
13 mkdir -p /var/lib/glusterd
14 touch /var/lib/glusterd/secure-access
15 ''
16 else
17 ''
18 rm -f /var/lib/glusterd/secure-access
19 '';
20
21 restartTriggers = lib.optionals (cfg.tlsSettings != null) [
22 config.environment.etc."ssl/glusterfs.pem".source
23 config.environment.etc."ssl/glusterfs.key".source
24 config.environment.etc."ssl/glusterfs.ca".source
25 ];
26
27 cfg = config.services.glusterfs;
28
29in
30
31{
32
33 ###### interface
34
35 options = {
36
37 services.glusterfs = {
38
39 enable = lib.mkEnableOption "GlusterFS Daemon";
40
41 logLevel = lib.mkOption {
42 type = lib.types.enum [
43 "DEBUG"
44 "INFO"
45 "WARNING"
46 "ERROR"
47 "CRITICAL"
48 "TRACE"
49 "NONE"
50 ];
51 description = "Log level used by the GlusterFS daemon";
52 default = "INFO";
53 };
54
55 useRpcbind = lib.mkOption {
56 type = lib.types.bool;
57 description = ''
58 Enable use of rpcbind. This is required for Gluster's NFS functionality.
59
60 You may want to turn it off to reduce the attack surface for DDoS reflection attacks.
61
62 See <https://davelozier.com/glusterfs-and-rpcbind-portmap-ddos-reflection-attacks/>
63 and <https://bugzilla.redhat.com/show_bug.cgi?id=1426842> for details.
64 '';
65 default = true;
66 };
67
68 enableGlustereventsd = lib.mkOption {
69 type = lib.types.bool;
70 description = "Whether to enable the GlusterFS Events Daemon";
71 default = true;
72 };
73
74 killMode = lib.mkOption {
75 type = lib.types.enum [
76 "control-group"
77 "process"
78 "mixed"
79 "none"
80 ];
81 description = ''
82 The systemd KillMode to use for glusterd.
83
84 glusterd spawns other daemons like gsyncd.
85 If you want these to stop when glusterd is stopped (e.g. to ensure
86 that NixOS config changes are reflected even for these sub-daemons),
87 set this to 'control-group'.
88 If however you want running volume processes (glusterfsd) and thus
89 gluster mounts not be interrupted when glusterd is restarted
90 (for example, when you want to restart them manually at a later time),
91 set this to 'process'.
92 '';
93 default = "control-group";
94 };
95
96 stopKillTimeout = lib.mkOption {
97 type = lib.types.str;
98 description = ''
99 The systemd TimeoutStopSec to use.
100
101 After this time after having been asked to shut down, glusterd
102 (and depending on the killMode setting also its child processes)
103 are killed by systemd.
104
105 The default is set low because GlusterFS (as of 3.10) is known to
106 not tell its children (like gsyncd) to terminate at all.
107 '';
108 default = "5s";
109 };
110
111 extraFlags = lib.mkOption {
112 type = lib.types.listOf lib.types.str;
113 description = "Extra flags passed to the GlusterFS daemon";
114 default = [ ];
115 };
116
117 tlsSettings = lib.mkOption {
118 description = ''
119 Make the server communicate via TLS.
120 This means it will only connect to other gluster
121 servers having certificates signed by the same CA.
122
123 Enabling this will create a file {file}`/var/lib/glusterd/secure-access`.
124 Disabling will delete this file again.
125
126 See also: <https://gluster.readthedocs.io/en/latest/Administrator%20Guide/SSL/>
127 '';
128 default = null;
129 type = lib.types.nullOr (
130 lib.types.submodule {
131 options = {
132 tlsKeyPath = lib.mkOption {
133 type = lib.types.str;
134 description = "Path to the private key used for TLS.";
135 };
136
137 tlsPem = lib.mkOption {
138 type = lib.types.path;
139 description = "Path to the certificate used for TLS.";
140 };
141
142 caCert = lib.mkOption {
143 type = lib.types.path;
144 description = "Path certificate authority used to sign the cluster certificates.";
145 };
146 };
147 }
148 );
149 };
150 };
151 };
152
153 ###### implementation
154
155 config = lib.mkIf cfg.enable {
156 environment.systemPackages = [ pkgs.glusterfs ];
157
158 services.rpcbind.enable = cfg.useRpcbind;
159
160 environment.etc = lib.mkIf (cfg.tlsSettings != null) {
161 "ssl/glusterfs.pem".source = cfg.tlsSettings.tlsPem;
162 "ssl/glusterfs.key".source = cfg.tlsSettings.tlsKeyPath;
163 "ssl/glusterfs.ca".source = cfg.tlsSettings.caCert;
164 };
165
166 systemd.services.glusterd = {
167 inherit restartTriggers;
168
169 description = "GlusterFS, a clustered file-system server";
170
171 wantedBy = [ "multi-user.target" ];
172
173 requires = lib.optional cfg.useRpcbind "rpcbind.service";
174 after = [ "network.target" ] ++ lib.optional cfg.useRpcbind "rpcbind.service";
175
176 preStart =
177 ''
178 install -m 0755 -d /var/log/glusterfs
179 ''
180 # The copying of hooks is due to upstream bug https://bugzilla.redhat.com/show_bug.cgi?id=1452761
181 # Excludes one hook due to missing SELinux binaries.
182 + ''
183 mkdir -p /var/lib/glusterd/hooks/
184 ${rsync}/bin/rsync -a --exclude="S10selinux-label-brick.sh" ${glusterfs}/var/lib/glusterd/hooks/ /var/lib/glusterd/hooks/
185
186 ${tlsCmd}
187 ''
188 # `glusterfind` needs dirs that upstream installs at `make install` phase
189 # https://github.com/gluster/glusterfs/blob/v3.10.2/tools/glusterfind/Makefile.am#L16-L17
190 + ''
191 mkdir -p /var/lib/glusterd/glusterfind/.keys
192 mkdir -p /var/lib/glusterd/hooks/1/delete/post/
193 '';
194
195 serviceConfig = {
196 LimitNOFILE = 65536;
197 ExecStart = "${glusterfs}/sbin/glusterd --no-daemon --log-level=${cfg.logLevel} ${toString cfg.extraFlags}";
198 KillMode = cfg.killMode;
199 TimeoutStopSec = cfg.stopKillTimeout;
200 };
201 };
202
203 systemd.services.glustereventsd = lib.mkIf cfg.enableGlustereventsd {
204 inherit restartTriggers;
205
206 description = "Gluster Events Notifier";
207
208 wantedBy = [ "multi-user.target" ];
209
210 after = [ "network.target" ];
211
212 preStart = ''
213 install -m 0755 -d /var/log/glusterfs
214 '';
215
216 # glustereventsd uses the `gluster` executable
217 path = [ glusterfs ];
218
219 serviceConfig = {
220 Type = "simple";
221 PIDFile = "/run/glustereventsd.pid";
222 ExecStart = "${glusterfs}/sbin/glustereventsd --pid-file /run/glustereventsd.pid";
223 ExecReload = "/bin/kill -SIGUSR2 $MAINPID";
224 KillMode = "control-group";
225 };
226 };
227 };
228}