Friday, August 14, 2009

[updated] CruiseControl: Config

Before following this post you need an SVN server (post here) and a CruiseControl server (post here and here).

1. Create a special account, on the SVN server, for getting the source code from the CC server.

The objective here is to do something similar to what is described at http://svn.collab.net/repos/svn/trunk/notes/ssh-tricks

1.1. [SVN Server] On the SVN server:

1.1.1. Add two new SVN access accounts, but without shell access:

#---
useradd svn-ro
useradd svn-rw
usermod --lock svn-ro
usermod --lock svn-rw
#---


1.1.2. Verify if the SSH daemon is setup to accept public key authentication: /etc/ssh/sshd_config

It must have a line with:

PubkeyAuthentication yes

1.2. [CC Server] On the CC server:

1.2.1. Setup the key pair for the cruise user, to be used to authenticate at the SVN server (see documentation here):

a. Enter an EMPTY passphrase for the ssh key pair:

#---
mkdir ~cruise/.ssh
ssh-keygen -q -f ~cruise/.ssh/id_rsa -t rsa
#---


b. Let the user have access to own keys, but only this user:

#---
chmod -R go-rwx ~cruise/.ssh
chown -R cruise:cruise ~cruise/.ssh
#---


1.2.3. Copy the public key to the SVN server, at the svn-ro user home dir (remember that svn-ro user has no shell access, so do NOT try to transfer the key using the svn-ro account).

#---
scp ~cruise/.ssh/id_rsa.pub <user that HAS shell access in the SVN server>@<SVN server>:
#---


1.3. [SVN Server] Back at the SVN server:

1.3.1. Add the public key to the svn access user's (svn-ro) authorized key ring:

#---
mkdir -p ~svn-ro/.ssh/
mkdir -p ~svn-rw/.ssh/
cat ~<user used to deploy the public key>/id_rsa.pub >> ~svn-ro/.ssh/authorized_keys
cat ~<user used to deploy the public key>/id_rsa.pub >> ~svn-rw/.ssh/authorized_keys
chown -R svn-ro:svn-ro ~svn-ro/.ssh/
chmod -R go-rwx ~svn-ro/.ssh/
chown -R svn-rw:svn-rw ~svn-rw/.ssh/
chmod -R go-rwx ~svn-rw/.ssh/
#---


1.3.2. Edit the authorization key ring file: ~svn-ro/.ssh/authorized_keys AND ~svn-rw/.ssh/authorized_keys

a. It looks like this:

ssh-rsa AAAA<a lot more chars>= root@<CC server name>

b. change it to this:

command="/usr/bin/svnserve -t",no-port-forwarding,no-agent-forwarding,no-X11-forwarding,no-pty ssh-rsa AAAA<a lot more chars>= root@<CC server name>

1.4. [CC Server] Back to the CC server:

1.4.1. Create the necessary directories for the CC:

#---
mkdir -p /var/spool/cruisecontrol/{projects,logs,artifacts}
chown -R cruise:cruise /var/spool/cruisecontrol/
#---

1.4.1. Try to access the SVN server:

#---
su - cruise
svn list svn+ssh://svn-ro@<SVN server>/var/svn/
logout
#---


2. Configuring a project to be managed under the CC policy:

a. Local working copy (for the CruiseControl): /var/spool/cruisecontrol/projects
b. Special SVN repository for the CruiseControl configuration and building ANT scripts: /var/svn/cruisecontrol
c. A special SVN Project (under the /var/svn/trunk) to hold the main build and JUnit ANT scripts, that is called Master here

2.1. [SVN Server] Create the new CC root at the SVN

#---
svn mkdir -m "Initial setup: CruiseControl development tree" file:///var/svn/cruisecontrol
#---


2.4. [Dev Workstation] Create a project, named Main, and commit/import it to svn+ssh://<SVN server>/var/svn/cruisecontrol

Note.: This project must contain at least one file called build-cc.xml.

2.5. [SVN Server] To keep it simple:

#---
su - <A regular dev user>
mkdir Main
cd Main
cat > build-cc.xml << __END__
<project basedir="." default="main" name="Main">
<target name="main">
<echo message="Working"/>
</target>
</project>
__END__
svn import -m "Initial CruiseControl build file" file:///var/svn/cruisecontrol/Main
#---


2.6. [CC Server] Checkout the CC root from the SVN at the local working dir: /var/spool/cruisecontrol/projects

#---
su - cruise
svn checkout svn+ssh://svn-ro@<SVN Server>/var/svn/cruisecontrol/Main projects/Main
logout
#---


2.3. [CC Server] Create a new config.xml

[UPDATE: NOT WORKING PROPERLY] (Thanks to Leif, see comments below).

#---
cat > /etc/cruisecontrol/config.xml << __END__
<cruisecontrol>
<property name="cruise.working.dir" value="/var/spool/cruisecontrol" />
<property name="cruise.log.dir" value="\${cruise.working.dir}/logs" />
<property name="cruise.projects.dir" value="\${cruise.working.dir}/projects" />
<property name="svn.sandbox.username" value="svn-ro" />
<plugin name="basicproject" classname="net.sourceforge.cruisecontrol.ProjectConfig">
<labelincrementer defaultLabel="\${project.name}-1"
separator="-" />
<listeners>
<currentbuildstatuslistener
file="\${cruise.log.dir}/\${project.name}/status.txt" />
</listeners>
<modificationset quietperiod="30">
<svn LocalWorkingCopy="\${cruise.projects.dir}/\${project.name}" />
</modificationset>
<log>
<merge
dir="\${cruise.working.dir}/projects/\${project.name}/target/test-results" />
</log>
<publishers>
<artifactspublisher
file="\${cruise.working.dir}/projects/\${project.name}/target/\${project.name}.jar"
dest="\${cruise.working.dir}/artifacts/\${project.name}" />
</publishers>
</plugin>
<!-- here you can change the project name, if you decided from something else -->
<project name="Main" buildafterfailed="yes"
forceBuildNewProject="yes">
<bootstrappers>
<svnbootstrapper localWorkingCopy="\${cruise.projects.dir}/\${project.name}"
userName="\${svn.sandbox.username}" />
</bootstrappers>
<schedule interval="10">
<ant antWorkingDir="\${cruise.projects.dir}/\${project.name}"
buildfile="build-cc.xml" />
</schedule>
</project>
</cruisecontrol>
__END__
#---


[UPDATE]

2.4. [CC Server] Restart the server and check if it worked by accessing: http://localhost:8080/dashboard/

3. Have fun, configuring the build-cc.xml and organising your repository and code :-)


Related posts:
Subversion and Apache with PAM
CruiseControl on Fedora: Setup
CruiseControl on CentOS: Setup

2 comments:

Leif said...

I see in your config.xml you declare the bits like "publishers" and "log" outside of the "project" section. Does that work for you? I wish it would work for me so that I didn't have to copy/paste those sections into each "project". However I get an error when I try what you did and the docs make it look like it's not possible either?

Gustavo said...

Hi Leif,

You are right. This configuration file is faulty. I guess I didn't paid enough attention to it.

I do not have the fix yet and you are right about the log: it must be project-wise defined.

This post will be reviewed, but in about 3 or 4 weeks. Sorry about that.