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