at 18.09-beta 14 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.tomcat; 8 tomcat = cfg.package; 9in 10 11{ 12 13 meta = { 14 maintainers = with maintainers; [ danbst ]; 15 }; 16 17 ###### interface 18 19 options = { 20 21 services.tomcat = { 22 enable = mkEnableOption "Apache Tomcat"; 23 24 package = mkOption { 25 type = types.package; 26 default = pkgs.tomcat85; 27 defaultText = "pkgs.tomcat85"; 28 example = lib.literalExample "pkgs.tomcat9"; 29 description = '' 30 Which tomcat package to use. 31 ''; 32 }; 33 34 baseDir = mkOption { 35 type = lib.types.path; 36 default = "/var/tomcat"; 37 description = "Location where Tomcat stores configuration files, webapplications and logfiles"; 38 }; 39 40 logDirs = mkOption { 41 default = []; 42 type = types.listOf types.path; 43 description = "Directories to create in baseDir/logs/"; 44 }; 45 46 extraConfigFiles = mkOption { 47 default = []; 48 type = types.listOf types.path; 49 description = "Extra configuration files to pull into the tomcat conf directory"; 50 }; 51 52 extraEnvironment = mkOption { 53 type = types.listOf types.str; 54 default = []; 55 example = [ "ENVIRONMENT=production" ]; 56 description = "Environment Variables to pass to the tomcat service"; 57 }; 58 59 extraGroups = mkOption { 60 default = []; 61 example = [ "users" ]; 62 description = "Defines extra groups to which the tomcat user belongs."; 63 }; 64 65 user = mkOption { 66 type = types.str; 67 default = "tomcat"; 68 description = "User account under which Apache Tomcat runs."; 69 }; 70 71 group = mkOption { 72 type = types.str; 73 default = "tomcat"; 74 description = "Group account under which Apache Tomcat runs."; 75 }; 76 77 javaOpts = mkOption { 78 type = types.either (types.listOf types.str) types.str; 79 default = ""; 80 description = "Parameters to pass to the Java Virtual Machine which spawns Apache Tomcat"; 81 }; 82 83 catalinaOpts = mkOption { 84 type = types.either (types.listOf types.str) types.str; 85 default = ""; 86 description = "Parameters to pass to the Java Virtual Machine which spawns the Catalina servlet container"; 87 }; 88 89 sharedLibs = mkOption { 90 type = types.listOf types.str; 91 default = []; 92 description = "List containing JAR files or directories with JAR files which are libraries shared by the web applications"; 93 }; 94 95 serverXml = mkOption { 96 type = types.lines; 97 default = ""; 98 description = " 99 Verbatim server.xml configuration. 100 This is mutually exclusive with the virtualHosts options. 101 "; 102 }; 103 104 commonLibs = mkOption { 105 type = types.listOf types.str; 106 default = []; 107 description = "List containing JAR files or directories with JAR files which are libraries shared by the web applications and the servlet container"; 108 }; 109 110 webapps = mkOption { 111 type = types.listOf types.path; 112 default = [ tomcat.webapps ]; 113 defaultText = "[ pkgs.tomcat85.webapps ]"; 114 description = "List containing WAR files or directories with WAR files which are web applications to be deployed on Tomcat"; 115 }; 116 117 virtualHosts = mkOption { 118 type = types.listOf (types.submodule { 119 options = { 120 name = mkOption { 121 type = types.str; 122 description = "name of the virtualhost"; 123 }; 124 webapps = mkOption { 125 type = types.listOf types.path; 126 description = '' 127 List containing web application WAR files and/or directories containing 128 web applications and configuration files for the virtual host. 129 ''; 130 default = []; 131 }; 132 }; 133 }); 134 default = []; 135 description = "List consisting of a virtual host name and a list of web applications to deploy on each virtual host"; 136 }; 137 138 logPerVirtualHost = mkOption { 139 type = types.bool; 140 default = false; 141 description = "Whether to enable logging per virtual host."; 142 }; 143 144 jdk = mkOption { 145 type = types.package; 146 default = pkgs.jdk; 147 defaultText = "pkgs.jdk"; 148 description = "Which JDK to use."; 149 }; 150 151 axis2 = { 152 153 enable = mkOption { 154 default = false; 155 type = types.bool; 156 description = "Whether to enable an Apache Axis2 container"; 157 }; 158 159 services = mkOption { 160 default = []; 161 type = types.listOf types.str; 162 description = "List containing AAR files or directories with AAR files which are web services to be deployed on Axis2"; 163 }; 164 165 }; 166 167 }; 168 169 }; 170 171 172 ###### implementation 173 174 config = mkIf config.services.tomcat.enable { 175 176 users.groups = singleton 177 { name = "tomcat"; 178 gid = config.ids.gids.tomcat; 179 }; 180 181 users.users = singleton 182 { name = "tomcat"; 183 uid = config.ids.uids.tomcat; 184 description = "Tomcat user"; 185 home = "/homeless-shelter"; 186 extraGroups = cfg.extraGroups; 187 }; 188 189 systemd.services.tomcat = { 190 description = "Apache Tomcat server"; 191 wantedBy = [ "multi-user.target" ]; 192 after = [ "network.target" ]; 193 194 preStart = '' 195 # Create the base directory 196 mkdir -p \ 197 ${cfg.baseDir}/{conf,virtualhosts,logs,temp,lib,shared/lib,webapps,work} 198 chown ${cfg.user}:${cfg.group} \ 199 ${cfg.baseDir}/{conf,virtualhosts,logs,temp,lib,shared/lib,webapps,work} 200 201 # Create a symlink to the bin directory of the tomcat component 202 ln -sfn ${tomcat}/bin ${cfg.baseDir}/bin 203 204 # Symlink the config files in the conf/ directory (except for catalina.properties and server.xml) 205 for i in $(ls ${tomcat}/conf | grep -v catalina.properties | grep -v server.xml); do 206 ln -sfn ${tomcat}/conf/$i ${cfg.baseDir}/conf/`basename $i` 207 done 208 209 ${if cfg.extraConfigFiles != [] then '' 210 for i in ${toString cfg.extraConfigFiles}; do 211 ln -sfn $i ${cfg.baseDir}/conf/`basename $i` 212 done 213 '' else ""} 214 215 # Create a modified catalina.properties file 216 # Change all references from CATALINA_HOME to CATALINA_BASE and add support for shared libraries 217 sed -e 's|''${catalina.home}|''${catalina.base}|g' \ 218 -e 's|shared.loader=|shared.loader=''${catalina.base}/shared/lib/*.jar|' \ 219 ${tomcat}/conf/catalina.properties > ${cfg.baseDir}/conf/catalina.properties 220 221 ${if cfg.serverXml != "" then '' 222 cp -f ${pkgs.writeTextDir "server.xml" cfg.serverXml}/* ${cfg.baseDir}/conf/ 223 '' else '' 224 # Create a modified server.xml which also includes all virtual hosts 225 sed -e "/<Engine name=\"Catalina\" defaultHost=\"localhost\">/a\ ${toString (map (virtualHost: ''<Host name=\"${virtualHost.name}\" appBase=\"virtualhosts/${virtualHost.name}/webapps\" unpackWARs=\"true\" autoDeploy=\"true\" xmlValidation=\"false\" xmlNamespaceAware=\"false\" >${if cfg.logPerVirtualHost then ''<Valve className=\"org.apache.catalina.valves.AccessLogValve\" directory=\"logs/${virtualHost.name}\" prefix=\"${virtualHost.name}_access_log.\" pattern=\"combined\" resolveHosts=\"false\"/>'' else ""}</Host>'') cfg.virtualHosts)}" \ 226 ${tomcat}/conf/server.xml > ${cfg.baseDir}/conf/server.xml 227 '' 228 } 229 ${optionalString (cfg.logDirs != []) '' 230 for i in ${toString cfg.logDirs}; do 231 mkdir -p ${cfg.baseDir}/logs/$i 232 chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/logs/$i 233 done 234 ''} 235 ${optionalString cfg.logPerVirtualHost (toString (map (h: '' 236 mkdir -p ${cfg.baseDir}/logs/${h.name} 237 chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/logs/${h.name} 238 '') cfg.virtualHosts))} 239 240 # Symlink all the given common libs files or paths into the lib/ directory 241 for i in ${tomcat} ${toString cfg.commonLibs}; do 242 if [ -f $i ]; then 243 # If the given web application is a file, symlink it into the common/lib/ directory 244 ln -sfn $i ${cfg.baseDir}/lib/`basename $i` 245 elif [ -d $i ]; then 246 # If the given web application is a directory, then iterate over the files 247 # in the special purpose directories and symlink them into the tomcat tree 248 249 for j in $i/lib/*; do 250 ln -sfn $j ${cfg.baseDir}/lib/`basename $j` 251 done 252 fi 253 done 254 255 # Symlink all the given shared libs files or paths into the shared/lib/ directory 256 for i in ${toString cfg.sharedLibs}; do 257 if [ -f $i ]; then 258 # If the given web application is a file, symlink it into the common/lib/ directory 259 ln -sfn $i ${cfg.baseDir}/shared/lib/`basename $i` 260 elif [ -d $i ]; then 261 # If the given web application is a directory, then iterate over the files 262 # in the special purpose directories and symlink them into the tomcat tree 263 264 for j in $i/shared/lib/*; do 265 ln -sfn $j ${cfg.baseDir}/shared/lib/`basename $j` 266 done 267 fi 268 done 269 270 # Symlink all the given web applications files or paths into the webapps/ directory 271 for i in ${toString cfg.webapps}; do 272 if [ -f $i ]; then 273 # If the given web application is a file, symlink it into the webapps/ directory 274 ln -sfn $i ${cfg.baseDir}/webapps/`basename $i` 275 elif [ -d $i ]; then 276 # If the given web application is a directory, then iterate over the files 277 # in the special purpose directories and symlink them into the tomcat tree 278 279 for j in $i/webapps/*; do 280 ln -sfn $j ${cfg.baseDir}/webapps/`basename $j` 281 done 282 283 # Also symlink the configuration files if they are included 284 if [ -d $i/conf/Catalina ]; then 285 for j in $i/conf/Catalina/*; do 286 mkdir -p ${cfg.baseDir}/conf/Catalina/localhost 287 ln -sfn $j ${cfg.baseDir}/conf/Catalina/localhost/`basename $j` 288 done 289 fi 290 fi 291 done 292 293 ${toString (map (virtualHost: '' 294 # Create webapps directory for the virtual host 295 mkdir -p ${cfg.baseDir}/virtualhosts/${virtualHost.name}/webapps 296 297 # Modify ownership 298 chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/virtualhosts/${virtualHost.name}/webapps 299 300 # Symlink all the given web applications files or paths into the webapps/ directory 301 # of this virtual host 302 for i in "${if virtualHost ? webapps then toString virtualHost.webapps else ""}"; do 303 if [ -f $i ]; then 304 # If the given web application is a file, symlink it into the webapps/ directory 305 ln -sfn $i ${cfg.baseDir}/virtualhosts/${virtualHost.name}/webapps/`basename $i` 306 elif [ -d $i ]; then 307 # If the given web application is a directory, then iterate over the files 308 # in the special purpose directories and symlink them into the tomcat tree 309 310 for j in $i/webapps/*; do 311 ln -sfn $j ${cfg.baseDir}/virtualhosts/${virtualHost.name}/webapps/`basename $j` 312 done 313 314 # Also symlink the configuration files if they are included 315 if [ -d $i/conf/Catalina ]; then 316 for j in $i/conf/Catalina/*; do 317 mkdir -p ${cfg.baseDir}/conf/Catalina/${virtualHost.name} 318 ln -sfn $j ${cfg.baseDir}/conf/Catalina/${virtualHost.name}/`basename $j` 319 done 320 fi 321 fi 322 done 323 '') cfg.virtualHosts)} 324 325 ${optionalString cfg.axis2.enable '' 326 # Copy the Axis2 web application 327 cp -av ${pkgs.axis2}/webapps/axis2 ${cfg.baseDir}/webapps 328 329 # Turn off addressing, which causes many errors 330 sed -i -e 's%<module ref="addressing"/>%<!-- <module ref="addressing"/> -->%' ${cfg.baseDir}/webapps/axis2/WEB-INF/conf/axis2.xml 331 332 # Modify permissions on the Axis2 application 333 chown -R ${cfg.user}:${cfg.group} ${cfg.baseDir}/webapps/axis2 334 335 # Symlink all the given web service files or paths into the webapps/axis2/WEB-INF/services directory 336 for i in ${toString cfg.axis2.services}; do 337 if [ -f $i ]; then 338 # If the given web service is a file, symlink it into the webapps/axis2/WEB-INF/services 339 ln -sfn $i ${cfg.baseDir}/webapps/axis2/WEB-INF/services/`basename $i` 340 elif [ -d $i ]; then 341 # If the given web application is a directory, then iterate over the files 342 # in the special purpose directories and symlink them into the tomcat tree 343 344 for j in $i/webapps/axis2/WEB-INF/services/*; do 345 ln -sfn $j ${cfg.baseDir}/webapps/axis2/WEB-INF/services/`basename $j` 346 done 347 348 # Also symlink the configuration files if they are included 349 if [ -d $i/conf/Catalina ]; then 350 for j in $i/conf/Catalina/*; do 351 ln -sfn $j ${cfg.baseDir}/conf/Catalina/localhost/`basename $j` 352 done 353 fi 354 fi 355 done 356 ''} 357 ''; 358 359 serviceConfig = { 360 Type = "forking"; 361 PermissionsStartOnly = true; 362 PIDFile="/run/tomcat/tomcat.pid"; 363 RuntimeDirectory = "tomcat"; 364 User = cfg.user; 365 Environment=[ 366 "CATALINA_BASE=${cfg.baseDir}" 367 "CATALINA_PID=/run/tomcat/tomcat.pid" 368 "JAVA_HOME='${cfg.jdk}'" 369 "JAVA_OPTS='${builtins.toString cfg.javaOpts}'" 370 "CATALINA_OPTS='${builtins.toString cfg.catalinaOpts}'" 371 ] ++ cfg.extraEnvironment; 372 ExecStart = "${tomcat}/bin/startup.sh"; 373 ExecStop = "${tomcat}/bin/shutdown.sh"; 374 }; 375 }; 376 }; 377}