use cloud foundry vcap env variables in spring's application.yml - spring-boot

In my application.yml of my spring boot app I want to configure the actuator metrics to push to my elastic server.
metrics:
enable:
all: false
diskspace: true
jvm: true
mycustomstuff: true
export:
elastic:
enabled: true
host: https://${vcap.services.my-cloud-logging.credentials.Elasticsearch-endpoint}
password: ${vcap.services.my-cloud-logging.credentials.Elasticsearch-password}
user-name: ${vcap.services.my-cloud-logging.credentials.Elasticsearch-username}
auto-create-index: false
index: metrics
But micrometer keeps failing when sending metrics because my variable is not well expended
Illegal character in authority at index 8: https://${vcap.services.my-cloud-logging.credentials.Elasticsearch-endpoint}/metrics-2021-10/_bulk"
I checked at runtime all the variables have the correct value. They are created by CloudFoundryVcapEnvironmentPostProcesso.
Actually, I have the feeling the problem is caused by the concatenation of "https://" with the variable.
Also confirmed by this unanswered question, where the OP wants to prepend "jdbc:" to a vcap variable
Using double quotes as "host: https://${vcap.services.my-cloud-logging.credentials.Elasticsearch-endpoint}" didn't help

Related

Spring Cloud Gateway and TokenRelay Filter

I’m trying to migrate JHipster from using Zuul to Spring Cloud Gateway. JHipster uses Eureka to look up routes and I believe I’ve configured Spring Cloud Gateway correctly to look up routes and propagate the access token to them. Here’s my config:
spring:
cloud:
gateway:
default-filters:
- TokenRelay
discovery:
locator:
enabled: true
lower-case-service-id: true
route-id-prefix: /services/
httpclient:
pool:
max-connections: 1000
The problem I’m experiencing is the access token is not sending an Authorization header to the downstream services.
Here's how things were configured with Zuul in my application.yml:
zuul: # those values must be configured depending on the application specific needs
sensitive-headers: Cookie,Set-Cookie #see https://github.com/spring-cloud/spring-cloud-netflix/issues/3126
host:
max-total-connections: 1000
max-per-route-connections: 100
prefix: /services
semaphore:
max-semaphores: 500
I created a pull request to show what's changed after integrating Spring Cloud Gateway.
https://github.com/mraible/jhipster-reactive-microservices-oauth2/pull/4
Steps to reproduce the issue:
git clone -b reactive git#github.com:mraible/jhipster-reactive-microservices-oauth2.git
Start JHipster Registry, Keycloak, and the gateway app:
cd jhipster-reactive-microservices-oauth2/gateway
docker-compose -f src/main/docker/jhipster-registry.yml up -d
docker-compose -f src/main/docker/keycloak.yml up -d
./mvnw
Start MongoDB and the blog app:
cd ../blog
docker-compose -f src/main/docker/mongodb.yml up -d
./mvnw
Navigate to http://localhost:8080 in your browser, log in with admin/admin, and try to go to Entities > Blog. You will get a 403 access denied error. If you look in Chrome Developer Tools at the network traffic, you'll see the access token isn't included in any headers.
I was able to solve this using this answer.
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
predicates:
- name: Path
args:
pattern: "'/services/'+serviceId.toLowerCase()+'/**'"
filters:
- name: RewritePath
args:
regexp: "'/services/' + serviceId.toLowerCase() + '/(?<remaining>.*)'"
replacement: "'/${remaining}'"
I also had to add .pathMatchers("/services/**").authenticated() to my security config, which wasn't needed for Zuul. You can see my commit here.

No such label error with spring cloud config server with composite config of two git repos

