How to mock Consul properties in local environment of SpringBoot app? - spring-boot

There is a SpringBoot applicattion with the following configuration:
application.yml
custom:
api-base-url: http://${application.environment}-internal-api:8080
secret-key: ${my.consul.property.secretKey}
Normally on staging env, the placeholders are being resolved by a configuration in Consul (all needed spring cloud consul dependencies were added).
I would like to run application locally and override both of these properties (api-base-url, secret-key)
with the following properties file:
/my/local/directory/app-local.yml
application.environment: local
custom:
api-base-url: http://extenal-api.org
secret-key: 36vch34c53j54v563ch3
Trying to run spring-boot:run command I get a property resolving error.
mvn spring-boot:run -D spring-boot.run.arguments=--spring.config.additional-location=/my/local/directory/app-local.yml
java.lang.IllegalArgumentException:
Could not resolve placeholder 'my.consul.property.secretKey'
in value "${my.consul.property.secretKey}"
at o.s.u.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:180)
at o.s.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at o.s.c.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:239)
And even if we exclude custom.secret-key, it appears that custom.api-base-url is resolved to http://local-internal-api:8080, that means the app-local.yml is processed, application.environment is resolved to "local", but the other two properties are still resolved from the original values in application.yml
What is the proper way to override properties and placeholders for running application locally?

Related

Spring Boot Configuration File Location From Tomcat

I'm trying to setup backend application so it gets different configuration files depending on env.
On dev env I would like to load default application.yml from classpath. This should be the case when I'm running the app via: mvn spring-boot:run or java -jar ./target/myapp.war
But when this app is running on Tomcat it should load application.yml from server specific file e.g. /etc/apps/myapp/application.yml (not default one from classpath) because server has different mongodb credentials etc...
I don't want to use profiles because this mean I need to put server credentials in project on github in application.yml. I just want that this is known by server administrator and developer don't know anything about it.
Is there any way how can I tell this application inside tomcat to load different configuration file.
In this Tomcat I have other applications that are using spring boot so I need some solution that is independent. Setting globally spring.config.location is not the case because all apps will load this one file.
You can use #PropertyResource annotation with context xml.
NOTE: ignoreResourceNotFound will help not throw exception when file not found, say for Dev env.
#Configuration
#PropertySources({
#PropertySource("classpath:application.properties"),
#PropertySource(value = "file:${config.file}", ignoreResourceNotFound=true)
})
public class AppConfig {
//...
}
/META-INF/context.xml
<Context>
<Parameter name="config.file" value="/yourpath/application.properties"/>
</Context>
If you don't want to save path in context.xml inside your project, there are other ways to define application level context depending on your tomcat version. Please refer here for details for tomcat 9.
If you want to read properties from external location then write bootstrap.yml in your application and delete application.yml.
bootstrap.yml:
spring:
config:
location: file:/home/external/properties/location/
name: application
profiles:
active: dev
file location: /home/external/properties/location/
suppose you need dev and prod environment.Then keep this 3 properties file in this location.
application.yml
application-dev.yml
application-prod.yml
Spring boot read application.yml properties first. If set active profile dev in bootstrap.yml then application.yml value overwirte by application-dev.yml.
Or you can use config server
Look at this

Specifying application config file by name when Spring Boot starts up

Currently I can build my Gradle-based Spring Boot app like so:
./gradlew build && java -Dspring.config=. -jar build/libs/myapp.jar
And this works fine provided I have an application.yml in the root of my project directory.
However, I would now like to have both an application-local.yml as well as an application-dev.yml, and to specify which one to use when I build + run myapp.jar.
How can I specify either file at startup?
You can use Spring boot's capability of using Profile Specific property file.
You can specify the application yml inline with your profile name
application-[profile].yml. In your case, it would be
application-dev.yml
application-local.yml
Specify the profile you would want to use as a command line argument
-Dspring.profiles.active=dev

In Spring Boot, how do you build a JAR file for a different profile even if proper environment variables have not been set?

