Docker-compose string interpolation causes type conversion issue in spring boot project - spring

I am running a stack of services/applications and would like to deploy these using a single docker-compose file. I tested this and it works flawlessly. But now, when I try to make the docker-compose file more configurable by having an .env file take control of the configuration the spring boot project that has to be deployed gives me the following error:
api | Failed to bind properties under 'spring.data.mongodb.port' to java.lang.Integer:
api |
api | Property: spring.data.mongodb.port
api | Value: '27017'
api | Origin: System Environment Property "spring.data.mongodb.port"
api | Reason: failed to convert java.lang.String to java.lang.Integer (caused by java.lang.NumberFormatException: For input string: "'27017'")
The env file I am using:
SPRING_DATA_MONGODB_PORT=27017
How the back-end is receiving the configuration request in spring boot's application.properties file:
spring.data.mongodb.port=27017
The problem is clear, but how do I make sure that whenever the environment variable arrives, the '27017' in String format is casted to an Integer?
Thanks!

Related

How to set args using Spring Camel Lib in application.properties

Working with SpringBoot, Java 11.
In application.properties i want to configure: camel.component.rabbitmq.args
Documentation by camel using rabbitmq: https://camel.apache.org/components/3.18.x/rabbitmq-component.html#_message_body
Note: I'm not asking about rabbit, just the configuration in application.
Error i have received trying to configure by my way:
application.properties
camel.component.rabbitmq.args={arg.queue.x-message-ttl=3600000}
Error:
Failed to bind properties under 'camel.component.rabbitmq.args' to java.util.Map<java.lang.String, java.lang.Object>:
Reason: No converter found capable of converting from type [java.lang.String] to type [java.util.Map<java.lang.String, java.lang.Object>]
How is the correct way by example? Thanks!!!
In the application.properties, the proper syntax for a component option of type Map is componentOptionName[mapKey]=mapValue so in your case it would be:
camel.component.rabbitmq.args[queue.x-message-ttl]=3600000

encrypt key Property binding error in spring boot 2.7.0

I have Spring boot 2.7.0 application which connects config server with following configuration to decrypt secrets. But when I include below configuration in (application.yml or bootstrap.yml) getting binding error. Not sure what is the root cause of this issue as format is correct for the keys but still getting this error. Same config is working fine with Spring boot 2.2.1.
I have used same config in application.yml without bootstrap.yml as it depricated in 2.7.0 but still same issue.
encrypt:
key-store:
location: file:${key.path}
password: anthem$$docker
alias: docker
secret: anthem$$docker
org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'encrypt.key-store.alias' to java.lang.String
at org.springframework.boot.context.properties.bind.Binder.handleBindError(Binder.java:384)
at org.springframework.boot.context.properties.bind.Binder.bind(Binder.java:344)
at org.springframework.boot.context.properties.bind.Binder.lambda$bindDataObject$4(Binder.java:469)
at org.springframework.boot.context.properties.bind.Binder$$Lambda$78/234145890.bindProperty(Unknown Source)
at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:95)
at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:83)
at org.springframework.boot.context.properties.bind.JavaBeanBinder.bind(JavaBeanBinder.java:59)
at org.springframework.boot.context.properties.bind.Binder.lambda$bindDataObject$5(Binder.java:473)
Description:
Failed to bind properties under 'encrypt.key-store.alias' to java.lang.String:
Property: encrypt.key-store.alias
Value: docker
Origin: class path resource [bootstrap.yml] - 40:12
Reason: org.springframework.boot.context.config.InactiveConfigDataAccessException: Inactive property source 'Config resource 'class path resource [bootstrap.yml]' via location 'optional:classpath:/' (document #5)' imported from location 'class path resource [bootstrap.yml]' cannot contain property 'encrypt.key-store.alias' [origin: class path resource [bootstrap.yml] - 40:12]
Action:
Update your application's configuration

${VAULT_SCHEME} not working in bootstrap.properties

