Monday, 26 April 2010

Automating project setup and environment configuration

Share
Build automation is something very obvious, nowadays all projects have repository + build tool + automated scheduled builds. It's not a best practice it's a common practice.

And what about automating project setup and environment configuration?

Imagine a new member joining your team or upgrading/migrating your application to a different machine (or a client machine). Is everything contained in your project's wiki? I don't think so. Wiki pages tend to be outdated. In fact they are up to date only when project starts :).

Many times there are some hidden truths that are obvious to some members of your team while they are a mystery to others (and for sure to new members).

Have you ever though about automating project setup and environment configuration?

Today I post some ideas which I have successfully implemented in my PhD system and many projects in which I was involved during my work as a Software Engineer.

These ideas are all about Java related technologies, but I'm sure the same things can be achieved using other enterprise-grade platforms (e.g., .NET).

Automated project setup

With Maven2 I have created different profiles for development, internal, and production environments. The profiles manage database, ESB, OS, and host-specific settings. The development profile can be changed individually for every developer. When a new developer downloads source code from the repository he or she should change all settings in just one file! This can be achieved by using Maven profiles and filtering, I wrote about it some time ago: Maven profiles, filters, resources, and final artefact name.

Automated environment configuration - bash script and cygwin

Every enterprise application server comes with something like a console or a command line tool which may be used for administration, installing libraries, etc.

In my PhD system I use Apache Geronimo. I wrote a simple bash script for checking libraries in Geronimo's repository and installing missing ones. The installation script was written in bash.

Why bash? Because under Windows I'm using Cygwin. Thanks to this I can have only one installation script for both Windows and Linux. I just added 1 if in my script:

#!/bin/sh
LIB_DIR="`pwd`/libs"
if [ -z "$GERONIMO_HOME" ] ; then
 echo "\$GERONIMO_HOME not set, aborting..."
 exit 1
fi
if [ -z "$1" -o -z "$2" ] ; then
 echo -e "Administrator credentials not set. Username and password must be passed as command line arguments, for example:\n"
 echo -e "\t$0 system manager"
 exit 1
fi
cygwin=false
os400=false
case "`uname`" in
 CYGWIN*) cygwin=true;;
 OS400*) os400=true;;
esac
while read inputline
do
 groupId="$(echo $inputline | cut -d \  -f1)"
 artefactId="$(echo $inputline | cut -d \  -f2)"
 version="$(echo $inputline | cut -d \  -f3)"
 type="$(echo $inputline | cut -d \  -f4)"
 file="$LIB_DIR/$artefactId-$version.$type"
 repoFile=`echo $groupId | sed s/"\."/"\/"/g`
 repoFile=$GERONIMO_HOME/repository/$repoFile/$artefactId/$version/$artefactId-$version.$type
 if $cygwin; then
    file=`cygpath --windows "$file"`
    repoFile=`cygpath --windows "$repoFile"`
 fi
 if [ -e $repoFile ] ; then
  echo "library $file already deployed to $GERONIMO_HOME"
  continue
 fi
 $GERONIMO_HOME/bin/deploy.sh -u $1 -p $2 install-library --groupId $groupId $file
done < libs_index.txt
# special endorsed libraries
cp $LIB_DIR/xerces-2.9.1.jar $GERONIMO_HOME/lib/endorsed
$GERONIMO_HOME/bin/deploy.sh -u $1 -p $2 stop welcome-tomcat
# Linux geronimo.sh
sed '2 i export JAVA_OPTS="-server -Xms128M -Xmx2048M -XX:MaxPermSize=256M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled -Xverify:none -XX:+AggressiveOpts"' < $GERONIMO_HOME/bin/geronimo.sh > $GERONIMO_HOME/bin/tmp_geronimo
mv $GERONIMO_HOME/bin/tmp_geronimo $GERONIMO_HOME/bin/geronimo.sh
# Windows geronimo.bat
sed '1 i set JAVA_OPTS=-server -Xms128M -Xmx2048M -XX:MaxPermSize=256M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled -Xverify:none -XX:+AggressiveOpts' < $GERONIMO_HOME/bin/geronimo.bat > $GERONIMO_HOME/bin/tmp_geronimo
mv $GERONIMO_HOME/bin/tmp_geronimo $GERONIMO_HOME/bin/geronimo.bat
exit 0

