I wanted to know how easy it would be to get Spring-Boot auto-reconfiguration to work in OpenShift. It did not really work for me in Cloud Foundry without some massaging ( auto re-config blog ).

The proper way would be to extend https://github.com/spring-projects/spring-cloud/tree/master/spring-cloud-core for OpenShift Which is probably dead simple, too, but I wanted to do a quick 30 minute hack which become about a 90 minutes dirty hack.

In simple terms, the cartridge always sets -Dspring.profiles.active=cloud (unless this is overwritten by the app developer). And when it finds a ‘OPENSHIFT_MYSQL_DB_URL’ environment variable (which means the user added that service (cartridge) to the application, then the cartridge will add a the MariaDB (MySQL) information to ‘VCAP_SERVICES’ In addition I als set ‘VCAP_APPLICATION’ to some partially correct values, as well as VCAP_APP_HOST and VCAP_APP_PORT.

Then I deployed the jar generated from the unfamous-quotes cloud-foundry-autoreconfig-tests branch and it correctly picked up the MySQL DB and SUCCESS.

It was ridiculously easy to get that working in OpenShift. If I hadn’t put in a typo in one of my first attempts it would have been even easier.

What I did not mentioned in the last blog was that the version of the “unfamous quotes” code only works on Cloud Foundry if there is a data source supplied by Cloud Foundry. Otherwise you get:

org.springframework.cloud.CloudException: No unique service matching interface javax.sql.DataSource found. Expected 1, found 0

This happens due to the this code in DataSourceConfiguration:

return connectionFactory().dataSource();    

With the current version of the spring runner cartridge the same happens: You have to add a MariaDB or it wont work.

Since this was just a quick and dirty test, I did not add any other DB services. But I also would rather check out the spring-core-cloud and create an OpenShift Cloud Connector.

I started with the code from https://github.com/spring-guides/gs-accessing-data-jpa.git (complete). I then added a simple HTML/JS UI on top of the Restful API and added validation.

The way Spring Boot works in this set-up is that it automatically creates an in-memory H2 DB and auto-wires everything together. There is basically no code and it works fine and is simple enough. All in an executable Jar with an embedded Tomcat (~29M).

I uploaded that example to different Cloud PaaS providers as well as private PaaS running in a VM and it
either required no or very little effort to run it (except for one where it failed completely … see previous posts).

What surprised me was that Cloud Foundry does not seem to support auto-reconfig for a jar packaged Spring Boot application. When I added a MySQL service and happily expected it to magically work and instead Cloud Foundry continued to start with the H2 DB (relevant git commit).

I tried different set-ups, but in the end I had to add an additional Spring cloud configuration file:

public class DataSourceConfiguration {
    @Configuration()
    public static class CloudConfiguration extends AbstractCloudConfig {
        @Bean(destroyMethod = "close")
        public javax.sql.DataSource dataSource() {
            return connectionFactory().dataSource();
        }
    }
}

And it immediately picked up the MySQL DB Did not create tables, though for that I also had to set spring.jpa.hibernate.ddl-auto=update in the application.property file.

The problem with that approach is that it won’t work locally:

Caused by: org.springframework.cloud.CloudException: No suitable cloud connector found

My thought was that it might just work with using the cloud profile so I changed it

public class DataSourceConfiguration {
    @Configuration()
    @Profile({ "cloud" })
    public static class CloudConfiguration extends AbstractCloudConfig {
        @Bean(destroyMethod = "close")
        public javax.sql.DataSource dataSource() {
            return connectionFactory().dataSource();
        }
    }
}

But that profile is not set by Cloud Foundry. One option could be to set the AbstractCloudConfig profile as default and set a different (e.g. local) profile for local development (see DataSourceConfiguration commit)

This works for this project, but might not for others.

Another option could be to set the cloud profile only when deploying to Cloud Foundry via e.g. JAVA_OPTS (see older posts). Either way can be a awkward for anyone not knowing the chosen path.

I prefer the second option because it means that local development works as expected and the same code behaves exactly the same way in Cloud Foundry (ie using H2 instead of MySQL. (see DataSourceConfiguration commit for cloud profile)

And with a specific manifest.yml file this can be overwritten for Cloud Foundry (though I don’t like having this file as part of the code) so that the active Spring Profile is “cloud”. With this set-up the code uses H2 locally and will use the DB service provided by Cloud Foundry – in my case MySQL – when deployed to Cloud Foundry.