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