Automated environment configuration - simple tasks and Ant

And what if you are using a simple web container, like we use in my current company? The solution we chose is even more portable, we wrote Ant tasks which copy libraries to specific Tomcat's lib directory. And that's all Tomcat needs.

Starting servers automatically

This might not be crucial for development machines, but is crucial for internal, demo, and production environments.

On Windows machines you can use Windows Services. That is not a problem. On Linux you can use update-rc.d tool. It allows you to add init scripts which adheres to the following convention:
  • if invoked with param start - starts given server/service
  • if invoked with param stop - stops given server/service
  • if invoked with param restart - restarts given server/service
Here are two examples of such scripts for Apache Geronimo:

#!/bin/sh
. /lib/lsb/init-functions
startcmd () {
 /opt/geronimo-tomcat6-javaee5-2.1.3/bin/geronimo.sh start
}
stopcmd () {
    /opt/geronimo-tomcat6-javaee5-2.1.3/bin/geronimo.sh stop --user xyz --password abc
}
case "$1" in
start)  log_daemon_msg "Starting Apache Geronimo"
        startcmd
        log_end_msg $?
        ;;
stop)   log_daemon_msg "Stopping Apache Geronimo"
        stopcmd
        log_end_msg $?
        ;;
restart) log_daemon_msg "Restarting Apache Geronimo"
        stopcmd
        startcmd
        log_end_msg $?
        ;;
*)      log_action_msg "Usage: $0 {start|stop|restart}"
        exit 2
        ;;
esac
exit 0
and IBM DB2:
#!/bin/sh
. /lib/lsb/init-functions
startcmd () {
 su -c '/home/db2inst1/sqllib/adm/db2start' db2inst1
}
stopcmd () {
    su -c '/home/db2inst1/sqllib/adm/db2stop force' db2inst1
}
case "$1" in
start)  log_daemon_msg "Starting IBM DB2"
        startcmd
        log_end_msg $?
        ;;
stop)   log_daemon_msg "Stopping IBM DB2"
        stopcmd
        log_end_msg $?
        ;;
restart) log_daemon_msg "Restarting IBM DB2"
        stopcmd
        startcmd
        log_end_msg $?
        ;;
*)      log_action_msg "Usage: $0 {start|stop|restart}"
        exit 2
        ;;
esac
exit 0

They can be added to initial scripts by executing update-rc.d tool:

update-rc.d tomcat.sh defaults
update-rc.d db2.sh defaults

Summary

That would be all.

I guess there are many other ways you can make your life easier with automating project setup and environment configuration. Hope these tips will help you.

Cheers,
Łukasz

4 comments:

Tomasz Dziurko said...

There is small error on the page:
"SyntaxHighlighter Can't find brush for: bash"
As far as I know syntax highlighter doesn't support bash. But you can try adding this:
http://bboy.mr.freeze.googlepages.com/shBrushBash.js

Łukasz said...

Cześć Tomek,

SyntaxHighlighter supports Bash (vide: http://alexgorbatchev.com/wiki/SyntaxHighlighter:Brushes:Bash). I simply forgot to add brush for it :)

thanks for spotting it,
Łukasz

Eric Rich said...

Have you tried Maven and Cargo? We use Maven, JUnit, Cargo, Cactus, and Selenium for our tests.

Being able to start/start containers and deploy the webapp automatically is very convenient.

Łukasz said...

Hi Eric,

You're right I could have written more about integration-tests.

So, for completeness I add some more links here :)

Of course I used Cargo, I even wrote a post about it: http://jee-bpel-soa.blogspot.com/search/label/cargo. But in my projects I'm using Maven2 Jetty plugin (I had some problems with Cargo and pre-deploying external WARs).

I also wrote about Selenium here: http://jee-bpel-soa.blogspot.com/search/label/selenium.

I have a series of posts about testing - see label http://jee-bpel-soa.blogspot.com/search/label/testing.

If you click label http://jee-bpel-soa.blogspot.com/search/label/maven, we will find lots of examples of failsafe, etc.

thanks,
Lukasz