Override configuration properties in micronaut - java

I have a micronaut application in which I want to override the default configuration properties based on a profile I pass through an environment variable.
Tha application has a default application.yml
I am currently passing:
MICRONAUT_CONFIG_FILES=classpath:application.yml,/path/to/application-prod.yml
MICRONAUT_ENVIRONMENTS=prod
However just application-prod.yml is taken into account (unlike for Spring Boot where it updates the defaults).
What is the best way to achieve the update? The only solution so far is to replicate all the settings in application-prod.yml but it seems pretty anti-DRY.

Related

Spring Boot: how to disable (or remove) property in application.properties using externalized configuration

I'm working on a Spring Boot project (v2.3.x) connected to a MongoDB instance.
The connection is configured using the property spring.data.mongodb.uri.
Now, for local development I'd like to configure the connection using host/port, i.e. using these properties (I'm configuring these via ENV VARs):
spring.data.mongodb.host
spring.data.mongodb.port
Adding these properties, while leaving spring.data.mongodb.uri, obviously results in an error on application run:
java.lang.IllegalStateException: Invalid mongo configuration, either uri or host/port/credentials/replicaSet must be specified
So I'm wondering if there is a way to disable the spring.data.mongodb.uri configuration using properties override (externalized configuraion) provided by Spring Boot.
Is this possible? I tried setting spring.data.mongodb.uri=null but the startup error remains.
How can I achieve this without directly modifying the application.properties file?
NOTE: I also considered using profiles, but also using this feature I cannot find a way to override the "main" configuration.
You could use "application-default.properties" file and put spring.data.mongodb.uri in there. The "default" Spring profile will be active when no other profiles are selected. So you can start locally with any profile ("dev" or whatever) and "application-default.properties" file will not be loaded.
Of course, keep in mind that adding any profile in production would also disable spring.data.mongodb.uri in this case.

How to merge application.properties with application-default.properties and include in other test profiles with Spring Boot >2.4

We would like to merge src/main/resources/application.properties with additional default properties when running tests which in turn should be included by other (test) properties files activated via specific profiles in our Spring Boot application.
Up until Spring Boot 2.4 this worked quite well by having all common test properties in src/test/resources/application-default.properties to keep things DRY. Those were then automatically merged with the ones from src/main/resources/application.properties by Spring [1]. This allowed us to have our own set of default properties without requiring tests to specify an #ActiveProfiles("default").
Other (test) profiles could then have their own application-<profile>.properties with spring.profiles.include=default and then further extend the defaults.
With Spring Boot 2.4 I'm struggling with the new "rules":
I can no longer load application-default.properties from application-<profile>.properties since spring.profiles.include is no longer allowed in non profile-specific documents [2].
I don't want to introduce a src/test/resources/application.properties since I don't want to repeat everything from src/main/resources/application.properties. Also I don't want to load any activate any test-related profiles in the app's properties.
It looks like one solution could be to explicitly add spring.profiles.include=default to src/main/resources/application.properties to force the application to include the properties file with default properties which will work as before when it comes to running the actual application but consider src/test/resources/application-default.properties when running the tests.
Is this the way to go or are there smarter solutions to tackle this problem and still keep the properties free of redundancies?
spring.profiles.active=dev
add this config in application.properties file

Spring-boot property value used in another property key

In my spring boot project, I want to use a property value in another property key:
server.mode=mock
server.protocol.mock=http
server.host.mock=my.host-mock.org
...
server.protocol.prod=https
server.host.prod=my.host-prod.org
...
I want to depending on "server.mode" value use the related property key server.protocol.{value}
How could I do this?
Thanks for help
You can use spring profiles, where you can setup different property configurations for different deployment environments.
Using property files, you can create a property file per profile and then have spring boot use the right property configuration depending on the active profile.
application-dev.properties
server.scheme=http
server.host=my.host-mock.org
application-prod.properties
server.scheme=http
server.host=my.host-mock.org
You would then have to tell spring boot which profile to use by setting it in the spring.profiles.active property. When deploying to the cloud with application manifests (like Cloud Foundry or Kubernetes), then it is convenient to set this via an environment variable SPRING_PROFILES_ACTIVE.
See the official spring-boot documentation for more information about profiles.
This can be achieved using the following format while fetching the value in code (or the correpsonding xml) where you are using it:
#Value("${server.protocol.${server.mode}}")
private String mode;

Setting spring.profiles.active from an environment variable in Spring Boot with Gradle

My company has a standard way to specifying the environment a web service should run in, specifically 'development' and 'production' by using an environment variable APP_ENV. Each of these environments have a separate config file: application-dev.yml and application-prod.yml.
In spring boot, we can use SPRING_PROFILES_ACTIVE or equivalents to do this, but what I really want to do is grab the VALUE from APP_ENV, and use that as the profile.
I've got some code
SpringApplication app = new SpringApplication(Application.class);
springApp.setAdditionalProfiles(System.getenv("APP_ENV"););
springApp.run(args);
Any tips on how to do this a bit cleaner? I'm getting
java.lang.IllegalStateException: Failed to load ApplicationContext errors on various gradle tasks that make this solution kind of flimsy.
you can use System.getProperty which will always return a String like below,
springApp.setAdditionalProfiles(System.getProperty("APP_ENV", "dev"));
In the above snippet, we use System.getProperty(“APP_ENV”) to extract the value of the property APP_ENV. We also are making use of the default value so if the property is not available in the system, getProperty returns dev.

How to access the credentials in Kubernetes for MongoDB with Java?

I am working on Java Springboot with MongoDB using Kubernetes. Currently I just hard coded the URI in application properties and I would like to know
how can I access to the MongoDB credentials on Kubernetes with Java?
The recommended way of passing credentials to Kubernetes pods is to use secrets and to expose them to the application either as environment variables, or as a volume. The link above describes in detail how each approach works.
If I properly understood the question, it is specifically about Java Spring Boot applications running on Kubernetes.
Few options come to my mind...some not that secure or exclusive to running on Kubernetes but still mentioned here:
Environment variables with values in the deployment/pod configuration. Everyone with access to the configuration will be able to see them.
Use ${<env-var>} / ${<end-var>:<default-value>} to access the environment variables in Spring Boot's application.properties/.yaml file. For example, if DB_USERNAME and DB_PASSWORD are two such environment variables:
spring.data.mongodb.username = ${DB_USERNAME}
spring.data.mongodb.password = ${DB_PASSWORD}
...or
spring.data.mongodb.uri = mongodb://${DB_USERNAME}:${DB_PASSWORD}#<host>:<port>/<dbname>
This will work regardless whether the application uses spring.data.mongodb.* properties or properties with custom names injected in a #Configuration class with #Value.
Based on how the Java application is started in the container, startup arguments can be defined in the deployment/pod configuration, similarly to the bullet point above.
Environment variables with values populated from secret(s). Access the environment variables from SpringBoot as above.
Secrets as files - the secrets will "appear" in a file dynamically added to the container at some location/directory; it would require you to define your own #Configuration class that loads the user name and password from the file using #PropertySource.
The whole application.properties could be put in a ConfigMap. Notice that the properties will be in clear text. Then populate a Volume with the ConfigMap so that application.properties will be added to the container at some location/directory. Point Spring Boot to that location using spring.config.location as env. var, system property, or program argument.
Spring Cloud Vault
Some other external vault-type of secure storage - an init container can fetch the db credentials and make them available to the Java application in a file on a shared volume in the same pod.
Spring Cloud Config...even though it is unlikely you'd want to put db credentials in its default implementation of the server storage backend - git.

Categories