The following information, configuration files, and philosophies are an attempt to make CC run in a manner consistent with that of the RedHat and JPackage standards. It is an attempt to follow best practices as viewed by a system administrator. It is specific to getting a solid deployment of CruiseControl withing the RedHat Application Server. The following is a list of these goals.
- CruiseControl must install from RPM.
- Third Party Jars used by CruiseControl must also be installed via RPM.
- For maximum security, standards, and ease, third party Jars should come from the Red Hat Network or JPackage.
- Any Jar unavailable from either RHN or JPackage should be RPM independently.
- CruiseControl should be managed through a System V init script.
- Make these files readily accessible to others.
CruiseControl Version
This documentation supports:
Installing CruiseControl from RPM(s)
Preparing the System
- Subscribe your system to the RHN channels for RHAPS and Extras for all the Java goodies.
Required RPMs
Building source and binary RPM
This section will detail the files and methods which go into building the binary RPM for deployment on a RedHat server.
Files:
Init Script
This is a bit rough but functioning under RHEL4.
NOTE: This init script replaces the cruisecontrol.sh wrapper script. One of my goals was to define all the needed
environmental variables in a single location. Placing classpaths, ANT_HOME, JAVA_HOME, JAVA_LIBS, etc. variables in
relatively hidden locations like ~/.bash_profile is sloppy.
#!/bin/sh
#
# This init script replaces the startup script which comes with
# CruiseControl. It has been packaged with the RedHat RPM.
# Please edit the vars below to taste.
#
# Edit these variables to suit your Cruise Control installation
# chkconfig: 345 99 05
# description: Script used to start and stop the CruiseControl auto-build system
#
# Author: Eugene Eichelberger <geichel@collegenet.com>
#
# Source function library.
if [ -x /etc/rc.d/init.d/functions ]; then
. /etc/rc.d/init.d/functions
fi
#cruisecontrol specific vars:
if [ -z $JAVA_HOME ]; then
JAVA_HOME=/usr/lib/jvm/java-1.4.2-ibm-1.4.2.2
fi
CCNAME=cruisecontrol
CCDIR=/usr/share/$CCNAME
CC_USER=buildmgr
CC_GROUP=users
CCCONFIGDIR=/var/$CCNAME
CCCONFIGFILE=${CCCONFIGDIR}/config.xml
CCLOGFILE=/dev/null
CCPORT=8000
CCBUILDNAME="'CollegeNET Build from BLEND! (automated)'"
LIBDIR=$CCDIR/lib
DISTDIR=$CCDIR/dist
#experimental command which relies on several RHN provided RPM.
# **THIS SHOULD BE ON A SINGLE LINE**
CRUISE_PATH="$JAVA_HOME/lib/tools.jar:
$DISTDIR/cruisecontrol.jar:
/usr/share/java/log4j.jar:
$LIBDIR/jdom.jar:
/usr/share/java/ant.jar:
/usr/share/java/ant-launcher.jar:
$LIBDIR/xercesImpl-2.7.0.jar:
$LIBDIR/xml-apis-2.7.0.jar:
/usr/share/java/xalan-j2.jar:
$LIBDIR/jakarta-oro-2.0.3.jar:
$LIBDIR/mail.jar:
/usr/share/java/junit.jar:
$LIBDIR/activation.jar:
$LIBDIR/commons-net-1.1.0.jar:
$LIBDIR/starteam-sdk.jar:
/usr/share/java/mx4j/mx4j.jar:
/usr/share/java/mx4j/mx4j-tools.jar:
/usr/share/java/mx4j/mx4j-remote.jar:
$LIBDIR/smack.jar:$LIBDIR/comm.jar:
$LIBDIR/x10.jar:$LIBDIR/fast-md5.jar:."
# **THIS SHOULD BE ON A SINGLE LINE**
CCCOMMAND="$JAVA_HOME/bin/java $CC_OPTS
-cp $CRUISE_PATH
-Djavax.management.builder.initial=mx4j.server.MX4JMBeanServerBuilder CruiseControl
-configfile ${CCCONFIGFILE}
-jmxport ${CCPORT}
-ccname $CCBUILDNAME >/dev/null 2>/dev/null </dev/null & disown"
#general init vars
CC_PID=/var/run/$CCNAME.pid
SHUTDOWN_WAIT=30
RETVAL=0
start() {
echo -n "Starting $CCNAME: "
if [ -f /var/lock/subsys/$CCNAME ] ; then
if [ -f /var/run/$CCNAME.pid ]; then
local kpid
read kpid < /var/run/$CCNAME.pid
if checkpid $kpid 2>&1; then
echo "process allready running"
return -1
else
echo "lock file found but no process running for pid $kpid, continuing"
rm -f /var/lock/subsys/$CCNAME /var/run/$CCNAME.pid
fi
fi
fi
touch $CC_PID
chown $CC_USER:$CC_GROUP $CC_PID
#log4j is not configured; change to /var directory and poop there.
su - $CC_USER -c "cd $CCCONFIGDIR ; $CCCOMMAND"
RETVAL=$?
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$CCNAME && ps -Af | grep "$CCNAME" | grep -v grep | cut -f2 -d' '|tail -1 > $CC_PID
[ $RETVAL -eq 0 ] && success || failure
echo
return $RETVAL
}
stop() {
echo -n "Stopping $CCNAME: "
if [ -f /var/lock/subsys/$CCNAME ] ; then
if [ -f /var/run/$CCNAME.pid ]; then
local kpid
read kpid < /var/run/$CCNAME.pid
kill -s 1 $kpid
RETVAL=$?
sleep 2
if [ -z "`ps --pid $kpid | grep -c $kpid`" ]; then
let kwait=$SHUTDOWN_WAIT
until [ `ps --pid $kpid | grep -c $kpid` != '0' ] || [ $count -gt $kwait ]
do
echo "waiting for processes to exit";
sleep 3
let count=$count+1;
done
if [ $count -gt $kwait ]; then
echo "killing processes which didn't stop after $SHUTDOWN_WAIT seconds"
kill -9 $kpid
RETVAL=$?
fi
fi
rm -f /var/lock/subsys/$CCNAME /var/run/$CCNAME.pid
fi
fi
[ -n "`ps -Af | grep $CCNAME | grep -v grep`" ] && success || failure
echo
return $RETVAL
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
condrestart)
if [ -f /var/run/$CCNAME.pid ] ; then
stop
start
fi
;;
*)
echo "Usage: $0 {start|stop|restart|condrestart}"
exit 1
esac
exit $RETVAL
%define name cruisecontrol
%define version 2.4.0
Summary: Automates a CVS checkout and java build loop
Name: %{name}
Version: %{version}
Release: redhat
Copyright: BSD
Group: Development/Tools
Source0: %{name}-src-%{version}.zip
Source1: build.xml
Source2: override.properties
Source3: cruisecontrol.init
Source4: log4j.properties
Patch0: web.xml.patch
BuildRoot: %{_tmppath}/%{name}-buildroot/
Vendor: community
Packager: geichel@collegenet.com
Buildarch: noarch
Requires: java-1.4.2, tomcat5, xalan-j2, xerces-j2
%description
CruiseControl is a framework for a continuous build process. It includes, but is not limited to, plugins
for email notification, Ant, and various source control tools. A web interface is provided to view the
details of the current and previous builds. CruiseControl is distributed under a BSD-style license and
is free for use. http:CruiseControl, a Continuous Integration Toolkit Copyright (c) 2001, ThoughtWorks, Inc. 651 W Washington
Ave. Suite 600 Chicago, IL 60661 USA All rights reserved.
%prep
rm -rf $RPM_BUILD_ROOT
%setup
install %SOURCE1 ..
install %SOURCE2 ..
install %SOURCE4 ./main/
install -d $RPM_BUILD_ROOT/etc/init.d/
install -m 755 %SOURCE3 $RPM_BUILD_ROOT/etc/init.d/cruisecontrol
%patch0
%patch1
%install
#ant is looking for three arguments: name of package, source dir, destination dir
(cd .. && ant -DNAME=%{name} -DBUILD.SRC=%{name}-%{version} -DBUILD.ROOT=$RPM_BUILD_ROOT)
(cd $RPM_BUILD_ROOT && find . -type f | sed 's/^\.install -d $RPM_BUILD_ROOT/var/cruisecontrol/artifacts
install -d $RPM_BUILD_ROOT/var/cruisecontrol/checkout
install -d $RPM_BUILD_ROOT/var/cruisecontrol/logs
%clean
cd ..
rm -rf %{name}-%{version}
rm -f build.xml override.properties web.xml.patch
rm -rf $RPM_BUILD_ROOT
%post
touch /var/lib/tomcat5/shared/lib/[xalan-j2].jar /var/lib/tomcat5/shared/lib/[xerces-j2].jar
%files -f installed_files
%docdir /usr/share/doc/cruisecontrol
%dir /var/cruisecontrol/artifacts
%dir /var/cruisecontrol/checkout
%dir /var/cruisecontrol/logs
%defattr(-, root, root)
%changelog
* Fri Feb 13 2006 Gene Eichelberger <geichel@collegenet.com>
- true src and binary rpm using src from website.
* Fri Feb 10 2006 Gene Eichelberger <geichel@collegenet.com>
- created build.xml for moving to version 2.4.0
* Wed Jan 18 2006 Gene Eichelberger <geichel@collegenet.com>
- initial packaging
<project name="cruisecontrol.rpm" default="install" basedir=".">
<fail message="please specify package name property on the command line" unless="NAME"/>
<fail message="please specify build source dir property on the command line" unless="BUILD.SRC"/>
<fail message="please specify build destination dir property on the command line" unless="BUILD.ROOT"/>
<!-- These are duplicated in the override.properties file (change in both places) -->
<property name="user.spool.root" value="/var/cruisecontrol/"/>
<property name="user.log.dir" value="${user.spool.root}/logs"/>
<property name="user.build.status.file" value="status.txt"/>
<property name="cruise.build.artifacts.dir" value="${user.spool.root}/artifacts"/>
<property name="cruise.checkout.dir" value="${user.spool.root}/checkout"/>
<!-- END override.properties file -->
<property name="reporting.override.file" value="override.properties"/>
<property name="build.rpm.root" value="${BUILD.ROOT}"/>
<property name="config.name" value="${NAME}"/>
<property name="build.spec" value="cruisecontrol.spec"/>
<property name="config.webapp" value="cruisecontrol.war"/>
<property name="cruisecontrol" value="${BUILD.SRC}"/>
<property name="cruisecontrol.main" value="${cruisecontrol}/main"/>
<property name="cruisecontrol.reporting" value="${cruisecontrol}/reporting/jsp"/>
<property name="cruisecontrol.reporting.webapp" value="${cruisecontrol.reporting}/dist/${config.webapp}"/>
<property name="install.docs" value="${build.rpm.root}/usr/share/doc/${config.name}"/>
<property name="install.share" value="${build.rpm.root}/usr/share/${config.name}"/>
<property name="install.bin" value="${install.share}/bin"/>
<property name="install.dist" value="${install.share}/dist"/>
<property name="install.lib" value="${install.share}/lib"/>
<target name="clean" description="deletes old builds and rpms">
<delete failOnError="true" includeEmptyDirs="true" dir="${build.rpm.root}"/>
</target>
<target name="install" depends="build" description="deploy to the build.rpm.root">
<mkdir dir="${install.share}"/>
<mkdir dir="${install.docs}"/>
<copy todir="${install.dist}" file="${cruisecontrol.main}/dist/cruisecontrol.jar"/>
<copy todir="${install.lib}">
<fileset dir="${cruisecontrol.main}/lib"/>
</copy>
<copy todir="${install.docs}">
<fileset dir="${cruisecontrol}/docs"/>
</copy>
<copy todir="${install.docs}/main">
<fileset dir="${cruisecontrol.main}/docs"/>
</copy>
<copy todir="${install.docs}/reporting">
<fileset dir="${cruisecontrol.reporting}/docs"/>
</copy>
<copy todir="${install.bin}">
<fileset file="${cruisecontrol.main}/bin/cruisecontrol.sh"/>
</copy>
<copy todir="${install.share}" file="${cruisecontrol}/license.txt"/>
<copy todir="${install.dist}" file="${cruisecontrol.reporting.webapp}"/>
</target>
<!-- The following targets are the primary cc build steps -->
<target name="build" description="dummy build target" depends="build.main, build.report"/>
<target name="build.main" description="builds cruisecontrol main ">
<ant dir="${cruisecontrol.main}" target="clean" inheritAll="false"/>
<ant dir="${cruisecontrol.main}" target="jar" inheritAll="false"/>
</target>
<target name="build.report" description="builds the cruisecontrol reporting app">
<copy file="${reporting.override.file}" toDir="${cruisecontrol.reporting}"/>
<ant dir="${cruisecontrol.reporting}" target="war" inheritAll="false">
<property name="basedir" value="${cruisecontrol.reporting}"/>
<property name="checkstyle.fail.on.violation" value="false"/>
</ant>
</target>
<!-- END The following targets are the primary cc build steps -->
</project>