Automatic deployment for Tomcat Applications

I like continuous deployment just like continuous integration. However it can be pain if you have too many environments to deploy to.

In the project that I am currently involved in, we have 3 environments for which continuous deployment makes sense. Deployment frequency is different, deployment policies are different but I am sure it is possible to automatize the deployment process up to some extend.

Just for that reason (and also because I am bored of doing deployment and I like writing scripts time to time), I spent a couple of hours to write a script that can be invoked by cron to do deployment to tomcat. The process is easy;

  • Scripts checks all the war files under a specific folder
    • For every war file under in that directory
    • Checks if the war file is complete
    • If so stops tomcat (only for once:) )
    • Removes all the files related to the current war file from tomcat/webapps
    • Copies war file to tomcat/webapps
  • Starts tomcat

The full script is as follows. I am not a experienced bash coder, so be fair. Now all you have to do is to transfer the file to inbound directory. There are different ways for different build management tools. I am using maven so I defined an ant-run goal to copy the deployables via ssh.

#!/bin/sh

SCRIPT_USER="dev"
TOMCAT_DIR="/appdata/apps/wcm"
WAIT=10
TOMCAT_STOPPED=0

log_deployment()
{
    ssh [email protected] 'echo "Deployment was started at `date`" > /appdata/apache2/htdocs/deploy.txt'
}

start_tomcat()
{
    if [ $TOMCAT_STOPPED -eq 1 ];
    then
        log "Starting tomcat"
        $TOMCAT_DIR/bin/startup.sh
        log_deployment
    fi
}

# stops tomcat
stop_tomcat()
{
    if [ $TOMCAT_STOPPED -eq 0 ];
    then
        log "Stopping tomcat"
        $TOMCAT_DIR/bin/shutdown.sh
        sleep $WAIT
        log "Making sure it is stopped by killing(-9) any process contains java and tomcat in their run command"
        kill -9 `ps ux | awk '/java/ && /tomcat/ && !/awk/ {print $2}'`
        TOMCAT_STOPPED=1
    fi
}

# prepares deployable for deployment
prepare_for_deploy()
{
    log "Going to make deployment for $1, file size is stable"
    log "Moving deployable $1 to processed directory"
    BASE_NAME="`basename $1`"
    BASE_NAME=${BASE_NAME:0:${#BASE_NAME}-4}
    log "Cleaning tomcat webapps directory for $BASE_NAME"
    rm -rf $TOMCAT_DIR/webapps/$BASE_NAME*
    log "Moving $1 to tomcat webapps directory"
    mv $1 $TOMCAT_DIR/webapps/.
}

# logs a message with date
log()
{
    echo "`date` >> $1"
}

# logs an error with date
error()
{
    echo "`date` >> $1" 1>&2
}

if [ $USER != $SCRIPT_USER ]; then
  error "You must run this script as user '$SCRIPT_USER'!"
  exit 1
fi

log "Checking inbound for deployables"

cd `dirname $0`
mkdir -p inbound

if [ -z `ls inbound/*.war` ];
then
  log "No deployables found"
  exit 0
fi

for f in inbound/*.war;
do
    LAST_ACCESS=$(stat -c%Y "$f")
    NOW=$(date +%s)
    let DIFF=$NOW-$LAST_ACCESS

    log "$f is accessed $DIFF seconds ago."

    SIZE1=$(stat -c%s "$f")
    sleep $WAIT
    SIZE2=$(stat -c%s "$f")
    if [ "$SIZE1" -eq "$SIZE2" ]
    then
        stop_tomcat
        prepare_for_deploy $f
    else
        log "File is still being copied"
    fi
done

start_tomcat