We have a spring cloud config server with a composite configuration like this:
spring:
profiles:
active: composite
cloud:
config:
server:
composite:
-
type: git
uri: "https://github.comcast.com/config-org/{application}"
username: "mainUsername"
password: "mainPassword"
searchPaths: "*"
-
type: git
uri: "https://github.comcast.com/config-org/shared-repo"
username: "sharedUsername"
password: "sharedPassword"
searchPaths: "*"
health:
enabled: false
Here's the issue we're running into. Given that there is a repository named xsp-reference-service, when the cloud config client makes a request to the config server with a label for a branch that exists in the application (xsp-reference-service) repository, but not in the shared (shared-repo) repository, we get this:
{
"timestamp": "2019-12-04T16:18:43.886+0000",
"status": 404,
"error": "Not Found",
"message": "No such label: schrodingers_branch",
"path": "/xsp-reference-service/dev/schrodingers_branch"
}
Is there a way we can either tell Spring Cloud Config Server to not worry about the missing branch in the shared repository (fail gracefully)? If not, can we force cloud config server to use a default label (branch name) if the provided one does not exist? I'll even take suggestions on maybe a different setup that would serve our use case better. Any comments are welcome.
I don't have the required rep to comment nor do I know how to tell Spring Cloud Config Server to gracefully fail. That being said, I was able to find some information here[1].
Two important points from the above documentation:
Any type of failure when retrieving values from an environment
repository results in a failure for the entire composite environment.
When using a composite environment, it is important that all
repositories contain the same labels. If you have an environment
similar to those in the preceding examples and you request
configuration data with the master label but the Subversion repository
does not contain a branch called master, the entire request fails.
It might be in your best interest to revisit your design with having a shared repo. One alternative could be to use Spring Vault[2]. Then (taken from the same above link) you can define distinct types of repositories and no longer have this composite labeling problem.
spring:
profiles:
active: git, vault
cloud:
config:
server:
git:
uri: file:///path/to/git/repo
order: 2
vault:
host: 127.0.0.1
port: 8200
order: 1
1: https://cloud.spring.io/spring-cloud-config/multi/multi__spring_cloud_config_server.html#composite-environment-repositories
2: https://spring.io/projects/spring-vault

Reaching yaml consul config from Spring-Boot

I try to use Consul as configuration server with Spring boot. I already succeed to use the kv store of consul to fetch variables, but now I want to be able to fetch variables as YAML files. Here is my bootstrap.yaml :
spring:
cloud.consul:
host: localhost
port: 8500
config:
enabled: true
format: YAML
failFast: true
I put this config on consul on the path "/config/my.application.name/data" :
testspring: hello
And I try to reach this property using :
#Value("${testspring}")
... with no success.
What am I missing here ? What is the good path for config on consul ?
Thanks
EDIT :
It appears that the config is loaded on the value ${data} and that it is not parsed. The data="testspring: hello", which is not what is expected.
I was able to fetch data using your sample. But if I remove format: YAML (so use default KEY_VALUE) from my config then not parsed data property is fetched.
Maybe double check your bootstrap.yml config for correct indentations.
What version of Spring Boot and Spring Cloud you are using ?

Spring Cloud Consul health check configuration

I'm running a Spring Boot application as a Docker container. This works fine so far, but it's giving me some head aches when trying to use Spring Cloud Consul as well. It reads the configuration from the Consul KVS just fine, but the health checks seem to be acting up.
The default health check uses the hostname of the docker container, for example http://users-microservice/health. Obviously this won't resolve when accessed from Consul.
No problem, the documentation mentions that you can use healthCheckPath in your bootstrap.yml file to configure it. This is what I have now:
spring:
application:
name: users-microservice
cloud:
consul:
host: myserver.com
port: 8500
config:
prefix: API-CONFIG
profileSeparator: '__'
discovery:
tags: users-microservice
healthCheckPath: http://myserver.com:${server.port}/status
healthCheckInterval: 30s
Unfortunately, this variable seems to be used in a very different manner from what I expected. This is what Consul is trying to reach:
Get http://users:18090http//myserver.com:18090/status: dial tcp: unknown port tcp/18090http
How can I fix this? Is there some undocumented configuration parameter that I should set?
Use spring.cloud.consul.discovery.healthCheckUrl=http://myserver.com:${server.port}/status
healthCheckPath only changes the path, not host and port.

Spring cloud config environment variable interpolation

I'm using spring-cloud-config in my Spring Boot project and I don't understand how to interpolate environment variables.
For example I have MYSQL_PASSWORD variable set in the config server (as environment variable) and I want to get it from other clients, without redefining the variable inside all of them. This is my config:
service.yml (in config-server)
spring:
datasource:
url: jdbc:mysql://mysql:3306/${MYSQL_DATABASE}?autoReconnect=true&useSSL=false
username: ${MYSQL_USER}
password: ${MYSQL_PASSWORD}
bootstrap.yml (into the client)
spring:
application:
name: event-service
cloud:
config:
uri: http://config-service:8888
fail-fast: true
If I start my services with this configuration, placeholder ${MYSQL_***} is not interpolated and I cannot connect to the database obviously.
What I have to do to make it work is to define environment variables like MYSQL_*** also in the client.
This is weird for me as I want config-server to be the central repository for everything. Do you have any advice?
I suggest you try to replace ${MYSQL_USER} and ${MYSQL_PASSWORD} with ${mysql.user} and ${mysql.password} - that way you'll be relying on Spring Boot's default property replacement.
Although I'm not sure that configuration server supports what you're trying to use, I've never tried a similar use case, please write back with a solution if the approach I suggested didn't work :)

Resources