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