Updates to OptionalArgs and addtional client filters

This commit is contained in:
spencergibb
2022-12-15 12:27:01 -05:00
parent ecdcfa4a2f
commit 2ada08039a
8 changed files with 133 additions and 118 deletions

View File

@@ -22,8 +22,11 @@ import org.junit.jupiter.api.BeforeAll;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.netflix.eureka.http.RestTemplateDiscoveryClientOptionalArgs;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import static org.assertj.core.api.Assertions.assertThat;
public class EurekaClientTest extends BaseCertTest {
private static final Log log = LogFactory.getLog(EurekaClientTest.class);
@@ -36,10 +39,7 @@ public class EurekaClientTest extends BaseCertTest {
public static void setupAll() {
server = startEurekaServer(EurekaClientTest.TestEurekaServer.class);
service = startService(server, EurekaClientTest.TestApp.class);
// Will use Jersey
// FIXME: 4.0
// assertThat(service.discoveryClientOptionalArgs())
// .isInstanceOf(DiscoveryClient.DiscoveryClientOptionalArgs.class);
assertThat(service.discoveryClientOptionalArgs()).isInstanceOf(RestTemplateDiscoveryClientOptionalArgs.class);
log.info("Successfully asserted that Jersey will be used");
waitForRegistration(() -> new EurekaClientTest().createEurekaClient());
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright 2013-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.netflix.eureka;
/**
* @author Dave Syer
*/
// FIXME: 4.0
public class MutableDiscoveryClientOptionalArgs {
} /*
* extends DiscoveryClientOptionalArgs {
*
* private Collection<ClientFilter> additionalFilters;
*
* @Override public void setAdditionalFilters(Collection<ClientFilter>
* additionalFilters) { additionalFilters = new LinkedHashSet<>(additionalFilters);
* this.additionalFilters = additionalFilters;
* super.setAdditionalFilters(additionalFilters); }
*
* public Collection<ClientFilter> getAdditionalFilters() { return
* this.additionalFilters; }
*
* }
*/

View File

@@ -26,6 +26,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
@@ -96,21 +97,6 @@ public class DiscoveryClientOptionalArgsConfiguration {
return new DefaultEurekaClientHttpRequestFactorySupplier(restTemplateTimeoutProperties);
}
// FIXME: 4.0
/*
* @Bean
*
* @ConditionalOnClass(name = "com.sun.jersey.api.client.filter.ClientFilter")
*
* @ConditionalOnMissingBean(value = AbstractDiscoveryClientOptionalArgs.class, search
* = SearchStrategy.CURRENT) public MutableDiscoveryClientOptionalArgs
* discoveryClientOptionalArgs(TlsProperties tlsProperties) throws
* GeneralSecurityException, IOException {
* logger.info("Eureka HTTP Client uses Jersey"); MutableDiscoveryClientOptionalArgs
* result = new MutableDiscoveryClientOptionalArgs(); setupTLS(result, tlsProperties);
* return result; }
*/
private static void setupTLS(AbstractDiscoveryClientOptionalArgs<?> args, TlsProperties properties)
throws GeneralSecurityException, IOException {
if (properties.isEnabled()) {
@@ -119,6 +105,19 @@ public class DiscoveryClientOptionalArgsConfiguration {
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = "jakarta.ws.rs.client.ClientRequestFilter")
@ConditionalOnBean(value = AbstractDiscoveryClientOptionalArgs.class, search = SearchStrategy.CURRENT)
static class DiscoveryClientOptionalArgsTlsConfiguration {
DiscoveryClientOptionalArgsTlsConfiguration(TlsProperties tlsProperties,
AbstractDiscoveryClientOptionalArgs optionalArgs) throws GeneralSecurityException, IOException {
logger.info("Eureka HTTP Client uses Jersey");
setupTLS(optionalArgs, tlsProperties);
}
}
@ConditionalOnMissingClass("com.sun.jersey.api.client.filter.ClientFilter")
@ConditionalOnClass(name = "org.springframework.web.reactive.function.client.WebClient")
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled", havingValue = "true")

View File

@@ -28,6 +28,7 @@ import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.EurekaClientConfig;
import com.netflix.discovery.shared.transport.jersey.TransportClientFactories;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@@ -501,12 +502,12 @@ class EurekaClientAutoConfigurationTests {
}
@Test
@Disabled
void basicAuth() {
TestPropertyValues
.of("server.port=8989", "eureka.client.serviceUrl.defaultZone=https://user:foo@example.com:80/eureka")
.applyTo(this.context);
setupContext(MockClientConfiguration.class);
// ApacheHttpClient4 http = this.context.getBean(ApacheHttpClient4.class);
// FIXME: ApacheHttpClient4 http = this.context.getBean(ApacheHttpClient4.class);
// Mockito.verify(http).addFilter(Matchers.any(HTTPBasicAuthFilter.class));
}
@@ -688,21 +689,6 @@ class EurekaClientAutoConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
protected static class MockClientConfiguration {
// FIXME: 4.0
/*
* @Bean public EurekaJerseyClient jerseyClient() { EurekaJerseyClient mock =
* Mockito.mock(EurekaJerseyClient.class);
* Mockito.when(mock.getClient()).thenReturn(apacheClient()); return mock; }
*
* @Bean public ApacheHttpClient4 apacheClient() { return
* Mockito.mock(ApacheHttpClient4.class); }
*/
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AutoServiceRegistrationProperties.class)
public static class AutoServiceRegistrationConfiguration {

View File

@@ -16,14 +16,17 @@
package org.springframework.cloud.netflix.eureka.config;
import org.junit.jupiter.api.Disabled;
import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.netflix.eureka.sample.EurekaSampleApplication;
import org.springframework.test.annotation.DirtiesContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Daniel Lavoie
*/
@@ -31,13 +34,12 @@ import org.springframework.test.annotation.DirtiesContext;
@SpringBootTest(classes = EurekaSampleApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
class JerseyOptionalArgsConfigurationTest {
// @Autowired
// private DiscoveryClientOptionalArgs optionalArgs;
@Autowired
private AbstractDiscoveryClientOptionalArgs optionalArgs;
@Test
@Disabled // FIXME: 4.0.0
void contextLoads() {
// assertThat(optionalArgs).isNotNull();
assertThat(optionalArgs).isNotNull();
}
}

View File

@@ -17,6 +17,11 @@
package org.springframework.cloud.netflix.eureka.server;
import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@@ -29,16 +34,21 @@ import com.netflix.discovery.converters.EurekaJacksonCodec;
import com.netflix.discovery.converters.wrappers.CodecWrapper;
import com.netflix.discovery.converters.wrappers.CodecWrappers;
import com.netflix.discovery.shared.transport.jersey.TransportClientFactories;
import com.netflix.discovery.shared.transport.jersey3.EurekaIdentityHeaderFilter;
import com.netflix.discovery.shared.transport.jersey3.EurekaJersey3Client;
import com.netflix.discovery.shared.transport.jersey3.EurekaJersey3ClientImpl;
import com.netflix.discovery.shared.transport.jersey3.Jersey3TransportClientFactories;
import com.netflix.eureka.DefaultEurekaServerContext;
import com.netflix.eureka.EurekaServerConfig;
import com.netflix.eureka.EurekaServerContext;
import com.netflix.eureka.EurekaServerIdentity;
import com.netflix.eureka.cluster.PeerEurekaNode;
import com.netflix.eureka.cluster.PeerEurekaNodes;
import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
import com.netflix.eureka.resources.DefaultServerCodecs;
import com.netflix.eureka.resources.ServerCodecs;
import com.netflix.eureka.transport.EurekaServerHttpClientFactory;
import com.netflix.eureka.transport.Jersey3DynamicGZIPContentEncodingFilter;
import com.netflix.eureka.transport.Jersey3EurekaServerHttpClientFactory;
import com.netflix.eureka.transport.Jersey3ReplicationClient;
import jakarta.servlet.Filter;
@@ -48,8 +58,12 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientRequestFilter;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.ext.Provider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.spi.Container;
@@ -101,6 +115,8 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@PropertySource("classpath:/eureka/server.properties")
public class EurekaServerAutoConfiguration implements WebMvcConfigurer {
private static final Log log = LogFactory.getLog(EurekaServerAutoConfiguration.class);
/**
* List of packages containing Jersey resources required by the Eureka server.
*/
@@ -162,7 +178,6 @@ public class EurekaServerAutoConfiguration implements WebMvcConfigurer {
return codec == null ? CodecWrappers.getCodec(CodecWrappers.XStreamXml.class) : codec;
}
// FIXME: 4.0
@Bean
@ConditionalOnMissingBean
public ReplicationClientAdditionalFilters replicationClientAdditionalFilters() {
@@ -374,7 +389,7 @@ public class EurekaServerAutoConfiguration implements WebMvcConfigurer {
static class RefreshablePeerEurekaNodes extends PeerEurekaNodes
implements ApplicationListener<EnvironmentChangeEvent> {
private ReplicationClientAdditionalFilters replicationClientAdditionalFilters;
/* for testing */ ReplicationClientAdditionalFilters replicationClientAdditionalFilters;
RefreshablePeerEurekaNodes(final PeerAwareInstanceRegistry registry, final EurekaServerConfig serverConfig,
final EurekaClientConfig clientConfig, final ServerCodecs serverCodecs,
@@ -386,11 +401,8 @@ public class EurekaServerAutoConfiguration implements WebMvcConfigurer {
@Override
protected PeerEurekaNode createPeerEurekaNode(String peerEurekaNodeUrl) {
Jersey3ReplicationClient replicationClient = Jersey3ReplicationClient.createReplicationClient(serverConfig,
serverCodecs, peerEurekaNodeUrl);
// FIXME: 4.0
// this.replicationClientAdditionalFilters.getFilters().forEach(replicationClient::addReplicationClientFilter);
Jersey3ReplicationClient replicationClient = createReplicationClient(serverConfig, serverCodecs,
peerEurekaNodeUrl, this.replicationClientAdditionalFilters.getFilters());
String targetHost = hostFromUrl(peerEurekaNodeUrl);
if (targetHost == null) {
@@ -399,6 +411,64 @@ public class EurekaServerAutoConfiguration implements WebMvcConfigurer {
return new PeerEurekaNode(registry, targetHost, peerEurekaNodeUrl, replicationClient, serverConfig);
}
// FIXME: 4.0 update Jersey3ReplicationClient.createReplicationClient to handle
// additional filters
private static Jersey3ReplicationClient createReplicationClient(EurekaServerConfig config,
ServerCodecs serverCodecs, String serviceUrl, Collection<ClientRequestFilter> additionalFilters) {
String name = Jersey3ReplicationClient.class.getSimpleName() + ": " + serviceUrl + "apps/: ";
EurekaJersey3Client jerseyClient;
try {
String hostname;
try {
hostname = new URL(serviceUrl).getHost();
}
catch (MalformedURLException e) {
hostname = serviceUrl;
}
String jerseyClientName = "Discovery-PeerNodeClient-" + hostname;
EurekaJersey3ClientImpl.EurekaJersey3ClientBuilder clientBuilder = new EurekaJersey3ClientImpl.EurekaJersey3ClientBuilder()
.withClientName(jerseyClientName).withUserAgent("Java-EurekaClient-Replication")
.withEncoderWrapper(serverCodecs.getFullJsonCodec())
.withDecoderWrapper(serverCodecs.getFullJsonCodec())
.withConnectionTimeout(config.getPeerNodeConnectTimeoutMs())
.withReadTimeout(config.getPeerNodeReadTimeoutMs())
.withMaxConnectionsPerHost(config.getPeerNodeTotalConnectionsPerHost())
.withMaxTotalConnections(config.getPeerNodeTotalConnections())
.withConnectionIdleTimeout(config.getPeerNodeConnectionIdleTimeoutSeconds());
if (serviceUrl.startsWith("https://") && "true"
.equals(System.getProperty("com.netflix.eureka.shouldSSLConnectionsUseSystemSocketFactory"))) {
clientBuilder.withSystemSSLConfiguration();
}
jerseyClient = clientBuilder.build();
}
catch (Throwable e) {
throw new RuntimeException("Cannot Create new Replica Node :" + name, e);
}
String ip = null;
try {
ip = InetAddress.getLocalHost().getHostAddress();
}
catch (UnknownHostException e) {
log.warn("Cannot find localhost ip", e);
}
Client jerseyApacheClient = jerseyClient.getClient();
jerseyApacheClient.register(new Jersey3DynamicGZIPContentEncodingFilter(config));
for (ClientRequestFilter filter : additionalFilters) {
jerseyApacheClient.register(filter);
}
EurekaServerIdentity identity = new EurekaServerIdentity(ip);
jerseyApacheClient.register(new EurekaIdentityHeaderFilter(identity));
return new Jersey3ReplicationClient(jerseyClient, serviceUrl);
}
@Override
public void onApplicationEvent(final EnvironmentChangeEvent event) {
if (shouldUpdate(event.getKeys())) {

View File

@@ -19,21 +19,20 @@ package org.springframework.cloud.netflix.eureka.server;
import java.util.Collection;
import java.util.LinkedHashSet;
// FIXME: 4.0
//import com.sun.jersey.api.client.filter.ClientFilter;
import jakarta.ws.rs.client.ClientRequestFilter;
/**
* @author Yuxin Bai
*/
public class ReplicationClientAdditionalFilters {
private final Collection<?> filters;
private final Collection<ClientRequestFilter> filters;
public ReplicationClientAdditionalFilters(Collection<?> filters) {
public ReplicationClientAdditionalFilters(Collection<ClientRequestFilter> filters) {
this.filters = new LinkedHashSet<>(filters);
}
public Collection<?> getFilters() {
public Collection<ClientRequestFilter> getFilters() {
return this.filters;
}

View File

@@ -16,16 +16,20 @@
package org.springframework.cloud.netflix.eureka.server;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collections;
import com.netflix.eureka.cluster.PeerEurekaNodes;
import org.junit.jupiter.api.Disabled;
import jakarta.ws.rs.client.ClientRequestContext;
import jakarta.ws.rs.client.ClientRequestFilter;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration.RefreshablePeerEurekaNodes;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;
@@ -34,7 +38,6 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Yuxin Bai
*/
@Disabled // FIXME: 4.0
@SpringBootTest(classes = RefreshablePeerEurekaNodesWithCustomFiltersTests.Application.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, value = { "spring.application.name=eureka",
"server.contextPath=/context", "management.security.enabled=false" })
@@ -47,18 +50,13 @@ class RefreshablePeerEurekaNodesWithCustomFiltersTests {
void testCustomPeerNodesShouldTakePrecedenceOverDefault() {
assertThat(peerEurekaNodes instanceof RefreshablePeerEurekaNodes)
.as("PeerEurekaNodes should be an instance of RefreshablePeerEurekaNodes").isTrue();
RefreshablePeerEurekaNodes refreshablePeerEurekaNodes = (RefreshablePeerEurekaNodes) peerEurekaNodes;
// ReplicationClientAdditionalFilters filters =
// getField(RefreshablePeerEurekaNodes.class,
// (RefreshablePeerEurekaNodes) peerEurekaNodes,
// "replicationClientAdditionalFilters");
// assertThat(filters.getFilters())
// .as("PeerEurekaNodes'should have only one filter set on
// replicationClientAdditionalFilters").hasSize(1);
// assertThat(filters.getFilters().iterator().next() instanceof
// Application.CustomClientFilter)
// .as("The type of the filter should be CustomClientFilter as user declared
// so").isTrue();
ReplicationClientAdditionalFilters filters = refreshablePeerEurekaNodes.replicationClientAdditionalFilters;
assertThat(filters.getFilters())
.as("PeerEurekaNodes'should have only one filter set on replicationClientAdditionalFilters").hasSize(1);
assertThat(filters.getFilters().iterator().next() instanceof Application.CustomClientFilter)
.as("The type of the filter should be CustomClientFilter as user declared so").isTrue();
}
private static <T, R> R getField(Class<T> clazz, T target, String fieldName) {
@@ -74,19 +72,19 @@ class RefreshablePeerEurekaNodesWithCustomFiltersTests {
@EnableEurekaServer
protected static class Application {
// FIXME: 4.0
/*
* @Bean public ReplicationClientAdditionalFilters customFilters() { return new
* ReplicationClientAdditionalFilters(Collections.singletonList(new
* CustomClientFilter())); }
*
* protected class CustomClientFilter extends ClientFilter {
*
* @Override public ClientResponse handle(ClientRequest cr) throws
* ClientHandlerException { return getNext().handle(cr); }
*
* }
*/
@Bean
public ReplicationClientAdditionalFilters customFilters() {
return new ReplicationClientAdditionalFilters(Collections.singletonList(new CustomClientFilter()));
}
protected class CustomClientFilter implements ClientRequestFilter {
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
// noop
}
}
}