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