nixos/tomcat: add types + proper systemd integration

fixes #35443
This commit is contained in:
Jörg Thalheim 2018-02-24 13:13:53 +00:00
parent 024220bd7f
commit 196e21a160

View File

@ -19,11 +19,7 @@ in
options = { options = {
services.tomcat = { services.tomcat = {
enable = mkEnableOption "Apache Tomcat";
enable = mkOption {
default = false;
description = "Whether to enable Apache Tomcat";
};
package = mkOption { package = mkOption {
type = types.package; type = types.package;
@ -36,23 +32,28 @@ in
}; };
baseDir = mkOption { baseDir = mkOption {
type = lib.types.path;
default = "/var/tomcat"; default = "/var/tomcat";
description = "Location where Tomcat stores configuration files, webapplications and logfiles"; description = "Location where Tomcat stores configuration files, webapplications and logfiles";
}; };
logDirs = mkOption { logDirs = mkOption {
default = []; default = [];
type = types.listOf types.path;
description = "Directories to create in baseDir/logs/"; description = "Directories to create in baseDir/logs/";
}; };
extraConfigFiles = mkOption { extraConfigFiles = mkOption {
default = []; default = [];
type = types.listOf types.path;
description = "Extra configuration files to pull into the tomcat conf directory"; description = "Extra configuration files to pull into the tomcat conf directory";
}; };
environment = mkOption { extraEnvironment = mkOption {
default = ""; type = types.listOf types.str;
description = "File to be sourced before executing tomcat. Can be used to set environment variables"; default = [];
example = [ "ENVIRONMENT=production" ];
description = "Environment Variables to pass to the tomcat service";
}; };
extraGroups = mkOption { extraGroups = mkOption {
@ -62,39 +63,46 @@ in
}; };
user = mkOption { user = mkOption {
type = types.str;
default = "tomcat"; default = "tomcat";
description = "User account under which Apache Tomcat runs."; description = "User account under which Apache Tomcat runs.";
}; };
group = mkOption { group = mkOption {
type = types.str;
default = "tomcat"; default = "tomcat";
description = "Group account under which Apache Tomcat runs."; description = "Group account under which Apache Tomcat runs.";
}; };
javaOpts = mkOption { javaOpts = mkOption {
type = types.either (types.listOf types.str) types.str;
default = ""; default = "";
description = "Parameters to pass to the Java Virtual Machine which spawns Apache Tomcat"; description = "Parameters to pass to the Java Virtual Machine which spawns Apache Tomcat";
}; };
catalinaOpts = mkOption { catalinaOpts = mkOption {
type = types.either (types.listOf types.str) types.str;
default = ""; default = "";
description = "Parameters to pass to the Java Virtual Machine which spawns the Catalina servlet container"; description = "Parameters to pass to the Java Virtual Machine which spawns the Catalina servlet container";
}; };
sharedLibs = mkOption { sharedLibs = mkOption {
type = types.listOf types.str;
default = []; default = [];
description = "List containing JAR files or directories with JAR files which are libraries shared by the web applications"; description = "List containing JAR files or directories with JAR files which are libraries shared by the web applications";
}; };
serverXml = mkOption { serverXml = mkOption {
type = types.lines;
default = ""; default = "";
description = " description = "
Verbatim server.xml configuration. Verbatim server.xml configuration.
This is mutualyl exclusive with the virtualHosts options. This is mutually exclusive with the virtualHosts options.
"; ";
}; };
commonLibs = mkOption { commonLibs = mkOption {
type = types.listOf types.str;
default = []; default = [];
description = "List containing JAR files or directories with JAR files which are libraries shared by the web applications and the servlet container"; description = "List containing JAR files or directories with JAR files which are libraries shared by the web applications and the servlet container";
}; };
@ -107,11 +115,21 @@ in
}; };
virtualHosts = mkOption { virtualHosts = mkOption {
type = types.listOf (types.submodule {
options = {
name = mkOption {
type = types.listOf types.str;
description = "name of the virtualhost";
default = [];
};
};
});
default = []; default = [];
description = "List consisting of a virtual host name and a list of web applications to deploy on each virtual host"; description = "List consisting of a virtual host name and a list of web applications to deploy on each virtual host";
}; };
logPerVirtualHost = mkOption { logPerVirtualHost = mkOption {
type = types.bool;
default = false; default = false;
description = "Whether to enable logging per virtual host."; description = "Whether to enable logging per virtual host.";
}; };
@ -127,11 +145,13 @@ in
enable = mkOption { enable = mkOption {
default = false; default = false;
type = types.bool;
description = "Whether to enable an Apache Axis2 container"; description = "Whether to enable an Apache Axis2 container";
}; };
services = mkOption { services = mkOption {
default = []; default = [];
type = types.listOf types.str;
description = "List containing AAR files or directories with AAR files which are web services to be deployed on Axis2"; description = "List containing AAR files or directories with AAR files which are web services to be deployed on Axis2";
}; };
@ -163,149 +183,104 @@ in
description = "Apache Tomcat server"; description = "Apache Tomcat server";
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
after = [ "network.target" ]; after = [ "network.target" ];
serviceConfig.Type = "oneshot";
serviceConfig.RemainAfterExit = true;
preStart = '' preStart = ''
# Create the base directory # Create the base directory
mkdir -p ${cfg.baseDir} mkdir -p \
${cfg.baseDir}/{conf,virtualhosts,logs,temp,lib,shared/lib,webapps,work}
mkdir -p ${cfg.baseDir} chown ${cfg.user}:${cfg.group} \
${cfg.baseDir}/{conf,virtualhosts,logs,temp,lib,shared/lib,webapps,work}
# Create a symlink to the bin directory of the tomcat component # Create a symlink to the bin directory of the tomcat component
ln -sfn ${tomcat}/bin ${cfg.baseDir}/bin ln -sfn ${tomcat}/bin ${cfg.baseDir}/bin
# Create a conf/ directory
mkdir -p ${cfg.baseDir}/conf
chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/conf
# Symlink the config files in the conf/ directory (except for catalina.properties and server.xml) # Symlink the config files in the conf/ directory (except for catalina.properties and server.xml)
for i in $(ls ${tomcat}/conf | grep -v catalina.properties | grep -v server.xml) for i in $(ls ${tomcat}/conf | grep -v catalina.properties | grep -v server.xml); do
do ln -sfn ${tomcat}/conf/$i ${cfg.baseDir}/conf/`basename $i`
ln -sfn ${tomcat}/conf/$i ${cfg.baseDir}/conf/`basename $i`
done done
${if cfg.extraConfigFiles != [] then '' ${if cfg.extraConfigFiles != [] then ''
for i in ${toString cfg.extraConfigFiles} for i in ${toString cfg.extraConfigFiles}; do
do
ln -sfn $i ${cfg.baseDir}/conf/`basename $i` ln -sfn $i ${cfg.baseDir}/conf/`basename $i`
done done
'' else ""} '' else ""}
# Create subdirectory for virtual hosts
mkdir -p ${cfg.baseDir}/virtualhosts
# Create a modified catalina.properties file # Create a modified catalina.properties file
# Change all references from CATALINA_HOME to CATALINA_BASE and add support for shared libraries # Change all references from CATALINA_HOME to CATALINA_BASE and add support for shared libraries
sed -e 's|''${catalina.home}|''${catalina.base}|g' \ sed -e 's|''${catalina.home}|''${catalina.base}|g' \
-e 's|shared.loader=|shared.loader=''${catalina.base}/shared/lib/*.jar|' \ -e 's|shared.loader=|shared.loader=''${catalina.base}/shared/lib/*.jar|' \
${tomcat}/conf/catalina.properties > ${cfg.baseDir}/conf/catalina.properties ${tomcat}/conf/catalina.properties > ${cfg.baseDir}/conf/catalina.properties
${if cfg.serverXml != "" then '' ${if cfg.serverXml != "" then ''
cat <<'EOF' > ${cfg.baseDir}/conf/server.xml cp -f ${pkgs.writeTextDir "server.xml" cfg.serverXml}/* ${cfg.baseDir}/conf/
${cfg.serverXml}EOF
'' else '' '' else ''
# Create a modified server.xml which also includes all virtual hosts # Create a modified server.xml which also includes all virtual hosts
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)}" \ 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)}" \
${tomcat}/conf/server.xml > ${cfg.baseDir}/conf/server.xml ${tomcat}/conf/server.xml > ${cfg.baseDir}/conf/server.xml
'' ''
} }
# Create a logs/ directory ${optionalString (cfg.logDirs != []) ''
mkdir -p ${cfg.baseDir}/logs for i in ${toString cfg.logDirs}; do
chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/logs mkdir -p ${cfg.baseDir}/logs/$i
${if cfg.logDirs != [] then '' chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/logs/$i
for i in ${toString cfg.logDirs}; do done
mkdir -p ${cfg.baseDir}/logs/$i ''}
chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/logs/$i ${optionalString cfg.logPerVirtualHost (toString (map (h: ''
done mkdir -p ${cfg.baseDir}/logs/${h.name}
'' else ""} chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/logs/${h.name}
${if cfg.logPerVirtualHost then '') cfg.virtualHosts))}
toString (map (h: ''
mkdir -p ${cfg.baseDir}/logs/${h.name}
chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/logs/${h.name}
'') cfg.virtualHosts) else ''''}
# Create a temp/ directory
mkdir -p ${cfg.baseDir}/temp
chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/temp
# Create a lib/ directory
mkdir -p ${cfg.baseDir}/lib
chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/lib
# Create a shared/lib directory
mkdir -p ${cfg.baseDir}/shared/lib
chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/shared/lib
# Create a webapps/ directory
mkdir -p ${cfg.baseDir}/webapps
chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/webapps
# Symlink all the given common libs files or paths into the lib/ directory # Symlink all the given common libs files or paths into the lib/ directory
for i in ${tomcat} ${toString cfg.commonLibs} for i in ${tomcat} ${toString cfg.commonLibs}; do
do if [ -f $i ]; then
if [ -f $i ] # If the given web application is a file, symlink it into the common/lib/ directory
then ln -sfn $i ${cfg.baseDir}/lib/`basename $i`
# If the given web application is a file, symlink it into the common/lib/ directory elif [ -d $i ]; then
ln -sfn $i ${cfg.baseDir}/lib/`basename $i` # If the given web application is a directory, then iterate over the files
elif [ -d $i ] # in the special purpose directories and symlink them into the tomcat tree
then
# If the given web application is a directory, then iterate over the files
# in the special purpose directories and symlink them into the tomcat tree
for j in $i/lib/* for j in $i/lib/*; do
do ln -sfn $j ${cfg.baseDir}/lib/`basename $j`
ln -sfn $j ${cfg.baseDir}/lib/`basename $j` done
done fi
fi
done done
# Symlink all the given shared libs files or paths into the shared/lib/ directory # Symlink all the given shared libs files or paths into the shared/lib/ directory
for i in ${toString cfg.sharedLibs} for i in ${toString cfg.sharedLibs}; do
do if [ -f $i ]; then
if [ -f $i ] # If the given web application is a file, symlink it into the common/lib/ directory
then ln -sfn $i ${cfg.baseDir}/shared/lib/`basename $i`
# If the given web application is a file, symlink it into the common/lib/ directory elif [ -d $i ]; then
ln -sfn $i ${cfg.baseDir}/shared/lib/`basename $i` # If the given web application is a directory, then iterate over the files
elif [ -d $i ] # in the special purpose directories and symlink them into the tomcat tree
then
# If the given web application is a directory, then iterate over the files
# in the special purpose directories and symlink them into the tomcat tree
for j in $i/shared/lib/* for j in $i/shared/lib/*; do
do ln -sfn $j ${cfg.baseDir}/shared/lib/`basename $j`
ln -sfn $j ${cfg.baseDir}/shared/lib/`basename $j` done
done fi
fi
done done
# Symlink all the given web applications files or paths into the webapps/ directory # Symlink all the given web applications files or paths into the webapps/ directory
for i in ${toString cfg.webapps} for i in ${toString cfg.webapps}; do
do if [ -f $i ]; then
if [ -f $i ] # If the given web application is a file, symlink it into the webapps/ directory
then ln -sfn $i ${cfg.baseDir}/webapps/`basename $i`
# If the given web application is a file, symlink it into the webapps/ directory elif [ -d $i ]; then
ln -sfn $i ${cfg.baseDir}/webapps/`basename $i` # If the given web application is a directory, then iterate over the files
elif [ -d $i ] # in the special purpose directories and symlink them into the tomcat tree
then
# If the given web application is a directory, then iterate over the files
# in the special purpose directories and symlink them into the tomcat tree
for j in $i/webapps/* for j in $i/webapps/*; do
do ln -sfn $j ${cfg.baseDir}/webapps/`basename $j`
ln -sfn $j ${cfg.baseDir}/webapps/`basename $j` done
done
# Also symlink the configuration files if they are included # Also symlink the configuration files if they are included
if [ -d $i/conf/Catalina ] if [ -d $i/conf/Catalina ]; then
then for j in $i/conf/Catalina/*; do
for j in $i/conf/Catalina/* mkdir -p ${cfg.baseDir}/conf/Catalina/localhost
do ln -sfn $j ${cfg.baseDir}/conf/Catalina/localhost/`basename $j`
mkdir -p ${cfg.baseDir}/conf/Catalina/localhost done
ln -sfn $j ${cfg.baseDir}/conf/Catalina/localhost/`basename $j`
done
fi
fi fi
fi
done done
${toString (map (virtualHost: '' ${toString (map (virtualHost: ''
@ -317,99 +292,79 @@ in
# Symlink all the given web applications files or paths into the webapps/ directory # Symlink all the given web applications files or paths into the webapps/ directory
# of this virtual host # of this virtual host
for i in "${if virtualHost ? webapps then toString virtualHost.webapps else ""}" for i in "${if virtualHost ? webapps then toString virtualHost.webapps else ""}"; do
do if [ -f $i ]; then
if [ -f $i ] # If the given web application is a file, symlink it into the webapps/ directory
then ln -sfn $i ${cfg.baseDir}/virtualhosts/${virtualHost.name}/webapps/`basename $i`
# If the given web application is a file, symlink it into the webapps/ directory elif [ -d $i ]; then
ln -sfn $i ${cfg.baseDir}/virtualhosts/${virtualHost.name}/webapps/`basename $i` # If the given web application is a directory, then iterate over the files
elif [ -d $i ] # in the special purpose directories and symlink them into the tomcat tree
then
# If the given web application is a directory, then iterate over the files
# in the special purpose directories and symlink them into the tomcat tree
for j in $i/webapps/* for j in $i/webapps/*; do
do ln -sfn $j ${cfg.baseDir}/virtualhosts/${virtualHost.name}/webapps/`basename $j`
ln -sfn $j ${cfg.baseDir}/virtualhosts/${virtualHost.name}/webapps/`basename $j` done
done
# Also symlink the configuration files if they are included # Also symlink the configuration files if they are included
if [ -d $i/conf/Catalina ] if [ -d $i/conf/Catalina ]; then
then for j in $i/conf/Catalina/*; do
for j in $i/conf/Catalina/* mkdir -p ${cfg.baseDir}/conf/Catalina/${virtualHost.name}
do ln -sfn $j ${cfg.baseDir}/conf/Catalina/${virtualHost.name}/`basename $j`
mkdir -p ${cfg.baseDir}/conf/Catalina/${virtualHost.name} done
ln -sfn $j ${cfg.baseDir}/conf/Catalina/${virtualHost.name}/`basename $j`
done
fi
fi fi
fi
done done
'') cfg.virtualHosts)}
'' ${optionalString cfg.axis2.enable ''
) cfg.virtualHosts) } # Copy the Axis2 web application
cp -av ${pkgs.axis2}/webapps/axis2 ${cfg.baseDir}/webapps
# Create a work/ directory # Turn off addressing, which causes many errors
mkdir -p ${cfg.baseDir}/work sed -i -e 's%<module ref="addressing"/>%<!-- <module ref="addressing"/> -->%' ${cfg.baseDir}/webapps/axis2/WEB-INF/conf/axis2.xml
chown ${cfg.user}:${cfg.group} ${cfg.baseDir}/work
${if cfg.axis2.enable then # Modify permissions on the Axis2 application
'' chown -R ${cfg.user}:${cfg.group} ${cfg.baseDir}/webapps/axis2
# Copy the Axis2 web application
cp -av ${pkgs.axis2}/webapps/axis2 ${cfg.baseDir}/webapps
# Turn off addressing, which causes many errors # Symlink all the given web service files or paths into the webapps/axis2/WEB-INF/services directory
sed -i -e 's%<module ref="addressing"/>%<!-- <module ref="addressing"/> -->%' ${cfg.baseDir}/webapps/axis2/WEB-INF/conf/axis2.xml for i in ${toString cfg.axis2.services}; do
if [ -f $i ]; then
# If the given web service is a file, symlink it into the webapps/axis2/WEB-INF/services
ln -sfn $i ${cfg.baseDir}/webapps/axis2/WEB-INF/services/`basename $i`
elif [ -d $i ]; then
# If the given web application is a directory, then iterate over the files
# in the special purpose directories and symlink them into the tomcat tree
# Modify permissions on the Axis2 application for j in $i/webapps/axis2/WEB-INF/services/*; do
chown -R ${cfg.user}:${cfg.group} ${cfg.baseDir}/webapps/axis2 ln -sfn $j ${cfg.baseDir}/webapps/axis2/WEB-INF/services/`basename $j`
done
# Symlink all the given web service files or paths into the webapps/axis2/WEB-INF/services directory # Also symlink the configuration files if they are included
for i in ${toString cfg.axis2.services} if [ -d $i/conf/Catalina ]; then
do for j in $i/conf/Catalina/*; do
if [ -f $i ] ln -sfn $j ${cfg.baseDir}/conf/Catalina/localhost/`basename $j`
then done
# If the given web service is a file, symlink it into the webapps/axis2/WEB-INF/services
ln -sfn $i ${cfg.baseDir}/webapps/axis2/WEB-INF/services/`basename $i`
elif [ -d $i ]
then
# If the given web application is a directory, then iterate over the files
# in the special purpose directories and symlink them into the tomcat tree
for j in $i/webapps/axis2/WEB-INF/services/*
do
ln -sfn $j ${cfg.baseDir}/webapps/axis2/WEB-INF/services/`basename $j`
done
# Also symlink the configuration files if they are included
if [ -d $i/conf/Catalina ]
then
for j in $i/conf/Catalina/*
do
ln -sfn $j ${cfg.baseDir}/conf/Catalina/localhost/`basename $j`
done
fi
fi
done
''
else ""}
'';
script = ''
${if cfg.environment != "" then ''
if [ -r ${cfg.environment} ]; then
. ${cfg.environment}
fi fi
'' else ""} fi
${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' done
''; ''}
preStop = ''
echo "Stopping tomcat..."
CATALINA_BASE=${cfg.baseDir} JAVA_HOME=${cfg.jdk} ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c ${tomcat}/bin/shutdown.sh
''; '';
serviceConfig = {
Type = "forking";
PermissionsStartOnly = true;
PIDFile="/run/tomcat/tomcat.pid";
RuntimeDirectory = "tomcat";
User = cfg.user;
Environment=[
"CATALINA_BASE=${cfg.baseDir}"
"CATALINA_PID=/run/tomcat/tomcat.pid"
"JAVA_HOME='${cfg.jdk}'"
"JAVA_OPTS='${builtins.toString cfg.javaOpts}'"
"CATALINA_OPTS='${builtins.toString cfg.catalinaOpts}'"
] ++ cfg.extraEnvironment;
ExecStart = "${tomcat}/bin/startup.sh";
ExecStop = "${tomcat}/bin/shutdown.sh";
};
}; };
}; };
} }