nixos/ssh: use correct executable for grep in ssh-askpass-wrapper (#373746)
[NixPkgs.git] / nixos / modules / services / continuous-integration / jenkins / default.nix
blobc76aac1fa7ded33326ed94ac29cda1778f95fe4d
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
7 let
8   cfg = config.services.jenkins;
9   jenkinsUrl = "http://${cfg.listenAddress}:${toString cfg.port}${cfg.prefix}";
12   options = {
13     services.jenkins = {
14       enable = lib.mkOption {
15         type = lib.types.bool;
16         default = false;
17         description = ''
18           Whether to enable the jenkins continuous integration server.
19         '';
20       };
22       user = lib.mkOption {
23         default = "jenkins";
24         type = lib.types.str;
25         description = ''
26           User the jenkins server should execute under.
27         '';
28       };
30       group = lib.mkOption {
31         default = "jenkins";
32         type = lib.types.str;
33         description = ''
34           If the default user "jenkins" is configured then this is the primary
35           group of that user.
36         '';
37       };
39       extraGroups = lib.mkOption {
40         type = lib.types.listOf lib.types.str;
41         default = [ ];
42         example = [
43           "wheel"
44           "dialout"
45         ];
46         description = ''
47           List of extra groups that the "jenkins" user should be a part of.
48         '';
49       };
51       home = lib.mkOption {
52         default = "/var/lib/jenkins";
53         type = lib.types.path;
54         description = ''
55           The path to use as JENKINS_HOME. If the default user "jenkins" is configured then
56           this is the home of the "jenkins" user.
57         '';
58       };
60       listenAddress = lib.mkOption {
61         default = "0.0.0.0";
62         example = "localhost";
63         type = lib.types.str;
64         description = ''
65           Specifies the bind address on which the jenkins HTTP interface listens.
66           The default is the wildcard address.
67         '';
68       };
70       port = lib.mkOption {
71         default = 8080;
72         type = lib.types.port;
73         description = ''
74           Specifies port number on which the jenkins HTTP interface listens.
75           The default is 8080.
76         '';
77       };
79       prefix = lib.mkOption {
80         default = "";
81         example = "/jenkins";
82         type = lib.types.str;
83         description = ''
84           Specifies a urlPrefix to use with jenkins.
85           If the example /jenkins is given, the jenkins server will be
86           accessible using localhost:8080/jenkins.
87         '';
88       };
90       package = lib.mkPackageOption pkgs "jenkins" { };
92       packages = lib.mkOption {
93         default = [
94           pkgs.stdenv
95           pkgs.git
96           pkgs.jdk17
97           config.programs.ssh.package
98           pkgs.nix
99         ];
100         defaultText = lib.literalExpression "[ pkgs.stdenv pkgs.git pkgs.jdk17 config.programs.ssh.package pkgs.nix ]";
101         type = lib.types.listOf lib.types.package;
102         description = ''
103           Packages to add to PATH for the jenkins process.
104         '';
105       };
107       environment = lib.mkOption {
108         default = { };
109         type = with lib.types; attrsOf str;
110         description = ''
111           Additional environment variables to be passed to the jenkins process.
112           As a base environment, jenkins receives NIX_PATH from
113           {option}`environment.sessionVariables`, NIX_REMOTE is set to
114           "daemon" and JENKINS_HOME is set to the value of
115           {option}`services.jenkins.home`.
116           This option has precedence and can be used to override those
117           mentioned variables.
118         '';
119       };
121       plugins = lib.mkOption {
122         default = null;
123         type = lib.types.nullOr (lib.types.attrsOf lib.types.package);
124         description = ''
125           A set of plugins to activate. Note that this will completely
126           remove and replace any previously installed plugins. If you
127           have manually-installed plugins that you want to keep while
128           using this module, set this option to
129           `null`. You can generate this set with a
130           tool such as `jenkinsPlugins2nix`.
131         '';
132         example = lib.literalExpression ''
133           import path/to/jenkinsPlugins2nix-generated-plugins.nix { inherit (pkgs) fetchurl stdenv; }
134         '';
135       };
137       extraOptions = lib.mkOption {
138         type = lib.types.listOf lib.types.str;
139         default = [ ];
140         example = [ "--debug=9" ];
141         description = ''
142           Additional command line arguments to pass to Jenkins.
143         '';
144       };
146       extraJavaOptions = lib.mkOption {
147         type = lib.types.listOf lib.types.str;
148         default = [ ];
149         example = [ "-Xmx80m" ];
150         description = ''
151           Additional command line arguments to pass to the Java run time (as opposed to Jenkins).
152         '';
153       };
155       withCLI = lib.mkOption {
156         type = lib.types.bool;
157         default = false;
158         description = ''
159           Whether to make the CLI available.
161           More info about the CLI available at
162           [
163           https://www.jenkins.io/doc/book/managing/cli](https://www.jenkins.io/doc/book/managing/cli) .
164         '';
165       };
166     };
167   };
169   config = lib.mkIf cfg.enable {
170     environment = {
171       # server references the dejavu fonts
172       systemPackages = [
173         pkgs.dejavu_fonts
174       ] ++ lib.optional cfg.withCLI cfg.package;
176       variables =
177         { }
178         // lib.optionalAttrs cfg.withCLI {
179           # Make it more convenient to use the `jenkins-cli`.
180           JENKINS_URL = jenkinsUrl;
181         };
182     };
184     users.groups = lib.optionalAttrs (cfg.group == "jenkins") {
185       jenkins.gid = config.ids.gids.jenkins;
186     };
188     users.users = lib.optionalAttrs (cfg.user == "jenkins") {
189       jenkins = {
190         description = "jenkins user";
191         createHome = true;
192         home = cfg.home;
193         group = cfg.group;
194         extraGroups = cfg.extraGroups;
195         useDefaultShell = true;
196         uid = config.ids.uids.jenkins;
197       };
198     };
200     systemd.services.jenkins = {
201       description = "Jenkins Continuous Integration Server";
202       after = [ "network.target" ];
203       wantedBy = [ "multi-user.target" ];
205       environment =
206         let
207           selectedSessionVars = lib.filterAttrs (
208             n: v: builtins.elem n [ "NIX_PATH" ]
209           ) config.environment.sessionVariables;
210         in
211         selectedSessionVars
212         // {
213           JENKINS_HOME = cfg.home;
214           NIX_REMOTE = "daemon";
215         }
216         // cfg.environment;
218       path = cfg.packages;
220       # Force .war (re)extraction, or else we might run stale Jenkins.
222       preStart =
223         let
224           replacePlugins = lib.optionalString (cfg.plugins != null) (
225             let
226               pluginCmds = lib.mapAttrsToList (n: v: "cp ${v} ${cfg.home}/plugins/${n}.jpi") cfg.plugins;
227             in
228             ''
229               rm -r ${cfg.home}/plugins || true
230               mkdir -p ${cfg.home}/plugins
231               ${lib.concatStringsSep "\n" pluginCmds}
232             ''
233           );
234         in
235         ''
236           rm -rf ${cfg.home}/war
237           ${replacePlugins}
238         '';
240       # For reference: https://wiki.jenkins.io/display/JENKINS/JenkinsLinuxStartupScript
241       script = ''
242         ${pkgs.jdk17}/bin/java ${lib.concatStringsSep " " cfg.extraJavaOptions} -jar ${cfg.package}/webapps/jenkins.war --httpListenAddress=${cfg.listenAddress} \
243                                                   --httpPort=${toString cfg.port} \
244                                                   --prefix=${cfg.prefix} \
245                                                   -Djava.awt.headless=true \
246                                                   ${lib.concatStringsSep " " cfg.extraOptions}
247       '';
249       postStart = ''
250         until [[ $(${pkgs.curl.bin}/bin/curl -L -s --head -w '\n%{http_code}' ${jenkinsUrl} | tail -n1) =~ ^(200|403)$ ]]; do
251           sleep 1
252         done
253       '';
255       serviceConfig = {
256         User = cfg.user;
257         StateDirectory = lib.mkIf (lib.hasPrefix "/var/lib/jenkins" cfg.home) "jenkins";
258         # For (possible) socket use
259         RuntimeDirectory = "jenkins";
260       };
261     };
262   };