Java buildpack - Adding new services for auto reconfiguration

153 views
Skip to first unread message

garyfr...@gmail.com

unread,
Nov 13, 2014, 11:45:02 AM11/13/14
to vcap...@cloudfoundry.org
OK, we have a new service data source - similar in its role to Redis and Mongo with different characteristics...   I'm trying to figure out how to get a Spring app that uses this service to be "auto-reconfigured" when doing a cf push of that app....       Following through the buildpack logic eventually gets me to CloudAutoReconfigurationApplicationContextInitializer which has the following section...

private void addAutoReconfiguration(ConfigurableApplicationContext applicationContext) {

        addBeanFactoryPostProcessor(applicationContext,

                new DataSourceCloudServiceBeanFactoryPostProcessor(applicationContext, this.cloudUtils));

        addBeanFactoryPostProcessor(applicationContext,

                new MongoCloudServiceBeanFactoryPostProcessor(applicationContext, this.cloudUtils));

        addBeanFactoryPostProcessor(applicationContext,

                new RabbitCloudServiceBeanFactoryPostProcessor(applicationContext, this.cloudUtils));

        addBeanFactoryPostProcessor(applicationContext,

                new RedisCloudServiceBeanFactoryPostProcessor(applicationContext, this.cloudUtils));

    }


And I do understand what those BeanFactoryPostProcessors do - eventually found that code...      

The question is - do I have to change this file (fork the buildpack) to add my service for auto-reconfiguration OR is there another way to have my own BeanFactoryPostProcessor in the classpath of the app and get it picked up ?    I guess I could put something specifically into my .jars that adds the PostProcessor, but that seems odd to do it that way when the buildpack has a consistent way of doing this for the "known" services.     Couldnt the buildpack find these in some way in the classpath rather than hardcoding them??

Thanks for any suggestions

- Gary

Ken Krueger

unread,
Nov 13, 2014, 3:34:10 PM11/13/14
to vcap...@cloudfoundry.org
Hi Gary,

Forking the buildpack as you've described will achieve what you want.  I'll let Ben and others comment on if there is a more elegant way to allow these BFPPs to be auto detected somehow.

I'm curious about the use case though.  Obviously you can use normal service binding rather than using auto configuration at all.  (Some folks really dislike the auto-configuration and disable it.)  For an individual app forking is mega-overkill.  So my mind has been racing as to what you are really up to.  

(forgive me for being nosey, I always hate when people answer my post with "why do you want to do that?")

thx
k

--
You received this message because you are subscribed to the Google Groups "Cloud Foundry Developers" group.
To view this discussion on the web visit https://groups.google.com/a/cloudfoundry.org/d/msgid/vcap-dev/7029214b-f0c0-4d46-8d7c-3b3cf23f2a78%40cloudfoundry.org.

To unsubscribe from this group and stop receiving emails from it, send an email to vcap-dev+u...@cloudfoundry.org.



--
Ken Krueger  
Manager, Global Education Delivery
407 256 9737 Mobile
kenkrueger65 Skype

Education questions?  educ...@pivotal.io

garyfr...@gmail.com

unread,
Nov 13, 2014, 11:43:16 PM11/13/14
to vcap...@cloudfoundry.org
I'd rather not fork the buildpack, that could get messy the 2nd time someone needs to do this or when there is interest in doing this with a set of services in different combinations..

So, yes, it's perfectly OK if someone wants to do manual configuration - just seems to me that there shouldnt be anything different or special about particular services - somewhat of a disadvantage if we want uptake of our service (the less the friction the better).    Remember that this isnt aimed at an individual app, but as a service that will be eventually a larger Content Mgmt platform with multiple relevant new services - that developers can build arbitrary apps against.

But this service is really provided to the app primarily through Spring Data - the developer really shouldnt have to worry about how it gets bound into their app - just as they dont worry about that necessarily with Mongo or Redis.

So, for someone who just writes a nice Spring app locally with our service for testing and debugging, it should be simple to just do a cf push and have it run - again for the same reason that this is done for Mongo & Redis...   Why should those inherently be special/different?

Hope that provides a somewhat coherent explanation

- Gary

Guillaume Berche

unread,
Nov 14, 2014, 11:29:37 AM11/14/14
to vcap...@cloudfoundry.org, garyfr...@gmail.com
Is the spring cloud connector with the generic service support matching your need, ie the app spring context would have something like:

