What's the use of matchOptionalTrailingSeparator in Spring Cloud Gateway Predicate - spring

From the doc about Spring Cloud that Spring.io given:
The Path Route Predicate Factory takes two parameters: a list of Spring PathMatcher patterns and an optional flag called matchOptionalTrailingSeparator.
It mentions an optional flag matchOptionalTrailingSeparator without more description.
What is the use of this flag and how to use this flag?
Thanks

The parameter matchOptionalTrailingSeparator is used to determine whether the given Path predicate should also match the requests with the trailing slash / too.
By default, the value of this is true.
For e.g. below route
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Path=/foo/{segment}
will match both the request /foo/{segment} and /foo/{segment}/
But if it's written as:
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Path=/foo/{segment},false
It will not match the requests with trailing slash / i.e. it will only match /foo/{segment} and not match /foo/{segment}/

Related

spring bean override with custom implementation

I want to override a spring implantation and use my own bean. For example CompositeEnvironmentRepository which is a spring bean, i want to write my own. One way is to delete this bean from the spring jar file and provide my own jar file with my custom bean. Is there any better way to do this. Please suggest.
spring:
application:
name: spring-cloud-server
profiles:
active: vault,git
cloud:
vault:
authentication: CERT
config:
server:
failOnCompositeError: false
vault:
host: hostname
port: 490
scheme: https
backend: secret
defaultKey:
kvVersion: 2
order: 2
skipSslValidation: false
authentication: CERT
git:
uri: repo-url
order: 1
skip-ssl-validation: false
force-pull: true
repos:
dev:
pattern:
- '*/dev'
uri: url
searchPaths: '${somepath}'
The documentation describes how to provide your own environment repository. You probably don't want to override the entire CompositeEnvironmentRepository, but create your own EnvironmentRepository that provides the specific properties you need. Spring will include yours as part of the "composite".
https://cloud.spring.io/spring-cloud-config/multi/multi__spring_cloud_config_server.html#_custom_composite_environment_repositories

Quarkus application - add base path to OpenAPI definition

I'm currently working on a Quarkus based API that is due to be hosted on an API gateway that requires our application to be running with a base-path and I found out that by setting quarkus.resteasy.path in application.properties I can run the application with a base-path and it is being added to the specification automatically.
I am generating an OpenAPI 3 specification by using org.eclipse.microprofile.openapi.annotations. My problem is that in the specification this base-path is added to every single operation. I am instead trying to only apply the base-path within the servers declaration basically like the equivalent of what basePath used to be in OpenAPI 2.0.
Current outcome:
servers:
- url: https://dev.example.com
description: Development
- url: https://example.com
description: Production
security:
- jwt: []
paths:
/api/capacity/availability:
get:
...
/api/capacity/consume:
post:
...
Desired outcome:
servers:
- url: https://dev.example.com/api
description: Development
- url: https://example.com/api
description: Production
security:
- jwt: []
paths:
/capacity/availability:
get:
...
/capacity/consume:
post:
...
Any help would be appreciated.
You can also use config to set the servers: quarkus.smallrye-openapi.servers
See https://quarkus.io/guides/openapi-swaggerui#quarkus-smallrye-openapi_quarkus.smallrye-openapi.servers

Spring Actuator Metrics preserve "dot" in tags

I'm creating tags in my metrics exporter, in this way:
metrics:
export:
elastic:
host: "xx"
index: "metricbeat-k8s-apps"
user-name: "elastic"
password: "xx"
step: 30s
connect-timeout: 10s
tags:
cluster: ${CLUSTER}
kubernetes.pod.name: ${POD_NAME}
kubernetes.namespace: ${POD_NAMESPACE}
But I don't know why "kubernetes.pod.name" is converted to "kubernetes_pod_name", how can I preserve the dots ?
The word separator in Micrometer is 'dot' (see docs), according to the Elastic naming conventions, the word separator is 'underscore' in Elastic. In Micrometer, every registry has a NamingConvention. For Elastic, it is ElasticNamingConvention.
As you can see in that class, the default naming convention is snake_case:
public ElasticNamingConvention() {
this(NamingConvention.snakeCase);
}
You can see how ElasticMeterRegistry uses this naming convention, but you can provide your own, please check the docs.

Spring cloud gateway refresh with RewritePath fails

I'm running a spring cloud gateway instance that relies on spring cloud configuration server. My application starts up with the given following configuration.
cloud:
gateway:
routes:
- id: route-foo
uri: lb://foo
predicates:
- Path=/api/foo/**
filters:
- name: RewritePath
args:
regexp: "/api/foo/(?<remaining>.*)"
replacement: "/${remaining}"
Say I make a modification to my configuration and add an additional route below
- id: route-bar
uri: lb://bar
predicates:
- Path=/api/bar/**
filters:
- name: RewritePath
args:
regexp: "/api/bar/(?<remaining>.*)"
replacement: "/${remaining}"
Executing a POST to http://localhost:8080/actuator/refresh returns the following error.
500 Server Error for HTTP POST "/actuator/refresh" (Encoded)
java.lang.IllegalArgumentException: Could not resolve placeholder 'remaining' in value "/${remaining}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:178)
It appears that spring is trying to parse my RewritePath replacement and substitute it with environment variables. What are my options?
You're running into spring trying to replace variables in your configuration.
There are two solutions
Escape the replacement syntax (Preferred)
change replacement: "/${remaining}"
to replacement: "/$\\{remaining}"
The RewriteGatewayFilterFactory does a replace on the configuration before running the filter.
Enable ignoreUnresolvableNestedPlaceholders
#Bean
#Primary
public StandardReactiveWebEnvironment standardReactiveWebEnvironmentCustomizer(StandardReactiveWebEnvironment environment) {
environment.setIgnoreUnresolvableNestedPlaceholders(true);
return environment;
}
This will leave all unresolvable placeholders alone in your configuration and not fail during the refresh. I would recommend against this approach as it may end up delaying some issues into runtime if you're relying on a field to be populated correctly.
Theoretically you should be able to accomplish this same functionality with the PropertySourcesPlaceholderConfigurer, I had a hard time getting that to cooperate.

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.

Resources