How to Deploy a Grails (Tomcat 7) Application to Cloud Foundry

I had an issue with deploying my Grails project to Cloud Foundry using cloudfoundry-grails-plugin. My application was using Tomcat 7, unlike Cloud Foundry, which uses Tomcat 6. In other words, to have a Grails application with Tomcat 7 run, I had to deploy the entire Tomcat 7 directory, but before it, it had to be slightly reconfigured.

Here’s a link with a great tutorial on how to get Tomcat 7 up and running on Cloud Foundry.

After doing those tricky steps, I had to configure MySQL.

Cloud Foundry doesn’t give you information about your available database services. Instead, it has an environment variable named VCAP_SERVICES, which contains all the needed information on how to connect to them from your application. I.e. you have to teach your application how to connect to Cloud Foundry services.

I decided to create a util class which would gather database configuration for me, and append it to DataSource.groovy, here it goes:

class CloudFoundryUtils {
    private static final def log = LogFactory.getLog(CloudFoundryUtils)

    static ConfigObject getDataSource(Map args) {
        final String VCAP_SERVICES = System.getenv('VCAP_SERVICES')

        if (!VCAP_SERVICES) {
            log.error("No environment variable VCAP_SERVICES present!")
              return
        }

        def servicesConfig = JSON.parse(VCAP_SERVICES)
        def mysqlConfig = servicesConfig."${args.type}"
        ConfigObject dataSource = new ConfigObject()
        def mysqlInstance = mysqlConfig.find { it.name == args.service }

        def credentials = mysqlInstance.credentials
        dataSource.username = credentials.username
        dataSource.password = credentials.password
        dataSource.url = "jdbc:mysql://${credentials.host}:${credentials.port}" +
            "/${credentials.name}?autoReconnect=true&useUnicode=true&characterEncoding=utf8"
        dataSource.driverClassName = "com.mysql.jdbc.Driver"
        dataSource.removeAbandoned = true
        dataSource.removeAbandonedTimeout = 300 // 5 minutes
        dataSource.testOnBorrow = true
        dataSource.validationQuery = '/* ping */ SELECT 1'
        log.info("Applied dataSource configuration to DataSource.groovy")
        return dataSource
    }
}

Call to util class from DataSource.groovy:

cf {
  dataSource = CloudFoundryUtils.getDataSource(service: 'mysql-opht', type: 'mysql-5.1')
}

After doing the previous steps, you’re done with configuring, but I’ve also written a script, which packages the war file and copies its content to the tomcat/webapps/ROOT directory. This is optional, as you can ‘war’ your project and extract all packaged files to tomcat/webapps/ROOT manually:

/** ExtractArtefact.groovy (script)
*    run: -Dgrails.env=cf extract-artefact
**/

includeTargets << grailsScript("_GrailsWar")
includeTargets << grailsScript("_GrailsEvents")


target(extract: "Copy war to tomcat directory and deploy to cloudfoundry") {
    depends(war)

    def metadata = grails.util.Metadata.getCurrent()

    event("StatusUpdate", ["Cleaning deployment directory"])
    ant.delete(dir: "${basedir}/tomcat/webapps/ROOT")
    event("StatusUpdate", ["Extracting artefact to deploy directory"])
    def src = "${basedir}/target/${metadata."app.name"}-${metadata."app.version"}.war"
    def dest = "${basedir}/tomcat/webapps/ROOT"
    ant.unwar(src: src, dest: dest)
    event("StatusFinal", ["Successfully deployed to target directory"])
}

setDefaultTarget(extract)

My Tomcat settles in the base directory of the project, but you can change the destination URL to be an absolute path anywhere in your system.

When the script is executed (or you have extracted the content of the war file to the ROOT directory), the last and final step is to execute the “vmc push” command from the tomcat directory.

Hope this would be helpful!

Software Developer