<cloud:service id="email" service-name="email-service" connector-type="com.something.EmailConnectory/>

and the app may leverage/customize the cloudfoundry connector to extract the proper information from VCAP_SERVICES to instanciate the bean of your new type (beyond the builtin mongo, redis, rabbit)

More at https://github.com/spring-cloud/spring-cloud-connectors/tree/master/spring-cloud-spring-service-connector#connecting-to-generic-services-1

Guillaume.

Scott Frederick

unread,
Nov 19, 2014, 9:54:42 AM11/19/14
to vcap...@cloudfoundry.org, garyfr...@gmail.com
The dependency path for auto-reconfiguration involves the Java Buildpack, which depends on the auto-reconfig support library to pull in the bean post-processors, which depends on Spring Cloud Connectors for service discovery and credentials parsing. Adding support for auto-reconfig of a new service type will require modifications to all three, so it would be more involved than just forking the buildpack. 

This auto-reconfig was implemented to maintain compatibility with Cloud Foundry v1, which only supported a limited number of services. Java was the only language that supported auto-reconfig in v1, and the only language to support it in v2. All other languages rely on libraries included in the app to configure services. I don't think expanding Java auto-reconfig to include any type of service is the right way to go. It would be better to put the application in control of service wiring so you don't have to worry about this dependency chain that leads back to the buildpack. 

Spring Cloud Connectors (SCC) includes a @ServiceScan annotation for Java config and a <cloud:service-scan> element for XML config. Using one of these in a Spring app will cause SCC to create a bean for each bound service, which can then be wired into the application. This works for any type of bean that SCC supports, so you would only need to extend SCC without forking anything else to get your new services supported. Creating two @Configuration beans (or the XML equivalent) like the ones below - one containing the local configuration of service beans and the other just triggering the @ServiceScan - will effectively do the same thing as auto-reconfiguration. 

    @Configuration
  @Profiles("default")
  class LocalConfig {
    // configure beans for local access
  }

    @Configuration
  @ServiceScan
  @Profiles("cloud")
  class CloudConfig {
  }

You can read more about using Spring Cloud Connectors, including @ServiceScan, and also about extending SCC to support additional services, in this presentation from SpringOne: http://www.slideshare.net/ramnivas2/spring-one2014-springcloudconnector.

Scott

garyfr...@gmail.com

unread,
Nov 19, 2014, 11:45:42 AM11/19/14
to vcap...@cloudfoundry.org, garyfr...@gmail.com
Yes, I am aware (and am using) the ability to have different service beans for different profiles...  And I'm OK if the decision is to not extend auto-reconfig (i.e. it is vestigial).    IF auto-reconfig is intended to persist as anything other than compatibility, then it should be set up to handle other kinds of services - which was really the point I was trying to make...      

The point was to avoid the developer of an app worrying about creating multiple configs - even using @ServiceScan.   But again, I'm OK if the decision is that way is the intended one and just telling app developers that they need to do it.... 

- Gary

Scott Frederick

unread,
Nov 19, 2014, 7:58:57 PM11/19/14
to vcap...@cloudfoundry.org, garyfr...@gmail.com
Let me expand on this thinking a bit. 

CF service providers can publish any number of services to their marketplace. Especially for on-prem CF deployments, the services that are provided might be either of a proprietary nature or not very commonly used in the community. Spring Cloud Connectors was designed with this in mind. SCC connectors for new types of services can be developed in SCC extension projects that are kept separate from the main SCC project - separate source code repos and separate published jar files. So proprietary things can be kept private and less-commonly used things can be kept out of the core to prevent bloat. 

If the auto-reconfig support library could be made made smart enough to auto-configure any type of service connector that SCC knows about (I'm not sure how that would work to start with), people would still need to customize auto-reconfig to pull in any SCC extension jar files that aren't part of the core. So you'd need to fork that project, and then you'd need to fork the Java buildpack to pull in the custom auto-reconfig support lib. 

Using @ServiceScan and Spring bean profiles requires more code and configuration in the app, but @ServiceScan automatically works for any service connectors in the SCC core and any extension jar found on the classpath. So the SCC scanning approach scales much better than the auto-reconfig approach. 

Scott
Reply all
Reply to author
Forward
0 new messages