Entity view (Content)

Centralized configuration management for Mule applications

By jacek
Jun. 7, 2017

Using property placeholders is one of the recommended practices for writing Mule ESB applications. Thanks to that all environment specific configuration or sensitive values can be defined outside Mule’s flow configuration XML, what allows to deploy exactly the same binary Mule application file on lower environments, like development or test, and later to be promoted to production.

How property placeholders work?

Mule ESB delivers two standard components for resolving property placeholders:

  • context:property-placeholder - standard spring-based property source
  • secure-property-placeholder:config - Mule specific property placeholder resolver with built in decryption of encoded values

That is obvious, right? But if you ever wondered what is hidden behind those tags, let me tell you the details.

Both those tags add to Mule application spring context a bean implementing BeanFactoryPostProcessor interface. Implementation of that interface allows to scan through all property values gathered from all declared beans within mule flow configuration XML files and replace all ${..} property placeholders with matching values from the properties sources before any bean is initialized.

Besides decoding secured properties values there is one more important difference between those two tags. ‘secure-property-placeholder:config’ is based on deprecated PropertyPlaceholderConfigurer, while ‘context:property-placeholder’ is based on currently recommended Spring approach PropertySourcesPlaceholderConfigurer. That is the reason why even attribute names are different for each of that tag (‘ignore-resource-not-found’ vs ‘ignoreResourceNotFound’).

Note: The most important thing to remember - never declare those two tags together in the same application. You will be in big trouble trying to figure out why suddenly all your properties must be resolved or can’t be override with environment variables. Those two solutions are not fully compatible.

The easiest way to provide values for property placeholder is through properties files. The ‘location’ attribute accepts a list of URLs pointing to file’s address. Usually It is sourced from ‘classpath’ or from file system. Storing properties files in the ‘classpath’ is probably not a good idea - you have to release new version of the application whenever any property is changed. File system sounds much better - you can just replace the file and restart the same app and new property value is in place. Works like a charm… till you have to do it individually on multiple servers (your application became so important that it requires couple instances to handle the load) or in the cloud environment where file system is temporary and can be wiped out any moment. Then you realize that you need …

Centralized configuration management for Mule application

For CloudHub applications Mulesoft prepared a solution for centralized properties management. I never had a chance to play with it, but looks like it can simplify properties management. Although I’m not sure how flexible that solution is. Looks like you can’t easily import/export all properties between sandboxes. Entering manually values for tens of the properties can be even worse then copying properties files between multiple servers.

There is one more option - Spring Cloud Config server. Works for all cases, even for developers dealing with complex on-premise deployment without Anypoint Runtime Manager.

‘Spring Cloud Config’ server can be run as standalone application. Server reads properties from provided git repository and servers them through RESTful API. Address of property file can be provided as valid http URL and can be set up as ‘location’ in both ‘context:property-placeholder’ and ‘secure-property-placeholder:config’. In that simple way all instances of Mule application get the properties from single source that is backed up by git repository. Access to ‘Spring Cloud Config’ server resources can be protected with BASIC authentication. With that valid username/password must be provided in the URL for the property file. Setting up standalone ‘Spring Cloud Config’ server can be done relatively quickly, but making it fully scalable and reliable service for cloud-ready application is much, much harder. It is better to ask your cloud provider to do that…

‘Spring Cloud Config’ for Mule applications on Pivotal Cloud Foundry

If you are deploying Mule applications to Pivotal Cloud Foundry (PCF) then you can set up Spring Config Server for PCF. Once service is created and binded to the Mule application then PCF environment variable VCAP_SERVICES contains credentials required for connecting to the service. Sample config:

{ "p-config-server":
[ { "credentials":
{ "access_token_uri": "http://localhost:8889/oauth/token",
  "client_id": "p-config-server-09bcbe09-8dd8-4491-8a09-4f15365bbae7",
  "client_secret": "xxxxx", "uri": "http://localhost:8889/config"
},"label": "p-config-server",

  "name": "sample-app-config",
  "plan": "standard",
  "provider": null,
  "syslog_drain_url": null,
  "tags": [ "configuration", "spring-cloud" ], "volume_mounts": [] }]
}

There is one problem. PCF secures access to ‘Spring Cloud Config’ service with OAuth2 token authentication. Properties files can’t be accessed directly through URL, so approach with using standard ‘property-placeholder’ tags is not an option.

Pivotal delivers client-side implementation for connecting to the service, but implementation is done only for spring-boot applications and can’t be used directly in Mule. Looks like good old days when spring beans configuration was fully portable between XML and Java are gone.

To resolve that issue and connect Mule application to PCF services I had to implement custom PropertySourcesPlaceholderConfigurer.

‘ConfigClientOAuth2Configurer’ class is based on spring-cloud-services-spring-connector. Logic Inside the class takes application name from PCF ‘cloud:properties’ tag that converts VCAP_APPLICATION variable into ‘Properties’.

During spring bean factory post processing instance of ‘ConfigClientOAuth2Configurer’ class is looping through all PCF binded services. If information for ‘Spring Cloud Config’ is found, then based on it instance of OAuth2RestTemplate is created and passed to ConfigServicePropertySourceLocator. Finally spring active profile and application name decide what configuration set is fetched from ‘Spring Cloud Config’ service API.

It is best to keep ‘ConfigClientOAuth2Configurer’ spring bean declaration in separate classpath resource, for example in /src/main/resources/pcf-util-cloud-config-service.xml:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cloud="http://www.springframework.org/schema/cloud" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cloud http://www.springframework.org/schema/cloud/spring-cloud.xsd">

<bean class="com.appnovation.mule.cloud.cloudfoundry.ConfigClientOAuth2Configurer">  
 
<property name="properties"> <cloud:properties id="pcfProperties"/>  
 </property> <property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
</beans>

Then mule application can simply add jar with ‘ConfigClientOAuth2Configurer’ and ‘pcf-util-cloud-config-service.xml’ as maven dependency in order to import ‘Spring Cloud Config’ service connection with single line of xml configuration:

<spring:import resource="classpath:pcf-util-cloud-config-service.xml" />

Such a library can be shared between multiple Mule applications and make them fully deployable and configurable on PCF. Source code for the library can be downloaded from git repository.