I'm new to Spring Boot, so bear with me. Currently, I'm working on a small app just for the purposes of learning Spring Boot. My goal is to deploy it using AWS (elastic beanstalk).
So far, I've created three application properties files:
application.properties: Properties which apply to all profiles.
application-dev.properties: Properties only for development. This includes localhost connection to DB, path to self signed key store, etc.
application-prod.properties: Properties used only for prod. This includes the prod DB details, etc.
Everything works fine when running the app locally using the dev profile since everything has been hard coded in the application-dev.properties.
However, the application-prod.properties file contains references which will be resolved through OS environment variables, such as:
spring.datasource.username=${DB_USERNAME}
spring.datasource.password=${DB_PASSWORD}
I currently do not have the variables DB_USERNAME and DB_PASSWORD set up in my local OS, and I do not wish to do so. But when I run the following command, it obviously fails:
mvn package spring-boot:repackage -Dspring.profiles.active=prod
It fails because it's unable to find the above environment variables.
Is there any way to delay this check until I actually execute the JAR? My plan is to build the JAR locally and then copy it over to my prod server, and run it there. The prod server will definitely have these environment variables.
The workaround I found is this:
mvn package spring-boot:repackage -Dspring.profiles.active=dev
java -jar -Dspring.profiles.active=prod [jar-file-name].jar
However, this feels like a hack. And it may cause issues in the future that I can't think of right now.
You can use any value you want in those properties for prod profile. If the env varieble exists, Spring will take the value from there instead of the properties.
As explained here:
Spring Boot uses a very particular PropertySource order that is
designed to allow sensible overriding of values. Properties are
considered in the following order:
[...]
OS environment variables.
[...]
Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants).
So your application-prod.properties can look like this:
spring.datasource.username=willBeOverridenByEnvValue
spring.datasource.password=willBeOverridenByEnvValue
You have to make sure though that you set both SPRING_DATASOURCE_USERNAME and SPRING_DATASOURCE_PASSWORD env values in your prod server

Spring Boot embedded jar and application.properties location

I thought I had this working because in my IDE the correct environment properties file was being used, and a local application.properties was being correctly used. I am trying to use profile specific properties to determine various values throughout my Spring-Boot 1.3.5 app.
My src/main/resources/application.properties is:
spring.profiles.active=test
server.port=8080
deploy.server=http://localhost
liquibase.change-log:classpath:/db/changelog/db.changelog-master.xml
liquibase.check-change-log-location=true
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
logging.file=myapp.log
spring.jackson.serialization.write_dates_as_timestamps=false
And I have a src/main/resources/application-test.properties:
server.port=8081
deploy.server=https://test.myapp.com
logging.level.liquibase:TRACE
logging.level.org.springframework.security:DEBUG
Now I apparently have two problems:
After I run "gradle clean build" I get my jar and trying to run via:
java -jar build/libs/app.jar -Dspring.profiles.active=local
I see the message:
The following profiles are active: test
So it picking that up from the application.properties file and I can't seem to override it, which I think is causing my second problem:
My Jenkins build fails when I try to use a parameterized build with the values:
spring.profiles.active set to "test".
The error I get is Tomcat in a failed state. If I take that parameter out of the build, it works. But that build will not run from the command line unless I copy the application-{env}.properties to the run directory (which might be best practice anyway?).
I am not sure if the problem is the location of the properties files or the way I am trying to build them.

Spring boot not reading environment specific YAML file

I have developed a spring boot rest application and I am trying to read the environment specific YAML file based on the value "spring.profiles.active"
I have two files
1. application.yml
2. application-qa.yml
and I have below property in both the files
application.yml file has below property
comp:
bu:
env: local
application-qa.yml file has below property
comp:
bu:
env: QA
and I am setting spring.profiles.active=qa, given above, I was expecting that only application-qa.yml gets loaded, but in this case both application.yml and application-qa.yml are getting loaded and when my code looks for property comp.bu.env it is always getting the value
local
only
I want my code to read the comp.bu.env property from application-qa.yml file.
can some help to figure out what i am missing here?
It seems like the spring.profiles.active value is not being set correctly, and hence your app is loading the default application.yml.
Try setting the value with
-Dspring.profiles.active=qa
before the bootRun command.
e.g. If you are using gradle, you would do ./gradlew -Dspring.profiles.active=qa bootrun
Remove comp.bu.env configuration from application.properties. Create separate configuration file application-dev.yaml and place this configuration there:
comp:
bu:
env: local
Now when you work on local configure spring.profiles.active=qa.
This would effectively create development configuration profile.
Thanks for your points, I have solved it.
I have AWS profile in application-qa.yml which is causing my QA properties to be skipped because the profile name I have supplied is QA. I have moved my properties above the AWS:profile in application-qa.yml file then those properties started picking up.

Resources