at master 7.4 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 cfg = config.services.gerrit; 10 11 # NixOS option type for git-like configs 12 gitIniType = 13 let 14 primitiveType = lib.types.either lib.types.str (lib.types.either lib.types.bool lib.types.int); 15 multipleType = lib.types.either primitiveType (lib.types.listOf primitiveType); 16 sectionType = lib.types.lazyAttrsOf multipleType; 17 supersectionType = lib.types.lazyAttrsOf (lib.types.either multipleType sectionType); 18 in 19 lib.types.lazyAttrsOf supersectionType; 20 21 gerritConfig = pkgs.writeText "gerrit.conf" (lib.generators.toGitINI cfg.settings); 22 23 replicationConfig = pkgs.writeText "replication.conf" ( 24 lib.generators.toGitINI cfg.replicationSettings 25 ); 26 27 # Wrap the gerrit java with all the java options so it can be called 28 # like a normal CLI app 29 gerrit-cli = pkgs.writeShellScriptBin "gerrit" '' 30 set -euo pipefail 31 jvmOpts=( 32 ${lib.escapeShellArgs cfg.jvmOpts} 33 -Xmx${cfg.jvmHeapLimit} 34 ) 35 exec ${cfg.jvmPackage}/bin/java \ 36 "''${jvmOpts[@]}" \ 37 -jar ${cfg.package}/webapps/${cfg.package.name}.war \ 38 "$@" 39 ''; 40 41 gerrit-plugins = 42 pkgs.runCommand "gerrit-plugins" 43 { 44 buildInputs = [ gerrit-cli ]; 45 } 46 '' 47 shopt -s nullglob 48 mkdir $out 49 50 for name in ${toString cfg.builtinPlugins}; do 51 echo "Installing builtin plugin $name.jar" 52 gerrit cat plugins/$name.jar > $out/$name.jar 53 done 54 55 for file in ${toString cfg.plugins}; do 56 name=$(echo "$file" | cut -d - -f 2-) 57 echo "Installing plugin $name" 58 ln -sf "$file" $out/$name 59 done 60 ''; 61in 62{ 63 options = { 64 services.gerrit = { 65 enable = lib.mkEnableOption "Gerrit service"; 66 67 package = lib.mkPackageOption pkgs "gerrit" { }; 68 69 jvmPackage = lib.mkPackageOption pkgs "jdk21_headless" { }; 70 71 jvmOpts = lib.mkOption { 72 type = lib.types.listOf lib.types.str; 73 default = [ 74 "-Dflogger.backend_factory=com.google.common.flogger.backend.log4j.Log4jBackendFactory#getInstance" 75 "-Dflogger.logging_context=com.google.gerrit.server.logging.LoggingContext#getInstance" 76 ]; 77 description = "A list of JVM options to start gerrit with."; 78 }; 79 80 jvmHeapLimit = lib.mkOption { 81 type = lib.types.str; 82 default = "1024m"; 83 description = '' 84 How much memory to allocate to the JVM heap 85 ''; 86 }; 87 88 listenAddress = lib.mkOption { 89 type = lib.types.str; 90 default = "[::]:8080"; 91 description = '' 92 `hostname:port` to listen for HTTP traffic. 93 94 This is bound using the systemd socket activation. 95 ''; 96 }; 97 98 settings = lib.mkOption { 99 type = gitIniType; 100 default = { }; 101 description = '' 102 Gerrit configuration. This will be generated to the 103 `etc/gerrit.config` file. 104 ''; 105 }; 106 107 replicationSettings = lib.mkOption { 108 type = gitIniType; 109 default = { }; 110 description = '' 111 Replication configuration. This will be generated to the 112 `etc/replication.config` file. 113 ''; 114 }; 115 116 plugins = lib.mkOption { 117 type = lib.types.listOf lib.types.package; 118 default = [ ]; 119 description = '' 120 List of plugins to add to Gerrit. Each derivation is a jar file 121 itself where the name of the derivation is the name of plugin. 122 ''; 123 }; 124 125 builtinPlugins = lib.mkOption { 126 type = lib.types.listOf (lib.types.enum cfg.package.passthru.plugins); 127 default = [ ]; 128 description = '' 129 List of builtins plugins to install. Those are shipped in the 130 `gerrit.war` file. 131 ''; 132 }; 133 134 serverId = lib.mkOption { 135 type = lib.types.str; 136 description = '' 137 Set a UUID that uniquely identifies the server. 138 139 This can be generated with 140 `nix-shell -p util-linux --run uuidgen`. 141 ''; 142 }; 143 }; 144 }; 145 146 config = lib.mkIf cfg.enable { 147 148 assertions = [ 149 { 150 assertion = cfg.replicationSettings != { } -> lib.elem "replication" cfg.builtinPlugins; 151 message = "Gerrit replicationSettings require enabling the replication plugin"; 152 } 153 ]; 154 155 services.gerrit.settings = { 156 cache.directory = "/var/cache/gerrit"; 157 container.heapLimit = cfg.jvmHeapLimit; 158 gerrit.basePath = lib.mkDefault "git"; 159 gerrit.serverId = cfg.serverId; 160 httpd.inheritChannel = "true"; 161 httpd.listenUrl = lib.mkDefault "http://${cfg.listenAddress}"; 162 index.type = lib.mkDefault "lucene"; 163 }; 164 165 # Add the gerrit CLI to the system to run `gerrit init` and friends. 166 environment.systemPackages = [ gerrit-cli ]; 167 168 systemd.sockets.gerrit = { 169 unitConfig.Description = "Gerrit HTTP socket"; 170 wantedBy = [ "sockets.target" ]; 171 listenStreams = [ cfg.listenAddress ]; 172 }; 173 174 systemd.services.gerrit = { 175 description = "Gerrit"; 176 177 wantedBy = [ "multi-user.target" ]; 178 requires = [ "gerrit.socket" ]; 179 after = [ 180 "gerrit.socket" 181 "network.target" 182 ]; 183 184 path = [ 185 gerrit-cli 186 pkgs.bash 187 pkgs.coreutils 188 pkgs.git 189 pkgs.openssh 190 ]; 191 192 environment = { 193 GERRIT_HOME = "%S/gerrit"; 194 GERRIT_TMP = "%T"; 195 HOME = "%S/gerrit"; 196 XDG_CONFIG_HOME = "%S/gerrit/.config"; 197 }; 198 199 preStart = '' 200 set -euo pipefail 201 202 # bootstrap if nothing exists 203 if [[ ! -d git ]]; then 204 gerrit init --batch --no-auto-start 205 fi 206 207 # install gerrit.war for the plugin manager 208 rm -rf bin 209 mkdir bin 210 ln -sfv ${cfg.package}/webapps/${cfg.package.name}.war bin/gerrit.war 211 212 # copy the config, keep it mutable because Gerrit 213 ln -sfv ${gerritConfig} etc/gerrit.config 214 ln -sfv ${replicationConfig} etc/replication.config 215 216 # install the plugins 217 rm -rf plugins 218 ln -sv ${gerrit-plugins} plugins 219 ''; 220 221 serviceConfig = { 222 CacheDirectory = "gerrit"; 223 DynamicUser = true; 224 ExecStart = "${gerrit-cli}/bin/gerrit daemon --console-log"; 225 LimitNOFILE = 4096; 226 StandardInput = "socket"; 227 StandardOutput = "journal"; 228 StateDirectory = "gerrit"; 229 WorkingDirectory = "%S/gerrit"; 230 AmbientCapabilities = ""; 231 CapabilityBoundingSet = ""; 232 LockPersonality = true; 233 NoNewPrivileges = true; 234 PrivateDevices = true; 235 PrivateTmp = true; 236 ProtectClock = true; 237 ProtectControlGroups = true; 238 ProtectHome = true; 239 ProtectHostname = true; 240 ProtectKernelLogs = true; 241 ProtectKernelModules = true; 242 ProtectKernelTunables = true; 243 ProtectProc = "noaccess"; 244 ProtectSystem = "full"; 245 RestrictAddressFamilies = [ 246 "AF_UNIX" 247 "AF_INET" 248 "AF_INET6" 249 ]; 250 RestrictNamespaces = true; 251 RestrictRealtime = true; 252 RestrictSUIDSGID = true; 253 SystemCallArchitectures = "native"; 254 UMask = 27; 255 }; 256 }; 257 }; 258 259 meta.maintainers = with lib.maintainers; [ 260 edef 261 zimbatm 262 felixsinger 263 ]; 264 # uses attributes of the linked package 265 meta.buildDocsInSandbox = false; 266}