Spring Cloud Config fails to update properties dynamically - spring-boot

I have a Camel Spring Boot application where I am printing the value of a property which is set using Spring Cloud Config Server (via Git commit id plugin). The issue is that the value of the property in Camel application is not updated once the value is committed to Git. I have to restart the Camel application which fails the purpose of Spring Cloud Config server. Please note that we are using Git file system in our local machine.
The name of the properties file is CamelSpringBootSample-dev.properties.
As soon as I commit, the config server publishes the updated value at the endpoint on refresh:
http://localhost:8888/CamelSpringBootSample/dev
I have also made the Camel application end point available at:
http://localhost:8181/actuator/env
Here the value of the property is not updated on refresh. However, if I restart the Camel application, the value is reflecting.
The source code for all the three projects are uploaded in github.com.
The config server: https://github.com/sreejeshraj/config-server
The Camel client project (which uses the config server to configure itself): https://github.com/sreejeshraj/camel-config-server
Please do not get misled by the repository name camel-config-server. This is the client of config server, but I accidentally named it incorrectly, apologies.
The local git repository where the configuration properties are stored: https://github.com/sreejeshraj/Git-Config
Please note that I have used the annotation #RefreshScope in my Spring bean component class.
Can you please help me with this? Thanks in advance.

You have to set:
management.endpoints.web.exposure.include=refresh
in bootstrap.properties or bootstrap.yml.
and trigger the /actuator/refresh endpoint.
See #RefreshScope and /refresh not working
Note that as said in the comments, Camel does not update its values when a Spring beans is refreshed and there is no plan to implement this feature. (https://issues.apache.org/jira/browse/CAMEL-13892). You probably could find a solution through Spring Cloud Bus.

As #ortomala-lokni already pointed out, you need to refresh your configuration consumers after an update happened.
If you want a centralized solution for this task (for refreshing many components automatically), take a look at Spring Cloud Bus.
This page gives a quite good overview about the subject.

I had a situation where I had both application.properties and bootstrap.properties file in my client. I that case you should specify spring.application.name and spring.cloud.config.server.git.uri inside bootstrap.yml. I didn't refresh properties having spring.application.name inside applicaiton.properties.

Related

Open API (Swagger) non working in Spring Boot when adding context path

I have a Spring Boot application exposing REST services that are easily called on addresses like
http://localhost:8080/<controller_mapping>/<service_mapping>.
I've been asked to modify my settings in order to add a context path and have my services to respond on
http://localhost:8080//gesev-mensa/<controller_mapping>/<service_mapping>.
Thus I edited my application.properties adding
server.servlet.context-path=/gesev-mensa
Everything works but I can't call Swagger on old address
http://localhost:8080/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/
I get the error Failed to load remote configuration
As suggested, I tried to add property
springdoc.swagger-ui.path=/gesev-mensa/swagger-ui/index.html
but problem persists.
I guess Swagger should be reachable at
http://localhost:8080/gesev-mensa/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config#/
but that doesn't work.
Any hint?
Thanks for support.
Try removing
springdoc.swagger-ui.path=/gesev-mensa/swagger-ui/index.html
from your properties,
And your swagger will be available in
http://localhost:8080/gesev-mensa/swagger-ui/index.html
As per your current configuration with,
springdoc.swagger-ui.path=/gesev-mensa/swagger-ui/index.html
Swagger will be available in
http://localhost:8080/gesev-mensa/gesev-mensa/swagger-ui/index.html

Spring Cloud Config dual bootstrap files behavior

I have a setup where I am using the following:
Spring Boot 1.5.13 with Spring Cloud Version Edgware.S3
I have Spring Cloud Config Server and my Spring Boot apps are its clients
Each app carries a bootstrap.yml with the config server uri and some other properties.
Running containers on a Docker Swarm
I am currently passing Swarm secrets to the clients via a custom script which reads the files put into /run/secrets/ and creating a /config/bootstrap.properties file. It ends up looking like this:
spring.cloud.config.username=user
spring.cloud.config.password=password
My Docker image's default command is then this:
java -Djava.security.egd=file:/dev/./urandom -jar /${appName}.jar --spring.cloud.bootstrap.location=file:/config/bootstrap.properties"
Great. This is working without a problem. The app, seemingly, reads:
The external bootstrap.properties to read in the config server's credentials
The classpath bootstrap.yml to read in the rest of the config client props
Fetches and reads in the config server's application-appName.yml
Then reads the bundled application.yml from the classpath
Now. I'm moving the apps to Spring Boot 2.0.3 with Finchley.RELEASE and well, this breaks.
What is happening now is:
The external bootstrap.properties is read in to get the config server's credentials
The classpath bootstrap.yml is SKIPPED entirely (UNEXPECTED!)
Fetches and reads in the config server's application-appName.yml
Then reads the bundled application.yml from the classpath
The problem is that the properties that were set in the internal bootstrap.yml are now missing for the app so it blows up on start. I've been able to reproduce it outside the container environment by doing the same thing; point the app to an external bootstrap.properties. If I copy over the bootstrap.yml properties into the bootstrap.properties, then it works just fine. Also, if I don't provide an external properties file, then the internal bootstrap.yml kicks in without a problem. So it's either one or the other!
I'v also tried modifying the bootstrap location to include the default locations but no luck:
-- spring.cloud.bootstrap.location=file:/config/bootstrap.properties,classpath:,classpath:/config,file:,file:config/
Any ideas where to look next? Maybe there is a new spring.cloud.config property I'm missing? Or can anyone confirm which behavior is the correct behavior? Assuming they fixed a potential loophole in Finchley then I can just put this to rest and look for another solution. If it's 'broken' in Finchley, I guess an issue report is in order?
Well, some more digging showed that it looks like this is the new behavior:
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Migration-Guide
The behavior of the spring.config.location configuration has been fixed; it previously added a location to the list of default ones, now it replaces the default locations. If you were relying on the way it was handled previously, you should now use spring.config.additional-location instead.
It didn't look to be Spring Cloud specific but I had nothing to lose.
Changing my java command to use this new property did the trick:
--spring.config.additional-location=file:/config/bootstrap.properties
Thanks.

Spring Cloud Config and Spring Cloud Vault order of initialization

We are leveraging Spring Cloud Config and Spring Cloud Config Vault. We would like to know if there is a way to "bootstrap the bootstrap", ie we want spring cloud config server to be hit and then pull properties from that to leverage in our vault configuration. We looked at order, but it didn't appear to work, and I assume it is because of the post processing order, but I was hoping I might be missing something.
TL;DR
It doesn't work.
Explanation
What Spring Cloud does with its bootstrap context, is setting up an application context that contains a set of PropertySources initialized from Spring beans. The bootstrap context is used then as parent context for the actual context created by Spring Boot. A property lookup looks for properties in its own context and within the parent context.
Configuration properties are initialized very early in the startup process and they use properties from the current Environment. At the time ConfigurationProperties beans are initialized, the Environment does not yet contain any remote PropertySources.
The only option I see here (except creating a bootstrap-bootstrap-context) is using the Spring Cloud Config client within your main class and contribute Vault properties before any Spring context is built.
Probably you can, but it requires PropertySourceBootstrapConfiguration#initialize() method overriding. You can't disable bean PropertySourceBootstrapConfiguration, but you can disable it's initialize method by using applicationContext.getBeanFactory().getBean(PropertySourceBootstrapConfiguration.class).setPropertySourceLocators(new ArrayList<>()) in CustomPropertySourceBootstrapConfiguration (to avoid obsolete external property sources calls).
In your CustomPropertySourceBootstrapConfiguration#initialize method you can retrieve properties from config-server and then customize your vaultPropertySourceLocator by inserting generated in config-server secretId of token.
Don't forget to add your CustomPropertySourceBootstrapConfiguration to spring.factories.
So, it's not easy but it is possible.
We created the custom datasource using EnvironmentPostProcessor which will get called before autoconfigure beans
https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.application.customize-the-environment-or-application-context

Properties change with out a server restart

I have externalized all my application needed property files from webapps in tomcat. Now i can simply change a property file value without a need of rebuilding the war file and deploy it again. However each change to property file is associated with server recyling.
Is there a way how the recycling can be avoided for a property file change.
I am using spring to read the property files for few webapps and java property traditional way for few webapps.
Please suggest how to acheive
You may want to consider spring-cloud-config-server or spring-cloud-consul all of these options supports distributed properties management as well as value changes refresh without a need to recycle app servers.
And you can use #RefreshScope for Spring #Beans that want to be reinitialized when configuration changes, they also provide the following Management endpoints out of the box and many more as explained on the project git page
/refresh for refreshing the #RefreshScope beans
/restart for restarting the Spring context (disabled by default)
This is supported by either option (spring-cloud-config-server or spring-cloud-consul)
You may also give cfg4j a try. It supports reloading configuration from local files as well as remote services (git repository, Consul, etc.).

Having spring bean properties refreshed automatically from properties file

I'm using Spring 2.5.6. I have a bean whose properties are being assign from a property file via a PropertyPlaceholderConfigurer. I'm wondering whether its possible to have the property of the bean updated when the property file is modified. There would be for example some periodic process which checks the last modified date of the property file, and if it has changed, reload the bean.
I'm wondering if there is already something that satisfies my requirements. If not, what would be the best approach to solving this problem?
Thanks for your help.
Might also look into useing Spring's PropertyOverrideConfigurer. Could re-read the properties and re-apply it in some polling/schedular bean.
It does depend on how the actual configured beans use these properties. They might, for example, indirectly cache them somewhere themself.
If you want dynamic properties at runtime, perhaps another way to do it is JMX.
One way to do this is to embed a groovy console in your application. Here's some instructions. They were very simple to do, btw - took me very little time even though I'm not that familiar with groovy.
Once you do that you can simply go into the console and change values inside the live application on the fly.
You might try to use a custom scope for the bean that recreates beans on changes of the properties file. See my more extensive answer here.
Spring Cloud Config has facilities to change configuration properties at runtime via the Spring Cloud Bus and using a Cloud Config Server. The configuration or .properties or .yml files are "externalized" from the Spring app and instead retrieved from a Spring Cloud Config Server that the app connects to on startup. That Cloud Config Server retrieves the appropriate configuration .properties or .yml files from a GIT repo (there are other storage solutions, but GIT is the most common). You can then change configuration at runtime by changing the contents of the GIT repo's configuration files--The Cloud Config Server broadcasts the changes to any Client Spring applications via the Spring Cloud Bus, and those applications' configuration is updated without needing a restart of the app. You can find a working simple example here: https://github.com/ldojo/spring-cloud-config-examples

Resources