1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.jira; 8 9 pkg = cfg.package.override (optionalAttrs cfg.sso.enable { 10 enableSSO = cfg.sso.enable; 11 }); 12 13 crowdProperties = pkgs.writeText "crowd.properties" '' 14 application.name ${cfg.sso.applicationName} 15 application.password @NIXOS_JIRA_CROWD_SSO_PWD@ 16 application.login.url ${cfg.sso.crowd}/console/ 17 18 crowd.server.url ${cfg.sso.crowd}/services/ 19 crowd.base.url ${cfg.sso.crowd}/ 20 21 session.isauthenticated session.isauthenticated 22 session.tokenkey session.tokenkey 23 session.validationinterval ${toString cfg.sso.validationInterval} 24 session.lastvalidation session.lastvalidation 25 ''; 26 27in 28 29{ 30 options = { 31 services.jira = { 32 enable = mkEnableOption (lib.mdDoc "Atlassian JIRA service"); 33 34 user = mkOption { 35 type = types.str; 36 default = "jira"; 37 description = lib.mdDoc "User which runs JIRA."; 38 }; 39 40 group = mkOption { 41 type = types.str; 42 default = "jira"; 43 description = lib.mdDoc "Group which runs JIRA."; 44 }; 45 46 home = mkOption { 47 type = types.str; 48 default = "/var/lib/jira"; 49 description = lib.mdDoc "Home directory of the JIRA instance."; 50 }; 51 52 listenAddress = mkOption { 53 type = types.str; 54 default = "127.0.0.1"; 55 description = lib.mdDoc "Address to listen on."; 56 }; 57 58 listenPort = mkOption { 59 type = types.port; 60 default = 8091; 61 description = lib.mdDoc "Port to listen on."; 62 }; 63 64 catalinaOptions = mkOption { 65 type = types.listOf types.str; 66 default = []; 67 example = [ "-Xms1024m" "-Xmx2048m" ]; 68 description = lib.mdDoc "Java options to pass to catalina/tomcat."; 69 }; 70 71 proxy = { 72 enable = mkEnableOption (lib.mdDoc "reverse proxy support"); 73 74 name = mkOption { 75 type = types.str; 76 example = "jira.example.com"; 77 description = lib.mdDoc "Virtual hostname at the proxy"; 78 }; 79 80 port = mkOption { 81 type = types.port; 82 default = 443; 83 example = 80; 84 description = lib.mdDoc "Port used at the proxy"; 85 }; 86 87 scheme = mkOption { 88 type = types.str; 89 default = "https"; 90 example = "http"; 91 description = lib.mdDoc "Protocol used at the proxy."; 92 }; 93 94 secure = mkOption { 95 type = types.bool; 96 default = true; 97 description = lib.mdDoc "Whether the connections to the proxy should be considered secure."; 98 }; 99 }; 100 101 sso = { 102 enable = mkEnableOption (lib.mdDoc "SSO with Atlassian Crowd"); 103 104 crowd = mkOption { 105 type = types.str; 106 example = "http://localhost:8095/crowd"; 107 description = lib.mdDoc "Crowd Base URL without trailing slash"; 108 }; 109 110 applicationName = mkOption { 111 type = types.str; 112 example = "jira"; 113 description = lib.mdDoc "Exact name of this JIRA instance in Crowd"; 114 }; 115 116 applicationPasswordFile = mkOption { 117 type = types.str; 118 description = lib.mdDoc "Path to the file containing the application password of this JIRA instance in Crowd"; 119 }; 120 121 validationInterval = mkOption { 122 type = types.int; 123 default = 2; 124 example = 0; 125 description = lib.mdDoc '' 126 Set to 0, if you want authentication checks to occur on each 127 request. Otherwise set to the number of minutes between request 128 to validate if the user is logged in or out of the Crowd SSO 129 server. Setting this value to 1 or higher will increase the 130 performance of Crowd's integration. 131 ''; 132 }; 133 }; 134 135 package = mkOption { 136 type = types.package; 137 default = pkgs.atlassian-jira; 138 defaultText = literalExpression "pkgs.atlassian-jira"; 139 description = lib.mdDoc "Atlassian JIRA package to use."; 140 }; 141 142 jrePackage = mkOption { 143 type = types.package; 144 default = pkgs.oraclejre8; 145 defaultText = literalExpression "pkgs.oraclejre8"; 146 description = lib.mdDoc "Note that Atlassian only support the Oracle JRE (JRASERVER-46152)."; 147 }; 148 }; 149 }; 150 151 config = mkIf cfg.enable { 152 users.users.${cfg.user} = { 153 isSystemUser = true; 154 group = cfg.group; 155 home = cfg.home; 156 }; 157 158 users.groups.${cfg.group} = {}; 159 160 systemd.tmpfiles.rules = [ 161 "d '${cfg.home}' - ${cfg.user} - - -" 162 "d /run/atlassian-jira - - - - -" 163 164 "L+ /run/atlassian-jira/home - - - - ${cfg.home}" 165 "L+ /run/atlassian-jira/logs - - - - ${cfg.home}/logs" 166 "L+ /run/atlassian-jira/work - - - - ${cfg.home}/work" 167 "L+ /run/atlassian-jira/temp - - - - ${cfg.home}/temp" 168 "L+ /run/atlassian-jira/server.xml - - - - ${cfg.home}/server.xml" 169 ]; 170 171 systemd.services.atlassian-jira = { 172 description = "Atlassian JIRA"; 173 174 wantedBy = [ "multi-user.target" ]; 175 requires = [ "postgresql.service" ]; 176 after = [ "postgresql.service" ]; 177 178 path = [ cfg.jrePackage pkgs.bash ]; 179 180 environment = { 181 JIRA_USER = cfg.user; 182 JIRA_HOME = cfg.home; 183 JAVA_HOME = "${cfg.jrePackage}"; 184 CATALINA_OPTS = concatStringsSep " " cfg.catalinaOptions; 185 JAVA_OPTS = mkIf cfg.sso.enable "-Dcrowd.properties=${cfg.home}/crowd.properties"; 186 }; 187 188 preStart = '' 189 mkdir -p ${cfg.home}/{logs,work,temp,deploy} 190 191 sed -e 's,port="8080",port="${toString cfg.listenPort}" address="${cfg.listenAddress}",' \ 192 '' + (lib.optionalString cfg.proxy.enable '' 193 -e 's,protocol="HTTP/1.1",protocol="HTTP/1.1" proxyName="${cfg.proxy.name}" proxyPort="${toString cfg.proxy.port}" scheme="${cfg.proxy.scheme}" secure="${toString cfg.proxy.secure}",' \ 194 '') + '' 195 ${pkg}/conf/server.xml.dist > ${cfg.home}/server.xml 196 197 ${optionalString cfg.sso.enable '' 198 install -m660 ${crowdProperties} ${cfg.home}/crowd.properties 199 ${pkgs.replace-secret}/bin/replace-secret \ 200 '@NIXOS_JIRA_CROWD_SSO_PWD@' \ 201 ${cfg.sso.applicationPasswordFile} \ 202 ${cfg.home}/crowd.properties 203 ''} 204 ''; 205 206 serviceConfig = { 207 User = cfg.user; 208 Group = cfg.group; 209 PrivateTmp = true; 210 Restart = "on-failure"; 211 RestartSec = "10"; 212 ExecStart = "${pkg}/bin/start-jira.sh -fg"; 213 ExecStop = "${pkg}/bin/stop-jira.sh"; 214 }; 215 }; 216 }; 217 218 imports = [ 219 (mkRemovedOptionModule [ "services" "jira" "sso" "applicationPassword" ] '' 220 Use `applicationPasswordFile` instead! 221 '') 222 ]; 223}