Error while using custom loadbalancer for spring cloud loadbalancer with healthcheck configuration - spring

I am using a static list (SimpleDiscoveryClient) to loadbalance using spring cloud loadbalancer. Using StickySession Loadbalancer rule in https://github.com/fitzoh/spring-cloud-commons/blob/e10997b6141ff560479ef7065c3547f1f59360c8/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/core/StickySessionLoadBalancer.java.
My WebClientConfig class:
#Configuration
#LoadBalancerClient(name = "testservice", configuration = CustomLoadBalancerConfiguration.class)
public class WebClientConfig {
#LoadBalanced
#Bean
WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
}
Custom LoadBalancer Configuration class:
public class CustomLoadBalancerConfiguration {
#Bean
ReactorLoadBalancer<ServiceInstance> StickySessionLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new StickySessionLoadBalancer(loadBalancerClientFactory
.getLazyProvider(name, ServiceInstanceListSupplier.class),
name);
}
#Bean
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withHealthChecks()
.build(context);
}
}
Posting my yml here :
spring:
application:
name: sample
cloud:
discovery:
client:
health-indicator:
enabled: false
simple:
instances:
testservice:
- uri: http://localhost:8082
- uri: http://localhost:8081
loadbalancer:
configurations: health-check
cache:
enabled: false
health-check:
path:
default: /actuator/health
interval: 10000
gateway:
routes:
- id: testrouting
path: /user/*
uri: lb://testservice
predicates:
- Method=GET,POST
- Path=/user/**
It's all according to the official documentation. But with the customloadbalancer rule (Stickysession Loadbalancer), the healthchecks to servers are not happening to checkif the servers are alive or not. The server list is always empty (all servers are marked as not alive).

Related

Spring Cloud Config - Vault and JDBC backend with JDBC creds in Vault

I am attempting to modify our current Spring Cloud Config server which has only a JDBC backend to include a Vault backend in order make the JDBC connection credentials secret.
VAULT:
Listener 1: tcp (addr: "127.0.0.1:8400", cluster address: "127.0.0.1:8401", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
C:\apps\HashiCorp>vault kv get secret/my-secrets
=============== Data ===============
Key Value
--- -----
spring.datasource.password yadayadayada
spring.datasource.username cobar
bootstrap.yml
server:
port: 8888
spring:
application:
name: config-server
cloud:
config:
allowOverride: true
server:
jdbc:
sql: SELECT prop_key, prop_value from CloudProperties where application=? and profile=? and label=?
order: 2
#https://cloud.spring.io/spring-cloud-config/reference/html/#vault-backend
vault:
scheme: http
host: localhost
port: 8400
defaultKey: my-secrets
order: 1
application.yml
spring:
main:
banner-mode: off
allow-bean-definition-overriding: true
datasource:
url: jdbc:mysql://localhost/bootdb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false
#username: cobar
#password: yadayadayada
driverClassName: com.mysql.jdbc.Driver
hikari:
connection-timeout: 60000
maximum-pool-size: 5
cloud:
vault:
scheme: http
host: localhost
port: 8400
defaultKey: my-secrets
token: root.RIJQjZ4jRZUS8mskzfCON88K
The spring.datasource username and password are not being retrieved from the vault.
2021-12-01 12:43:39.927 INFO 5992 --- [ restartedMain]: The following profiles are active: jdbc,vault
2021-12-01 12:43:46.123 ERROR 5992 --- [ restartedMain] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Exception during pool initialization.
Login failed for user ''. ClientConnectionId:a32
Move properties from bootstrap to application context.
Call Vault endpoint to obtain secrets and use these to configure Datasource to JDBC backend.
#Slf4j
#SpringBootApplication
#EnableConfigServer
public class ConfigServerApplication {
public static final String VAULT_URL_FRMT = "%s://%s:%s/v1/secret/%s";
#Autowired
private Environment env;
public static void main(String[] args) {
SpringApplication app = new SpringApplication(ConfigServerApplication.class);
app.addListeners(new ApplicationPidFileWriter());
app.addListeners(new WebServerPortFileWriter());
app.run(args);
}
#Order(1)
#Bean("restTemplate")
public RestTemplate restTemplate() {
return new RestTemplate();
}
#Configuration
public class JdbcConfig {
#Autowired
private RestTemplate restTemplate;
#Bean
public DataSource getDataSource() {
Secrets secrets = findSecrets();
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.url(secrets.getData().get("spring.datasource.url"));
dataSourceBuilder.username(secrets.getData().get("spring.datasource.username"));
dataSourceBuilder.password(secrets.getData().get("spring.datasource.password"));
return dataSourceBuilder.build();
}
private Secrets findSecrets() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("X-Vault-Token", env.getProperty("spring.cloud.vault.token"));
HttpEntity request = new HttpEntity(httpHeaders);
String url = String.format(VAULT_URL_FRMT,
env.getProperty("spring.cloud.vault.scheme"),
env.getProperty("spring.cloud.vault.host"),
env.getProperty("spring.cloud.vault.port"),
env.getProperty("spring.cloud.vault.defaultKey")
);
return restTemplate.exchange(url, HttpMethod.GET, request, Secrets.class, 1).getBody();
}
}
}
#Getter
#Setter
public class Secrets implements Serializable {
private String request_id;
private String lease_id;
private boolean renewable;
private Duration lease_duration;
private Map<String, String> data;
}
Now you have a Cloud Config with a JDBC backend you can keep the Database properties secret.

Zuul throwing 404 No meesage Available error

I have my below app (microservices) which is successfully registered to Eureka server.I t has below Rest end point
#Controller
#RequestMapping("v1/base/")
public class PersonController {
#PostMapping
#RequestMapping(value="/personid")
public ResponseEntity< ?> getPersonList(){
return ResponseEntity.ok("All person list");
}
The properties file for person-application
eureka:
instance:
appname: person-application
client:
enabled: true
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka/
My zuul server yml file config is is .
server:
port:9000
servlet:
contextPath: /zuulapp
zuul:
routes:
person:
path: /v1/base/**
serviceId: person-application
When i call hit the rest point localhost:9000/zuulapp/person/personid i get the below error.How do i resolve this error
{
"timestamp":"2019-10-08T12:42:09.479+0000",
"status":404,
"error":"Internal Server Error",
"message":"No Message available"
"path" : "/zuulapp/person/personid"
}
Since the registered path in the zuul of the application is "/v1/base/**"
try this one: delete the contextpath properties then replace it with zuul.prefix properties.
server:
port:9000
zuul:
prefix: /zuulapp
routes:
person:
path: /person/**
serviceId: person-application
Now try checking this endpoint:
localhost:9000/zuulapp/person/v1/base/personid
try this in the controller class:
#RestController
#RequestMapping("/v1/base/")
public class PersonController {
#GetMapping(value="/personid")
public ResponseEntity< ?> getPersonList(){
return ResponseEntity.ok("All person list");
}

Spring Cloud Gateway - Unable to find GatewayFilterFactory with name [Filter_Name]

I have a spring cloud gateway application. I am trying to setup a gateway filter. The Spring Boot version is 2.3.4.RELEASE Here are the dependencies:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation platform(SpringBootPlugin.BOM_COORDINATES)
implementation platform('org.springframework.cloud:spring-cloud-dependencies:Hoxton.SR8')
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.cloud:spring-cloud-starter-sleuth'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
}
Here is the configutraion for the gateway client
server:
port: 8081
spring:
cloud:
gateway:
routes:
- id: onboard_redirect
uri: http://localhost:8080/api/v1/onboard
predicates:
- Path=/api/v1/onboard
filters:
- name: MyLogging
args:
baseMessage: My Custom Message
preLogger: true
postLogger: true
Here is my filter class:
#Component
public class MyLoggingGatewayFilterFactory extends AbstractGatewayFilterFactory<MyLoggingGatewayFilterFactory.Config> {
final Logger logger =
LoggerFactory.getLogger(MyLoggingGatewayFilterFactory.class);
public MyLoggingGatewayFilterFactory() {
super(Config.class);
}
#Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
// Pre-processing
if (config.preLogger) {
logger.info("Pre GatewayFilter logging: "
+ config.baseMessage);
}
return chain.filter(exchange)
.then(Mono.fromRunnable(() -> {
// Post-processing
if (config.postLogger) {
logger.info("Post GatewayFilter logging: "
+ config.baseMessage);
}
}));
};
}
public static class Config {
public String baseMessage;
public boolean preLogger;
public boolean postLogger;
}
}
Everything works without configuring the filter but when I configure the filter I get follwing error:
reactor.core.Exceptions$ErrorCallbackNotImplemented: java.lang.IllegalArgumentException: Unable to find GatewayFilterFactory with name MyLogging
Caused by: java.lang.IllegalArgumentException: Unable to find GatewayFilterFactory with name MyLogging
what I am doing wrong here?
The filter class is MyLoggingGatewayFilterFactory, not MyLogging as you set in your properties.
Try to the following modification in your application.yml file:
filters:
- name: MyLoggingGatewayFilterFactory
Add this dependency in the application.properties file.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-
resilience4j</artifactId>
</dependency>

Zuul Implementing WeightedResponseTimeRule Error - VIP address for client null is null

I'm encountering this VIP address null white implementing weightedResponseTimeRule for my Zuul gateway.
Did i do it correctly? implementing a config that will implement weightedRule.
I want to route my request to my 2 or more instance.
Error creating bean with name 'ribbonServerList' defined in org.springframework.cloud.netflix.ribbon.eureka.EurekaRibbonClientConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.netflix.loadbalancer.ServerList]: Factory method 'ribbonServerList' threw exception; nested exception is java.lang.NullPointerException: VIP address for client null is null
Currently my Config for Ribbon
#Configuration
public class GatewayRibbonConfiguration {
#Bean
public IClientConfig ribbonClientConfig(){
return new DefaultClientConfigImpl();
}
#Bean
public IPing ribbonPing(IClientConfig config) {
return new PingUrl();
}
#Bean
public IRule ribbonRule(IClientConfig config) {
return new WeightedResponseTimeRule();
}
}
Application
#SpringBootApplication
#EnableDiscoveryClient
#EnableZuulProxy
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
#Bean
public Prefilter prefilter(){
return new Prefilter();
}
}
bootstrap.yml
spring:
application:
name: gateway
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
my properties
server:
port: 8080
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 20000
ribbon:
ReadTimeout: 20000
ConnectTimeout: 20000
zuul:
prefix: /api
ignoredServices: '*'
host:
connect-timeout-millis: 20000
socket-timeout-millis: 20000
routes:
kicks-service:
path: /kicks/**
serviceId: kicks-service
stripPrefix: false
sensitiveHeaders:
kicks-inventory:
path: /inventory/**
serviceId: kicks-inventory
stripPrefix: false
sensitiveHeaders:

Issues with Spring cloud consul config while starting a Groovy app through Spring cloud cli

I am Exploring Consul for discovery and config server. I have added the required dependencies and yml file is set up. When i try to start the server using spring cloud cli (Spring run .) I am getting the below error which i am unable to resolve. Any help is appreciated.
Error :
"A component required a bean named 'configServerRetryInterceptor' that could >not be found."
I tried to define this bean but when i start the app through spring cloud cli it is not recognizing it.
Please see the code below
App.groovy
#Grab("spring-cloud-starter-consul-config")
#Grab("spring-cloud-starter-consul-discovery")
#EnableDiscoveryClient
#EnableCircuitBreaker
#RestController
#Log
class Application{
#Autowired
Greeter greeter
int counter = 0
#RequestMapping(value = "/counter", produces = "application/json")
String produce() {
counter++
log.info("Produced a value: ${counter}")
"{\"value\": ${counter}}"
}
#RequestMapping("/")
String home() {
"${greeter.greeting} World!"
}
#RequestMapping(value = '/questions/{questionId}')
#HystrixCommand(fallbackMethod = "defaultQuestion")
def question(#PathVariable String questionId) {
if(Math.random() < 0.5) {
throw new RuntimeException('random');
}
[questionId: questionId]
}
def defaultQuestion(String questionId) {
[questionId: 'defaultQuestion']
}
}
#Component
#RefreshScope
class Greeter {
#Value('${greeting}')
String greeting
}
bootstrap.yml
consul:
host: localhost
port: 8500
config:
enabled: true
prefix: config
defaultContext: master
profileSeparator: '::'
format: FILES
discovery:
instanceId: ${spring.application.name}:${spring.application.instance_id:${random.value}}
health-check-url: http://127.0.0.1:${server.port}/health
This issue was due to unwanted dependencies being pulled.
Explicitly disabling spring cloud config and spring cloud discovery fixed it.
spring:
cloud:
config:
enabled: false
discovery:
enabled: false
serviceId: CONFIG
eureka:
client:
register-with-eureka: false
fetch-registry: false

Resources