I have configured spring boot application to take properties from my environment but strangely I am facing an error while starting my application.
I have added the properties in my ~/.bash_profile and also did source ~/.bash_profile after adding them to the profile.
This is how my bootstrap.properties look like:
spring.application.name=gamification
spring.cloud.vault.enabled=${VAULT_ENABLE:true}
spring.cloud.vault.fail-fast=false
spring.cloud.vault.token=${VAULT_TOKEN}
spring.cloud.vault.scheme=${VAULT_SCHEME}
spring.cloud.vault.host=${VAULT_HOST}
spring.cloud.vault.port=${VAULT_PORT:8200}
I am getting this error:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.cloud.vault.config.VaultReactiveBootstrapConfiguration]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Scheme must be http or https
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:216) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:117) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:310) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
... 30 common frames omitted
Caused by: java.lang.IllegalArgumentException: Scheme must be http or https
at org.springframework.util.Assert.isTrue(Assert.java:118) ~[spring-core-5.2.4.RELEASE.jar:5.2.4.RELEASE]
at org.springframework.vault.client.VaultEndpoint.setScheme(VaultEndpoint.java:167) ~[spring-vault-core-2.2.0.RELEASE.jar:2.2.0.RELEASE]
at org.springframework.cloud.vault.config.VaultConfigurationUtil.createVaultEndpoint(VaultConfigurationUtil.java:91) ~[spring-cloud-vault-config-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.cloud.vault.config.VaultReactiveBootstrapConfiguration.<init>(VaultReactiveBootstrapConfiguration.java:110) ~[spring-cloud-vault-config-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_231]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_231]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_231]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_231]
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:203) ~[spring-beans-5.2.4.RELEASE.jar:5.2.4.RELEASE]
... 32 common frames omitted
I added a debug point in Vault Endpoint and found this:
Here as you can see, the VAULT_HOST is being taken as VAULT_HOST instead of the value of that environment variable, and same with the VAULT_SCHEME
[EDIT]
Adding bash_profile vault configuration:
export VAULT_ENABLE=true
export VAULT_SCHEME=http
export VAULT_HOST=vault-1.dev.lokal
export VAULT_PORT=8200
export VAULT_TOKEN=5F97X
[EDIT #2]
Tried out the solution suggested by #Gopinath
I am getting environment as null when trying to autowire it
The root cause of the problem can be found form this error message:
org.springframework.core.convert.ConverterNotFoundException:
No converter found capable of converting
from type [java.lang.String]
to type [org.springframework.cloud.vault.config.VaultProperties$Config]
The above message indicates that the VaultProperties object could not be initialized using the string parameter supplied.
Here is the link to documentation and instructions on configuring VaultProperties:
https://spring.io/guides/gs/vault-config/
Some more information to help understand vault:
References:
Spring Cloud Vault: https://cloud.spring.io/spring-cloud-vault/
Hashicorp Vault: https://www.vaultproject.io
What is a Vault?
A vault is a secure storage space meant for storing secret information.
Hashicorp Vault is one tool that offers vault functionality for cloud applications.
What is Spring Boot Vault?
Spring Boot applications commonly require secret information for those to work.
Some examples of secret information are:
Database password
Private key
API key
Usually, the input parameters are passed to Spring boot application through the
"application.properties" file or "bootstrap.properties" file.
The use of such properties file poses a security risk, if secret data is directly mentioned in the file.
Spring Boot Vault addresses this risk.
It pulls secret information from vault and supplies to the application at the start-up time.
The .properties file will only tell the application the names of parameters that it can expect from Vault.
The actual values of the parameters will be taken from vault.
How to setup Vault?
Step 1: Install and launch HashiCorp Vault from
https://www.vaultproject.io/downloads.html:
Step 2: After installing Vault, test whether it works, by launching
it in a console window.
> vault server --dev --dev-root-token-id="spring-boot-vault-demo"
==> Vault server configuration:
Api Address: http://127.0.0.1:8200
Cgo: disabled
Cluster Address: https://127.0.0.1:8201
Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
Log Level: info
Mlock: supported: false, enabled: false
Recovery Mode: false
Storage: inmem
Version: Vault v1.4.1
WARNING! dev mode is enabled!
.....
You may need to set the following environment variable:
PowerShell:
$env:VAULT_ADDR="http://127.0.0.1:8200"
cmd.exe:
set VAULT_ADDR=http://127.0.0.1:8200
The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.
Unseal Key: +Dihvgj/oRN2zo6/97ZqpWt086/CFRZEPkuauDu4uQo=
Root Token: spring-boot-vault-demo
Step 3: Store some secret data in the vault,
by running these commands in a separate command window:
> set VAULT_ADDR=http://127.0.0.1:8200
> set VAULT_TOKEN=spring-boot-vault-demo
> vault kv put secret/spring-boot-vault-demo password=££££$$$$%%%%
Key Value
--- -----
created_time 2020-05-02T09:59:41.2233332Z
deletion_time n/a
destroyed false
version 1
I did this:
I made a shell script called setenv.sh and put this under it:
#!/bin/bash
launchctl setenv VAULT_ENABLE true
launchctl setenv VAULT_SCHEME http
launchctl setenv VAULT_HOST vault-1.dev.lokal
launchctl setenv VAULT_PORT 8200
launchctl setenv VAULT_TOKEN 5F97X
And then, before starting the application I ran the shell script with
sudo sh setenv.sh
And the application seems to work fine without any errors. Strangely if I do it with my previous approach of adding the env variables inside the .bash_profile, it doesn't work.

Cannot bind environment variable to application.properties

Im working with Spring-boot and PostgreSQL and failed to bind the database password to the application.properties. I have already set the DATABASE_PASSWORD to env but its still failed to bind the properties
spring.datasource.url=jdbc:postgresql://${DATABASE_HOST}:${DATABASE_PORT}/${DATABASE_NAME}?reWriteBatchedInserts=true
spring.datasource.username=${DATABASE_USER}
spring.datasource.password=${DATABASE_PASSWORD}
Description:
Failed to bind properties under 'spring.datasource.password' to
java.lang.String:
Property: spring.datasource.password
Value: ${DATABASE_PASSWORD}
Origin: class path resource [application.properties]:16:28
Reason: Could not resolve placeholder 'DATABASE_PASSWORD' in value "${DATABASE_PASSWORD}"
if you have set your database_password to a system environment as you say, than spring should use that as this says -:
The values in application.properties are filtered through the existing Environment when they are used, so you can refer back to previously defined values (for example, from System properties).
Did you try restarting ?

Set management port to be server port +1 in Spring boot

As my service can get port number injected through env variable SERVER_PORT I wanted management port to be +1 of this value. So I tried to configure it in application.yml using various combinations of idea below:
management.port: "#{ ${server.port:8080} + 1}"
resulting in: Caused by: java.lang.NumberFormatException: For input string: "{8080+1}"
or
management.port: "# ${server.port:8080} + 1"
resulting in: Caused by: java.lang.NumberFormatException: For input string: "8080+1"
How can I do this correctly? I have found in Spring Boot documentation that SpEL is not working in application property files:
Finally, while you can write a SpEL expression in #Value, such
expressions are not processed from Application property files.
But maybe there is some other way?

Resources