mirror of
https://github.com/spring-cloud/spring-cloud-netflix.git
synced 2026-09-19 00:29:01 +00:00
Compare commits
36
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa45392a9a | ||
|
|
307b93bf5a | ||
|
|
f21d0046cd | ||
|
|
de6d506e9a | ||
|
|
2a8b7ed054 | ||
|
|
79a2eb8c4f | ||
|
|
dbb36fb0ed | ||
|
|
f8ed5c4163 | ||
|
|
47d3f7133c | ||
|
|
a74d8f966e | ||
|
|
5113f0abf3 | ||
|
|
99b8d2c6d4 | ||
|
|
3ef81ba9cd | ||
|
|
c7885631ed | ||
|
|
bb15b7f40e | ||
|
|
c97bd250af | ||
|
|
4b101efe19 | ||
|
|
61d5f5f9fb | ||
|
|
6b6173de3a | ||
|
|
4536954aca | ||
|
|
817ea2c88a | ||
|
|
1754585fc0 | ||
|
|
0bebfd1e3d | ||
|
|
a0c95db99e | ||
|
|
ad002b4da2 | ||
|
|
fb088832db | ||
|
|
3d30846108 | ||
|
|
3c84f2ec04 | ||
|
|
479f10e379 | ||
|
|
1bc989c5ce | ||
|
|
cf81e327ad | ||
|
|
35ef348fe9 | ||
|
|
45ddfdfb7c | ||
|
|
8ae4950200 | ||
|
|
d7275b888b | ||
|
|
ed9ca444c8 |
@@ -28,6 +28,6 @@ jobs:
|
||||
cache: 'maven'
|
||||
- name: Build with Maven
|
||||
run: ./mvnw clean install -B -U -P sonar
|
||||
- uses: codecov/codecov-action@v3
|
||||
- uses: codecov/codecov-action@v4
|
||||
with:
|
||||
fail_ci_if_error: false
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
antora:
|
||||
extensions:
|
||||
- '@springio/antora-extensions/partial-build-extension'
|
||||
# atlas-extension must be before latest-version-extension so latest versions are applied to imported versions
|
||||
- '@antora/atlas-extension'
|
||||
- require: '@springio/antora-extensions/latest-version-extension'
|
||||
- require: '@springio/antora-extensions/inject-collector-cache-config-extension'
|
||||
- '@antora/collector-extension'
|
||||
- '@antora/atlas-extension'
|
||||
- require: '@springio/antora-extensions/root-component-extension'
|
||||
root_component_name: 'cloud-netflix'
|
||||
- '@springio/antora-extensions/static-page-extension'
|
||||
@@ -36,4 +37,4 @@ runtime:
|
||||
format: pretty
|
||||
ui:
|
||||
bundle:
|
||||
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.2/ui-bundle.zip
|
||||
url: https://github.com/spring-io/antora-ui-spring/releases/download/v0.4.13/ui-bundle.zip
|
||||
|
||||
@@ -604,6 +604,17 @@ when running a Eureka server you must include these dependencies in your POM or
|
||||
|
||||
Spring Cloud Netflix Eureka Server does not support Spring AOT transformations or native images.
|
||||
|
||||
=== Metrics
|
||||
|
||||
`EurekaInstanceMonitor` listens to events related to Eureka instance registration and creates/updates `Gauge`s for Eureka instance information in Micrometer's `MeterRegistry`. By default, this behavior is disabled. If you want to enable it, you need to set `eureka.server.metrics.enabled` to `true`.
|
||||
|
||||
By default, the `Gauge`s are named `eureka.server.instances` and have the following tags:
|
||||
|
||||
- `application`: application name
|
||||
- `status`: instance status (`UP`, `DOWN`, `STARTING`, `OUT_OF_SERVICE`, `UNKNOWN`, see: `com.netflix.appinfo.InstanceInfo.InstanceStatus`)
|
||||
|
||||
You can add additional tags by injecting your own implementation of `EurekaInstanceTagsProvider`.
|
||||
|
||||
== Configuration properties
|
||||
|
||||
To see the list of all Spring Cloud Netflix related configuration properties please check link:appendix.html[the Appendix page].
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
|eureka.instance.a-s-g-name | | Gets the AWS autoscaling group name associated with this instance. This information is specifically used in an AWS environment to automatically put an instance out of service after the instance is launched and it has been disabled for traffic..
|
||||
|eureka.instance.app-group-name | | Get the name of the application group to be registered with eureka.
|
||||
|eureka.instance.appname | `+++unknown+++` | Get the name of the application to be registered with eureka.
|
||||
|eureka.instance.async-client-initialization | `+++false+++` | If true the EurekaClient will be initialized asynchronously when the InstanceRegistry bean is created.
|
||||
|eureka.instance.data-center-info | | Returns the data center this instance is deployed. This information is used to get some AWS specific instance information if the instance is deployed in AWS.
|
||||
|eureka.instance.default-address-resolution-order | `+++[]+++` |
|
||||
|eureka.instance.environment | |
|
||||
@@ -127,6 +128,7 @@
|
||||
|eureka.server.max-threads-for-peer-replication | `+++20+++` |
|
||||
|eureka.server.max-threads-for-status-replication | `+++1+++` |
|
||||
|eureka.server.max-time-for-replication | `+++30000+++` |
|
||||
|eureka.server.metrics.enabled | `+++false+++` | Indicates whether the metrics should be enabled for eureka instances.
|
||||
|eureka.server.min-available-instances-for-peer-replication | `+++-1+++` |
|
||||
|eureka.server.min-threads-for-peer-replication | `+++5+++` |
|
||||
|eureka.server.min-threads-for-status-replication | `+++1+++` |
|
||||
@@ -173,7 +175,7 @@
|
||||
|eureka.server.use-read-only-response-cache | `+++true+++` |
|
||||
|eureka.server.wait-time-in-ms-when-sync-empty | `+++0+++` |
|
||||
|eureka.server.xml-codec-name | |
|
||||
|spring.cloud.compatibility-verifier.compatible-boot-versions | `+++3.2.x+++` | Default accepted versions for the Spring Boot dependency. You can set {@code x} for the patch version if you don't want to specify a concrete value. Example: {@code 3.4.x}
|
||||
|spring.cloud.compatibility-verifier.compatible-boot-versions | | Default accepted versions for the Spring Boot dependency. You can set {@code x} for the patch version if you don't want to specify a concrete value. Example: {@code 3.4.x}
|
||||
|spring.cloud.compatibility-verifier.enabled | `+++false+++` | Enables creation of Spring Cloud compatibility verification.
|
||||
|spring.cloud.config.allow-override | `+++true+++` | Flag to indicate that {@link #isOverrideSystemProperties() systemPropertiesOverride} can be used. Set to false to prevent users from changing the default accidentally. Default true.
|
||||
|spring.cloud.config.initialize-on-context-refresh | `+++false+++` | Flag to initialize bootstrap configuration on context refresh event. Default false.
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.1.1-SNAPSHOT</version>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.1.1-SNAPSHOT</version>
|
||||
<version>4.1.2</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Netflix</name>
|
||||
<description>Spring Cloud Netflix</description>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-build</artifactId>
|
||||
<version>4.1.1-SNAPSHOT</version>
|
||||
<version>4.1.2</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
<scm>
|
||||
@@ -21,9 +21,9 @@
|
||||
</scm>
|
||||
<properties>
|
||||
<bintray.package>netflix</bintray.package>
|
||||
<spring-cloud-commons.version>4.1.1-SNAPSHOT</spring-cloud-commons.version>
|
||||
<spring-cloud-config.version>4.1.1-SNAPSHOT</spring-cloud-config.version>
|
||||
<testcontainers.version>1.19.3</testcontainers.version>
|
||||
<spring-cloud-commons.version>4.1.3</spring-cloud-commons.version>
|
||||
<spring-cloud-config.version>4.1.2</spring-cloud-config.version>
|
||||
<testcontainers.version>1.19.7</testcontainers.version>
|
||||
<mockserverclient.version>5.15.0</mockserverclient.version>
|
||||
|
||||
<!-- Sonar -->
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-dependencies-parent</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>4.1.1-SNAPSHOT</version>
|
||||
<version>4.1.2</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-dependencies</artifactId>
|
||||
<version>4.1.1-SNAPSHOT</version>
|
||||
<version>4.1.2</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>spring-cloud-netflix-dependencies</name>
|
||||
<description>Spring Cloud Netflix Dependencies</description>
|
||||
<properties>
|
||||
<eureka.version>2.0.1</eureka.version>
|
||||
<eureka.version>2.0.2</eureka.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.1.1-SNAPSHOT</version>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-eureka-client-tls-tests</artifactId>
|
||||
|
||||
+30
-1
@@ -24,8 +24,11 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration;
|
||||
import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier;
|
||||
@@ -76,7 +79,7 @@ public class RestTemplateEurekaClientTest extends BaseCertTest {
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier)
|
||||
throws GeneralSecurityException, IOException {
|
||||
return configuration.restTemplateDiscoveryClientOptionalArgs(tlsProperties,
|
||||
eurekaClientHttpRequestFactorySupplier);
|
||||
eurekaClientHttpRequestFactorySupplier, new RestTemplateBuilderObjectProvider());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -88,4 +91,30 @@ public class RestTemplateEurekaClientTest extends BaseCertTest {
|
||||
|
||||
}
|
||||
|
||||
private static class RestTemplateBuilderObjectProvider implements ObjectProvider<RestTemplateBuilder> {
|
||||
|
||||
private final RestTemplateBuilder builder = new RestTemplateBuilder();
|
||||
|
||||
@Override
|
||||
public RestTemplateBuilder getObject(Object... args) throws BeansException {
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestTemplateBuilder getIfAvailable() throws BeansException {
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestTemplateBuilder getIfUnique() throws BeansException {
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestTemplateBuilder getObject() throws BeansException {
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.1.1-SNAPSHOT</version>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-eureka-client</artifactId>
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2023 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -103,6 +103,7 @@ import static org.springframework.cloud.commons.util.IdUtils.getDefaultInstanceI
|
||||
* @author Daniel Lavoie
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @author Tim Ysewyn
|
||||
* @author Robert Bleyl
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties
|
||||
@@ -224,8 +225,8 @@ public class EurekaClientAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public EurekaServiceRegistry eurekaServiceRegistry() {
|
||||
return new EurekaServiceRegistry();
|
||||
public EurekaServiceRegistry eurekaServiceRegistry(EurekaInstanceConfigBean eurekaInstanceConfigBean) {
|
||||
return new EurekaServiceRegistry(eurekaInstanceConfigBean);
|
||||
}
|
||||
|
||||
// @Bean
|
||||
|
||||
+19
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2022 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -38,6 +38,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Spencer Gibb
|
||||
* @author Ryan Baxter
|
||||
* @author Gregor Zurowski
|
||||
* @author Robert Bleyl
|
||||
*/
|
||||
@ConfigurationProperties("eureka.instance")
|
||||
public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, EnvironmentAware {
|
||||
@@ -269,6 +270,12 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
*/
|
||||
private boolean preferIpAddress = false;
|
||||
|
||||
/**
|
||||
* If true the EurekaClient will be initialized asynchronously when the
|
||||
* InstanceRegistry bean is created.
|
||||
*/
|
||||
private boolean asyncClientInitialization;
|
||||
|
||||
/**
|
||||
* Initial status to register with remote Eureka server.
|
||||
*/
|
||||
@@ -547,6 +554,14 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
this.preferIpAddress = preferIpAddress;
|
||||
}
|
||||
|
||||
public boolean isAsyncClientInitialization() {
|
||||
return asyncClientInitialization;
|
||||
}
|
||||
|
||||
public void setAsyncClientInitialization(boolean asyncClientInitialization) {
|
||||
this.asyncClientInitialization = asyncClientInitialization;
|
||||
}
|
||||
|
||||
public InstanceStatus getInitialStatus() {
|
||||
return initialStatus;
|
||||
}
|
||||
@@ -597,6 +612,7 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
&& Objects.equals(namespace, that.namespace) && Objects.equals(hostname, that.hostname)
|
||||
&& preferIpAddress == that.preferIpAddress && Objects.equals(initialStatus, that.initialStatus)
|
||||
&& Arrays.equals(defaultAddressResolutionOrder, that.defaultAddressResolutionOrder)
|
||||
&& asyncClientInitialization == that.asyncClientInitialization
|
||||
&& Objects.equals(environment, that.environment);
|
||||
}
|
||||
|
||||
@@ -607,7 +623,7 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
leaseExpirationDurationInSeconds, virtualHostName, instanceId, secureVirtualHostName, aSGName,
|
||||
metadataMap, dataCenterInfo, ipAddress, statusPageUrlPath, statusPageUrl, homePageUrlPath, homePageUrl,
|
||||
healthCheckUrlPath, healthCheckUrl, secureHealthCheckUrl, namespace, hostname, preferIpAddress,
|
||||
initialStatus, Arrays.hashCode(defaultAddressResolutionOrder), environment);
|
||||
asyncClientInitialization, initialStatus, Arrays.hashCode(defaultAddressResolutionOrder), environment);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -631,6 +647,7 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
.append("', ").append("healthCheckUrl='").append(healthCheckUrl).append("', ")
|
||||
.append("secureHealthCheckUrl='").append(secureHealthCheckUrl).append("', ").append("namespace='")
|
||||
.append(namespace).append("', ").append("hostname='").append(hostname).append("', ")
|
||||
.append("asyncClientInitialization=").append(asyncClientInitialization).append(", ")
|
||||
.append("preferIpAddress=").append(preferIpAddress).append(", ").append("initialStatus=")
|
||||
.append(initialStatus).append(", ").append("defaultAddressResolutionOrder=")
|
||||
.append(Arrays.toString(defaultAddressResolutionOrder)).append(", ").append("environment=")
|
||||
|
||||
+6
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 the original author or authors.
|
||||
* Copyright 2017-2024 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.
|
||||
@@ -34,6 +34,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.cloud.configuration.SSLContextFactory;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.RestTemplateTimeoutProperties;
|
||||
@@ -49,6 +50,7 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* @author Daniel Lavoie
|
||||
* @author Armin Krezovic
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(RestTemplateTimeoutProperties.class)
|
||||
@@ -69,11 +71,11 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled", matchIfMissing = true,
|
||||
havingValue = "false")
|
||||
public RestTemplateDiscoveryClientOptionalArgs restTemplateDiscoveryClientOptionalArgs(TlsProperties tlsProperties,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier)
|
||||
throws GeneralSecurityException, IOException {
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier,
|
||||
ObjectProvider<RestTemplateBuilder> restTemplateBuilders) throws GeneralSecurityException, IOException {
|
||||
logger.info("Eureka HTTP Client uses RestTemplate.");
|
||||
RestTemplateDiscoveryClientOptionalArgs result = new RestTemplateDiscoveryClientOptionalArgs(
|
||||
eurekaClientHttpRequestFactorySupplier);
|
||||
eurekaClientHttpRequestFactorySupplier, restTemplateBuilders::getIfAvailable);
|
||||
setupTLS(result, tlsProperties);
|
||||
return result;
|
||||
}
|
||||
|
||||
+11
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2022 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -29,10 +29,12 @@ import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
|
||||
import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.RestTemplateTimeoutProperties;
|
||||
import org.springframework.cloud.netflix.eureka.http.DefaultEurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient;
|
||||
@@ -51,11 +53,12 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
* discovery.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Armin Krezovic
|
||||
*/
|
||||
@ConditionalOnClass(ConfigServicePropertySourceLocator.class)
|
||||
@Conditional(EurekaConfigServerBootstrapConfiguration.EurekaConfigServerBootstrapCondition.class)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties
|
||||
@EnableConfigurationProperties(RestTemplateTimeoutProperties.class)
|
||||
public class EurekaConfigServerBootstrapConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -70,16 +73,18 @@ public class EurekaConfigServerBootstrapConfiguration {
|
||||
havingValue = "false")
|
||||
public RestTemplateEurekaHttpClient configDiscoveryRestTemplateEurekaHttpClient(EurekaClientConfigBean config,
|
||||
Environment env, @Nullable TlsProperties properties,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier,
|
||||
ObjectProvider<RestTemplateBuilder> restTemplateBuilders) {
|
||||
return (RestTemplateEurekaHttpClient) new RestTemplateTransportClientFactory(properties,
|
||||
eurekaClientHttpRequestFactorySupplier)
|
||||
eurekaClientHttpRequestFactorySupplier, restTemplateBuilders::getIfAvailable)
|
||||
.newClient(HostnameBasedUrlRandomizer.randomEndpoint(config, env));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
EurekaClientHttpRequestFactorySupplier defaultEurekaClientHttpRequestFactorySupplier() {
|
||||
return new DefaultEurekaClientHttpRequestFactorySupplier();
|
||||
EurekaClientHttpRequestFactorySupplier defaultEurekaClientHttpRequestFactorySupplier(
|
||||
RestTemplateTimeoutProperties restTemplateTimeoutProperties) {
|
||||
return new DefaultEurekaClientHttpRequestFactorySupplier(restTemplateTimeoutProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+9
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2022 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -31,6 +31,9 @@ import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaServiceInstance;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* @author Tang Xiong
|
||||
*/
|
||||
public class EurekaConfigServerInstanceProvider {
|
||||
|
||||
private final Log log;
|
||||
@@ -53,7 +56,11 @@ public class EurekaConfigServerInstanceProvider {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("eurekaConfigServerInstanceProvider finding instances for " + serviceId);
|
||||
}
|
||||
EurekaHttpResponse<Applications> response = client.getApplications(config.getRegion());
|
||||
String remoteRegionsStr = config.fetchRegistryForRemoteRegions();
|
||||
String[] remoteRegions = remoteRegionsStr == null ? null : remoteRegionsStr.split(",");
|
||||
EurekaHttpResponse<Applications> response = config.getRegistryRefreshSingleVipAddress() == null
|
||||
? client.getApplications(remoteRegions)
|
||||
: client.getVip(config.getRegistryRefreshSingleVipAddress(), remoteRegions);
|
||||
List<ServiceInstance> instances = new ArrayList<>();
|
||||
if (!isSuccessful(response) || response.getEntity() == null) {
|
||||
return instances;
|
||||
|
||||
+15
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 the original author or authors.
|
||||
* Copyright 2017-2024 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.
|
||||
@@ -16,18 +16,32 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs;
|
||||
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
|
||||
/**
|
||||
* @author Daniel Lavoie
|
||||
* @author Armin Krezovic
|
||||
*/
|
||||
public class RestTemplateDiscoveryClientOptionalArgs extends AbstractDiscoveryClientOptionalArgs<Void> {
|
||||
|
||||
protected final EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier;
|
||||
|
||||
protected final Supplier<RestTemplateBuilder> restTemplateBuilderSupplier;
|
||||
|
||||
public RestTemplateDiscoveryClientOptionalArgs(
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
|
||||
this(eurekaClientHttpRequestFactorySupplier, RestTemplateBuilder::new);
|
||||
}
|
||||
|
||||
public RestTemplateDiscoveryClientOptionalArgs(
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier,
|
||||
Supplier<RestTemplateBuilder> restTemplateBuilderSupplier) {
|
||||
this.eurekaClientHttpRequestFactorySupplier = eurekaClientHttpRequestFactorySupplier;
|
||||
this.restTemplateBuilderSupplier = restTemplateBuilderSupplier;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 the original author or authors.
|
||||
* Copyright 2017-2024 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.
|
||||
@@ -29,6 +29,7 @@ import com.netflix.discovery.shared.transport.jersey.TransportClientFactories;
|
||||
|
||||
/**
|
||||
* @author Daniel Lavoie
|
||||
* @author Armin Krezovic
|
||||
*/
|
||||
public class RestTemplateTransportClientFactories implements TransportClientFactories<Void> {
|
||||
|
||||
@@ -42,7 +43,7 @@ public class RestTemplateTransportClientFactories implements TransportClientFact
|
||||
public TransportClientFactory newTransportClientFactory(EurekaClientConfig clientConfig,
|
||||
Collection<Void> additionalFilters, InstanceInfo myInstanceInfo) {
|
||||
return new RestTemplateTransportClientFactory(this.args.getSSLContext(), this.args.getHostnameVerifier(),
|
||||
this.args.eurekaClientHttpRequestFactorySupplier);
|
||||
this.args.eurekaClientHttpRequestFactorySupplier, this.args.restTemplateBuilderSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -50,7 +51,7 @@ public class RestTemplateTransportClientFactories implements TransportClientFact
|
||||
final Collection<Void> additionalFilters, final InstanceInfo myInstanceInfo,
|
||||
final Optional<SSLContext> sslContext, final Optional<HostnameVerifier> hostnameVerifier) {
|
||||
return new RestTemplateTransportClientFactory(this.args.getSSLContext(), this.args.getHostnameVerifier(),
|
||||
this.args.eurekaClientHttpRequestFactorySupplier);
|
||||
this.args.eurekaClientHttpRequestFactorySupplier, this.args.restTemplateBuilderSupplier);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+34
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 the original author or authors.
|
||||
* Copyright 2017-2024 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.
|
||||
@@ -21,6 +21,7 @@ import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
@@ -44,6 +45,7 @@ import com.netflix.discovery.shared.resolver.EurekaEndpoint;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import com.netflix.discovery.shared.transport.TransportClientFactory;
|
||||
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.cloud.configuration.SSLContextFactory;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@@ -63,6 +65,7 @@ import org.springframework.web.util.UriComponentsBuilder;
|
||||
* deserialization.
|
||||
*
|
||||
* @author Daniel Lavoie
|
||||
* @author Armin Krezovic
|
||||
*/
|
||||
public class RestTemplateTransportClientFactory implements TransportClientFactory {
|
||||
|
||||
@@ -72,11 +75,20 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
|
||||
|
||||
private final EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier;
|
||||
|
||||
private final Supplier<RestTemplateBuilder> restTemplateBuilderSupplier;
|
||||
|
||||
public RestTemplateTransportClientFactory(TlsProperties tlsProperties,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier,
|
||||
Supplier<RestTemplateBuilder> restTemplateBuilderSupplier) {
|
||||
this.sslContext = context(tlsProperties);
|
||||
this.hostnameVerifier = Optional.empty();
|
||||
this.eurekaClientHttpRequestFactorySupplier = eurekaClientHttpRequestFactorySupplier;
|
||||
this.restTemplateBuilderSupplier = restTemplateBuilderSupplier;
|
||||
}
|
||||
|
||||
public RestTemplateTransportClientFactory(TlsProperties tlsProperties,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
|
||||
this(tlsProperties, eurekaClientHttpRequestFactorySupplier, RestTemplateBuilder::new);
|
||||
}
|
||||
|
||||
private Optional<SSLContext> context(TlsProperties properties) {
|
||||
@@ -93,16 +105,23 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
|
||||
|
||||
public RestTemplateTransportClientFactory(Optional<SSLContext> sslContext,
|
||||
Optional<HostnameVerifier> hostnameVerifier,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier,
|
||||
Supplier<RestTemplateBuilder> restTemplateBuilderSupplier) {
|
||||
this.sslContext = sslContext;
|
||||
this.hostnameVerifier = hostnameVerifier;
|
||||
this.eurekaClientHttpRequestFactorySupplier = eurekaClientHttpRequestFactorySupplier;
|
||||
this.restTemplateBuilderSupplier = restTemplateBuilderSupplier;
|
||||
}
|
||||
|
||||
public RestTemplateTransportClientFactory(Optional<SSLContext> sslContext,
|
||||
Optional<HostnameVerifier> hostnameVerifier,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
|
||||
|
||||
this(sslContext, hostnameVerifier, eurekaClientHttpRequestFactorySupplier, RestTemplateBuilder::new);
|
||||
}
|
||||
|
||||
public RestTemplateTransportClientFactory() {
|
||||
this.sslContext = Optional.empty();
|
||||
this.hostnameVerifier = Optional.empty();
|
||||
this.eurekaClientHttpRequestFactorySupplier = new DefaultEurekaClientHttpRequestFactorySupplier();
|
||||
this(Optional.empty(), Optional.empty(), new DefaultEurekaClientHttpRequestFactorySupplier());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -120,7 +139,15 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
|
||||
private RestTemplate restTemplate(String serviceUrl) {
|
||||
ClientHttpRequestFactory requestFactory = this.eurekaClientHttpRequestFactorySupplier
|
||||
.get(this.sslContext.orElse(null), this.hostnameVerifier.orElse(null));
|
||||
RestTemplate restTemplate = new RestTemplate(requestFactory);
|
||||
|
||||
RestTemplate restTemplate;
|
||||
|
||||
if (restTemplateBuilderSupplier != null && restTemplateBuilderSupplier.get() != null) {
|
||||
restTemplate = restTemplateBuilderSupplier.get().requestFactory(() -> requestFactory).build();
|
||||
}
|
||||
else {
|
||||
restTemplate = new RestTemplate(requestFactory);
|
||||
}
|
||||
|
||||
try {
|
||||
URI serviceURI = new URI(serviceUrl);
|
||||
@@ -209,11 +236,6 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
|
||||
return response.getStatusCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRawStatusCode() throws IOException {
|
||||
return response.getRawStatusCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStatusText() throws IOException {
|
||||
return response.getStatusText();
|
||||
|
||||
+5
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 the original author or authors.
|
||||
* Copyright 2017-2024 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.
|
||||
@@ -50,6 +50,7 @@ import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
|
||||
import org.springframework.web.reactive.function.client.ExchangeFilterFunctions;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* Provides the custom {@link WebClient.Builder} required by the
|
||||
@@ -58,6 +59,7 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
*
|
||||
* @author Daniel Lavoie
|
||||
* @author Haytham Mohamed
|
||||
* @author Armin Krezovic
|
||||
*/
|
||||
public class WebClientTransportClientFactory implements TransportClientFactory {
|
||||
|
||||
@@ -78,14 +80,14 @@ public class WebClientTransportClientFactory implements TransportClientFactory {
|
||||
}
|
||||
|
||||
private WebClient.Builder setUrl(WebClient.Builder builder, String serviceUrl) {
|
||||
String url = serviceUrl;
|
||||
String url = UriComponentsBuilder.fromUriString(serviceUrl).userInfo(null).toUriString();
|
||||
|
||||
try {
|
||||
URI serviceURI = new URI(serviceUrl);
|
||||
if (serviceURI.getUserInfo() != null) {
|
||||
String[] credentials = serviceURI.getUserInfo().split(":");
|
||||
if (credentials.length == 2) {
|
||||
builder.filter(ExchangeFilterFunctions.basicAuthentication(credentials[0], credentials[1]));
|
||||
url = serviceUrl.replace(credentials[0] + ":" + credentials[1] + "@", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2022 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -17,25 +17,54 @@
|
||||
package org.springframework.cloud.netflix.eureka.serviceregistry;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
|
||||
|
||||
import static com.netflix.appinfo.InstanceInfo.InstanceStatus.UNKNOWN;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Robert Bleyl
|
||||
*/
|
||||
public class EurekaServiceRegistry implements ServiceRegistry<EurekaRegistration> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(EurekaServiceRegistry.class);
|
||||
|
||||
private EurekaInstanceConfigBean eurekaInstanceConfigBean;
|
||||
|
||||
public EurekaServiceRegistry() {
|
||||
|
||||
}
|
||||
|
||||
public EurekaServiceRegistry(EurekaInstanceConfigBean eurekaInstanceConfigBean) {
|
||||
this.eurekaInstanceConfigBean = eurekaInstanceConfigBean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(EurekaRegistration reg) {
|
||||
maybeInitializeClient(reg);
|
||||
if (eurekaInstanceConfigBean != null && eurekaInstanceConfigBean.isAsyncClientInitialization()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Initializing client asynchronously...");
|
||||
}
|
||||
|
||||
ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||
executorService.submit(() -> {
|
||||
maybeInitializeClient(reg);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Asynchronous client initialization done.");
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
maybeInitializeClient(reg);
|
||||
}
|
||||
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("Registering application " + reg.getApplicationInfoManager().getInfo().getAppName()
|
||||
|
||||
+33
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2022 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -51,6 +51,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Tang Xiong
|
||||
*/
|
||||
@RunWith(ModifiedClassPathRunner.class)
|
||||
@ClassPathExclusions("spring-webflux-*")
|
||||
@@ -163,7 +164,34 @@ public class EurekaConfigServerBootstrapConfigurationTests {
|
||||
"eureka.client.enabled=true",
|
||||
"spring.main.sources=" + TestConfigDiscoveryBootstrapConfiguration.class.getName(),
|
||||
"logging.level.org.springframework.cloud.netflix.eureka.config=DEBUG")
|
||||
.run();
|
||||
.run().close();
|
||||
assertThat(output).contains("eurekaConfigServerInstanceProvider finding instances for configserver")
|
||||
.contains("eurekaConfigServerInstanceProvider found 1 instance(s) for configserver");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void eurekaConfigServerInstanceProviderCalledWithRemoteRegions() {
|
||||
TomcatURLStreamHandlerFactory.disable();
|
||||
new SpringApplicationBuilder(TestConfigDiscoveryConfiguration.class)
|
||||
.properties("spring.config.use-legacy-processing=true", "spring.cloud.config.discovery.enabled=true",
|
||||
"eureka.client.enabled=true", "eureka.client.fetchRemoteRegionsRegistry=us-east-1,us-east-2",
|
||||
"spring.main.sources=" + TestConfigDiscoveryBootstrapConfiguration.class.getName(),
|
||||
"logging.level.org.springframework.cloud.netflix.eureka.config=DEBUG")
|
||||
.run().close();
|
||||
assertThat(output).contains("eurekaConfigServerInstanceProvider finding instances for configserver")
|
||||
.contains("eurekaConfigServerInstanceProvider found 1 instance(s) for configserver");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void eurekaConfigServerInstanceProviderCalledWithVipAddress() {
|
||||
TomcatURLStreamHandlerFactory.disable();
|
||||
new SpringApplicationBuilder(TestConfigDiscoveryConfiguration.class)
|
||||
.properties("spring.config.use-legacy-processing=true", "spring.cloud.config.discovery.enabled=true",
|
||||
"eureka.client.enabled=true", "eureka.client.registryRefreshSingleVipAddress=vip1",
|
||||
"eureka.client.fetchRemoteRegionsRegistry=us-east-1,us-east-2",
|
||||
"spring.main.sources=" + TestConfigDiscoveryBootstrapConfiguration.class.getName(),
|
||||
"logging.level.org.springframework.cloud.netflix.eureka.config=DEBUG")
|
||||
.run().close();
|
||||
assertThat(output).contains("eurekaConfigServerInstanceProvider finding instances for configserver")
|
||||
.contains("eurekaConfigServerInstanceProvider found 1 instance(s) for configserver");
|
||||
}
|
||||
@@ -208,7 +236,9 @@ public class EurekaConfigServerBootstrapConfigurationTests {
|
||||
when(response.getEntity()).thenReturn(applications);
|
||||
|
||||
EurekaHttpClient client = mock(EurekaHttpClient.class);
|
||||
when(client.getApplications("us-east-1")).thenReturn(response);
|
||||
when(client.getApplications("us-east-1", "us-east-2")).thenReturn(response);
|
||||
when(client.getApplications((String) null)).thenReturn(response);
|
||||
when(client.getVip("vip1", "us-east-1", "us-east-2")).thenReturn(response);
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
+10
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2022 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -26,11 +26,12 @@ import org.springframework.boot.test.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientEurekaHttpClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -53,10 +54,12 @@ class EurekaConfigServerBootstrapConfigurationWebClientIntegrationTests {
|
||||
@Test
|
||||
void webClientRespectsCodecProperties() {
|
||||
WebClient webClient = eurekaHttpClient.getWebClient();
|
||||
ClientResponse response = webClient.get().uri("http://localhost:" + port).exchange().block();
|
||||
ResponseEntity<String> response = webClient.get().uri("http://localhost:" + port).retrieve()
|
||||
.toEntity(String.class).block();
|
||||
|
||||
assertThat(response).isNotNull();
|
||||
assertThat(response.statusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(response.bodyToMono(String.class).block()).startsWith("....").hasSize(300000);
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(response.getBody()).startsWith("....").hasSize(300000);
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@@ -71,8 +74,8 @@ class EurekaConfigServerBootstrapConfigurationWebClientIntegrationTests {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http.authorizeHttpRequests().anyRequest().permitAll().and().csrf().disable();
|
||||
return http.build();
|
||||
return http.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
|
||||
.csrf(AbstractHttpConfigurer::disable).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+60
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017-2022 the original author or authors.
|
||||
* Copyright 2017-2024 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.
|
||||
@@ -16,23 +16,57 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import com.netflix.discovery.shared.resolver.DefaultEndpoint;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.reactive.function.client.ClientRequest;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.ExchangeFunction;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Daniel Lavoie
|
||||
* @author Armin Krezovic
|
||||
*/
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
class WebClientTransportClientFactoryTest {
|
||||
|
||||
@Mock
|
||||
private ExchangeFunction exchangeFunction;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<ClientRequest> captor;
|
||||
|
||||
private WebClientTransportClientFactory transportClientFatory;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
transportClientFatory = new WebClientTransportClientFactory(WebClient::builder);
|
||||
ClientResponse mockResponse = mock();
|
||||
when(mockResponse.statusCode()).thenReturn(HttpStatus.OK);
|
||||
when(mockResponse.bodyToMono(Void.class)).thenReturn(Mono.empty());
|
||||
given(exchangeFunction.exchange(captor.capture())).willReturn(Mono.just(mockResponse));
|
||||
|
||||
transportClientFatory = new WebClientTransportClientFactory(
|
||||
() -> WebClient.builder().exchangeFunction(exchangeFunction));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -45,6 +79,23 @@ class WebClientTransportClientFactoryTest {
|
||||
transportClientFatory.newClient(new DefaultEndpoint("http://test@localhost:8761"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUserInfoWithEncodedCharacters() {
|
||||
String encodedBasicAuth = HttpHeaders.encodeBasicAuth("test", "MyPassword@", null);
|
||||
String expectedAuthHeader = "Basic " + encodedBasicAuth;
|
||||
String expectedUrl = "http://localhost:8761";
|
||||
|
||||
WebClientEurekaHttpClient client = (WebClientEurekaHttpClient) transportClientFatory
|
||||
.newClient(new DefaultEndpoint("http://test:MyPassword%40@localhost:8761"));
|
||||
|
||||
client.getWebClient().get().retrieve().bodyToMono(Void.class).block(Duration.ofSeconds(10));
|
||||
|
||||
ClientRequest request = verifyAndGetRequest();
|
||||
|
||||
assertThat(request.headers().getFirst(HttpHeaders.AUTHORIZATION)).isEqualTo(expectedAuthHeader);
|
||||
assertThat(request.url().toString()).isEqualTo(expectedUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUserInfo() {
|
||||
transportClientFatory.newClient(new DefaultEndpoint("http://test:test@localhost:8761"));
|
||||
@@ -55,4 +106,11 @@ class WebClientTransportClientFactoryTest {
|
||||
transportClientFatory.shutdown();
|
||||
}
|
||||
|
||||
private ClientRequest verifyAndGetRequest() {
|
||||
ClientRequest request = captor.getValue();
|
||||
verify(exchangeFunction).exchange(request);
|
||||
verifyNoMoreInteractions(exchangeFunction);
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+65
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2022 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -16,14 +16,20 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.serviceregistry;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import com.netflix.appinfo.ApplicationInfoManager;
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.cloud.commons.util.InetUtils;
|
||||
import org.springframework.cloud.commons.util.InetUtilsProperties;
|
||||
import org.springframework.cloud.loadbalancer.support.SimpleObjectProvider;
|
||||
import org.springframework.cloud.netflix.eureka.CloudEurekaClient;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
|
||||
@@ -33,16 +39,24 @@ import static com.netflix.appinfo.InstanceInfo.InstanceStatus.DOWN;
|
||||
import static com.netflix.appinfo.InstanceInfo.InstanceStatus.OUT_OF_SERVICE;
|
||||
import static com.netflix.appinfo.InstanceInfo.InstanceStatus.UNKNOWN;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Tim Ysewyn
|
||||
* @author Robert Bleyl
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class EurekaServiceRegistryTests {
|
||||
|
||||
@Mock
|
||||
private EurekaInstanceConfigBean eurekaInstanceConfigBean;
|
||||
|
||||
@Test
|
||||
void eurekaClientNotShutdownInDeregister() {
|
||||
EurekaServiceRegistry registry = new EurekaServiceRegistry();
|
||||
@@ -110,8 +124,6 @@ class EurekaServiceRegistryTests {
|
||||
|
||||
CloudEurekaClient eurekaClient = mock(CloudEurekaClient.class);
|
||||
|
||||
when(eurekaClient.getInstanceInfo("myapp", "1234")).thenReturn(null);
|
||||
|
||||
ApplicationInfoManager applicationInfoManager = mock(ApplicationInfoManager.class);
|
||||
when(applicationInfoManager.getInfo()).thenReturn(mock(InstanceInfo.class));
|
||||
|
||||
@@ -130,4 +142,54 @@ class EurekaServiceRegistryTests {
|
||||
assertThat(map).hasSize(1).containsEntry("status", UNKNOWN.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void eurekaClientInitializesClientAsynchronously() {
|
||||
when(eurekaInstanceConfigBean.isAsyncClientInitialization()).thenReturn(true);
|
||||
EurekaServiceRegistry registry = new EurekaServiceRegistry(eurekaInstanceConfigBean);
|
||||
|
||||
final AtomicBoolean applicationsFetched = new AtomicBoolean();
|
||||
|
||||
CloudEurekaClient eurekaClient = mock(CloudEurekaClient.class);
|
||||
when(eurekaClient.getApplications()).thenAnswer((answer) -> {
|
||||
applicationsFetched.set(true);
|
||||
return answer;
|
||||
});
|
||||
|
||||
ApplicationInfoManager applicationInfoManager = mock(ApplicationInfoManager.class);
|
||||
|
||||
when(applicationInfoManager.getInfo()).thenReturn(mock(InstanceInfo.class));
|
||||
|
||||
EurekaRegistration registration = EurekaRegistration
|
||||
.builder(new EurekaInstanceConfigBean(new InetUtils(new InetUtilsProperties()))).with(eurekaClient)
|
||||
.with(applicationInfoManager).with(new EurekaClientConfigBean(), mock(ApplicationEventPublisher.class))
|
||||
.with(new SimpleObjectProvider<>(null)).build();
|
||||
|
||||
registry.register(registration);
|
||||
|
||||
await().atMost(Duration.ofSeconds(5)).pollInterval(Duration.ofMillis(500)).until(applicationsFetched::get);
|
||||
|
||||
verify(eurekaClient).getApplications();
|
||||
assertThat(applicationsFetched).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void eurekaClientInitializesClientSynchronously() {
|
||||
EurekaServiceRegistry registry = new EurekaServiceRegistry(eurekaInstanceConfigBean);
|
||||
|
||||
CloudEurekaClient eurekaClient = mock(CloudEurekaClient.class);
|
||||
ApplicationInfoManager applicationInfoManager = mock(ApplicationInfoManager.class);
|
||||
|
||||
when(applicationInfoManager.getInfo()).thenReturn(mock(InstanceInfo.class));
|
||||
|
||||
EurekaRegistration registration = EurekaRegistration
|
||||
.builder(new EurekaInstanceConfigBean(new InetUtils(new InetUtilsProperties()))).with(eurekaClient)
|
||||
.with(applicationInfoManager).with(new EurekaClientConfigBean(), mock(ApplicationEventPublisher.class))
|
||||
.with(new SimpleObjectProvider<>(null)).build();
|
||||
|
||||
registry.register(registration);
|
||||
|
||||
verify(eurekaClient).getApplications();
|
||||
verify(eurekaClient, never()).getEurekaClientConfig();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.1.1-SNAPSHOT</version>
|
||||
<version>4.1.2</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-eureka-server</artifactId>
|
||||
@@ -76,13 +76,7 @@
|
||||
<groupId>org.glassfish.hk2</groupId>
|
||||
<artifactId>spring-bridge</artifactId>
|
||||
<!-- FIXME: 4.0 -->
|
||||
<version>3.0.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.inject</groupId>
|
||||
<artifactId>jakarta.inject-api</artifactId>
|
||||
<!-- FIXME: 4.0 -->
|
||||
<version>2.0.1</version>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
<!-- Eureka deps that are now optional in eureka -->
|
||||
<dependency>
|
||||
|
||||
+24
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2022 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -25,6 +25,8 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.netflix.appinfo.ApplicationInfoManager;
|
||||
@@ -88,6 +90,7 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.cloud.client.actuator.HasFeatures;
|
||||
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaConstants;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
@@ -108,6 +111,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
* @author Biju Kunjummen
|
||||
* @author Fahim Farook
|
||||
* @author Weix Sun
|
||||
* @author Robert Bleyl
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(EurekaServerInitializerConfiguration.class)
|
||||
@@ -207,8 +211,25 @@ public class EurekaServerAutoConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Bean
|
||||
public PeerAwareInstanceRegistry peerAwareInstanceRegistry(ServerCodecs serverCodecs,
|
||||
EurekaServerHttpClientFactory eurekaServerHttpClientFactory) {
|
||||
this.eurekaClient.getApplications(); // force initialization
|
||||
EurekaServerHttpClientFactory eurekaServerHttpClientFactory,
|
||||
EurekaInstanceConfigBean eurekaInstanceConfigBean) {
|
||||
if (eurekaInstanceConfigBean.isAsyncClientInitialization()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Initializing client asynchronously...");
|
||||
}
|
||||
|
||||
ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||
executorService.submit(() -> {
|
||||
this.eurekaClient.getApplications();
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Asynchronous client initialization done.");
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.eurekaClient.getApplications(); // force initialization
|
||||
}
|
||||
|
||||
return new InstanceRegistry(this.eurekaServerConfig, this.eurekaClientConfig, serverCodecs, this.eurekaClient,
|
||||
eurekaServerHttpClientFactory,
|
||||
this.instanceRegistryProperties.getExpectedNumberOfClientsSendingRenews(),
|
||||
|
||||
+31
-17
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2022 the original author or authors.
|
||||
* Copyright 2013-2024 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.
|
||||
@@ -39,6 +39,7 @@ import org.springframework.context.ApplicationEvent;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Wonchul Heo
|
||||
*/
|
||||
public class InstanceRegistry extends PeerAwareInstanceRegistryImpl implements ApplicationContextAware {
|
||||
|
||||
@@ -78,52 +79,65 @@ public class InstanceRegistry extends PeerAwareInstanceRegistryImpl implements A
|
||||
|
||||
@Override
|
||||
public void register(InstanceInfo info, int leaseDuration, boolean isReplication) {
|
||||
handleRegistration(info, leaseDuration, isReplication);
|
||||
super.register(info, leaseDuration, isReplication);
|
||||
handleRegistration(info, leaseDuration, isReplication);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(final InstanceInfo info, final boolean isReplication) {
|
||||
handleRegistration(info, resolveInstanceLeaseDuration(info), isReplication);
|
||||
super.register(info, isReplication);
|
||||
handleRegistration(info, resolveInstanceLeaseDuration(info), isReplication);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel(String appName, String serverId, boolean isReplication) {
|
||||
handleCancelation(appName, serverId, isReplication);
|
||||
return super.cancel(appName, serverId, isReplication);
|
||||
final boolean cancelled = super.cancel(appName, serverId, isReplication);
|
||||
if (cancelled) {
|
||||
handleCancelation(appName, serverId, isReplication);
|
||||
}
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean renew(final String appName, final String serverId, boolean isReplication) {
|
||||
log("renew " + appName + " serverId " + serverId + ", isReplication {}" + isReplication);
|
||||
Application application = getApplication(appName);
|
||||
if (application != null) {
|
||||
InstanceInfo instanceInfo = application.getByInstanceId(serverId);
|
||||
if (instanceInfo != null) {
|
||||
publishEvent(new EurekaInstanceRenewedEvent(this, appName, serverId, instanceInfo, isReplication));
|
||||
}
|
||||
final boolean renewed = super.renew(appName, serverId, isReplication);
|
||||
if (renewed) {
|
||||
handleRenewal(appName, serverId, isReplication);
|
||||
}
|
||||
return super.renew(appName, serverId, isReplication);
|
||||
return renewed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean internalCancel(String appName, String id, boolean isReplication) {
|
||||
handleCancelation(appName, id, isReplication);
|
||||
return super.internalCancel(appName, id, isReplication);
|
||||
final boolean cancelled = super.internalCancel(appName, id, isReplication);
|
||||
if (cancelled) {
|
||||
handleCancelation(appName, id, isReplication);
|
||||
}
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
private void handleCancelation(String appName, String id, boolean isReplication) {
|
||||
log("cancel " + appName + ", serverId " + id + ", isReplication " + isReplication);
|
||||
log("cancelled " + appName + ", serverId " + id + ", isReplication " + isReplication);
|
||||
publishEvent(new EurekaInstanceCanceledEvent(this, appName, id, isReplication));
|
||||
}
|
||||
|
||||
private void handleRegistration(InstanceInfo info, int leaseDuration, boolean isReplication) {
|
||||
log("register " + info.getAppName() + ", vip " + info.getVIPAddress() + ", leaseDuration " + leaseDuration
|
||||
log("registered " + info.getAppName() + ", vip " + info.getVIPAddress() + ", leaseDuration " + leaseDuration
|
||||
+ ", isReplication " + isReplication);
|
||||
publishEvent(new EurekaInstanceRegisteredEvent(this, info, leaseDuration, isReplication));
|
||||
}
|
||||
|
||||
private void handleRenewal(final String appName, final String serverId, boolean isReplication) {
|
||||
log("renewed " + appName + ", serverId " + serverId + ", isReplication " + isReplication);
|
||||
final Application application = getApplication(appName);
|
||||
if (application != null) {
|
||||
final InstanceInfo instanceInfo = application.getByInstanceId(serverId);
|
||||
if (instanceInfo != null) {
|
||||
publishEvent(new EurekaInstanceRenewedEvent(this, appName, serverId, instanceInfo, isReplication));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void log(String message) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(message);
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2013-2024 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.server.metrics;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
|
||||
/**
|
||||
* Default implementation for {@link EurekaInstanceTagsProvider}.
|
||||
*
|
||||
* @author Wonchul Heo
|
||||
* @since 4.1.2
|
||||
*/
|
||||
class DefaultEurekaInstanceTagsProvider implements EurekaInstanceTagsProvider {
|
||||
|
||||
@Override
|
||||
public Tags eurekaInstanceTags(InstanceInfo instanceInfo) {
|
||||
return Tags.of(Tag.of("application", instanceInfo.getAppName()),
|
||||
Tag.of("status", instanceInfo.getStatus().name()));
|
||||
}
|
||||
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2013-2024 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.server.metrics;
|
||||
|
||||
import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.CompositeMeterRegistryAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
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.ConditionalOnProperty;
|
||||
import org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* Auto-configuration for Eureka Instance metrics.
|
||||
*
|
||||
* @author Wonchul Heo
|
||||
* @since 4.1.2
|
||||
*/
|
||||
@ConditionalOnClass(MeterRegistry.class)
|
||||
@ConditionalOnBean(MeterRegistry.class)
|
||||
@AutoConfigureAfter({ MetricsAutoConfiguration.class, CompositeMeterRegistryAutoConfiguration.class,
|
||||
EurekaServerAutoConfiguration.class })
|
||||
@ConditionalOnProperty(name = "eureka.server.metrics.enabled", havingValue = "true")
|
||||
class EurekaInstanceMetricsAutoConfiguration {
|
||||
|
||||
@ConditionalOnMissingBean
|
||||
@Bean
|
||||
public EurekaInstanceTagsProvider eurekaInstanceTagProvider() {
|
||||
return new DefaultEurekaInstanceTagsProvider();
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean
|
||||
@Bean
|
||||
public EurekaInstanceMonitor eurekaInstanceMeterBinder(MeterRegistry meterRegistry,
|
||||
PeerAwareInstanceRegistry instanceRegistry, EurekaInstanceTagsProvider tagProvider) {
|
||||
return new EurekaInstanceMonitor(meterRegistry, instanceRegistry, tagProvider);
|
||||
}
|
||||
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2013-2024 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.server.metrics;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.MultiGauge;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
|
||||
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceCanceledEvent;
|
||||
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRegisteredEvent;
|
||||
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRenewedEvent;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.event.SmartApplicationListener;
|
||||
|
||||
/**
|
||||
* {@link SmartApplicationListener} for collecting event metrics from
|
||||
* {@link PeerAwareInstanceRegistry}.
|
||||
*
|
||||
* @author Wonchul Heo
|
||||
* @since 4.1.2
|
||||
*/
|
||||
public class EurekaInstanceMonitor implements SmartApplicationListener {
|
||||
|
||||
private final MultiGauge eurekaInstances;
|
||||
|
||||
private final PeerAwareInstanceRegistry instanceRegistry;
|
||||
|
||||
private final EurekaInstanceTagsProvider tagProvider;
|
||||
|
||||
EurekaInstanceMonitor(MeterRegistry meterRegistry, PeerAwareInstanceRegistry instanceRegistry,
|
||||
EurekaInstanceTagsProvider tagProvider) {
|
||||
Objects.requireNonNull(meterRegistry);
|
||||
this.instanceRegistry = Objects.requireNonNull(instanceRegistry);
|
||||
this.tagProvider = Objects.requireNonNull(tagProvider);
|
||||
this.eurekaInstances = MultiGauge.builder("eureka.server.instances")
|
||||
.description("Number of application instances registered with the Eureka server.")
|
||||
.register(meterRegistry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
|
||||
// If events that change state are added, an event class must be added.
|
||||
return EurekaInstanceCanceledEvent.class.isAssignableFrom(eventType)
|
||||
|| EurekaInstanceRegisteredEvent.class.isAssignableFrom(eventType)
|
||||
|| EurekaInstanceRenewedEvent.class.isAssignableFrom(eventType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
final Map<Tags, Long> aggregatedCounts = instanceRegistry.getApplications().getRegisteredApplications().stream()
|
||||
.flatMap(application -> application.getInstances().stream())
|
||||
.collect(Collectors.groupingBy(tagProvider::eurekaInstanceTags, Collectors.counting()));
|
||||
eurekaInstances.register(aggregatedCounts.entrySet().stream()
|
||||
.map(entry -> MultiGauge.Row.of(entry.getKey(), entry.getValue())).collect(Collectors.toList()), true);
|
||||
}
|
||||
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2013-2024 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.server.metrics;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
|
||||
/**
|
||||
* Provides {@link Tags} for Eureka instance metrics.
|
||||
*
|
||||
* @author Wonchul Heo
|
||||
* @since 4.1.2
|
||||
*/
|
||||
public interface EurekaInstanceTagsProvider {
|
||||
|
||||
Tags eurekaInstanceTags(InstanceInfo instanceInfo);
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"properties": [
|
||||
{
|
||||
"name": "eureka.server.metrics.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"defaultValue": "false",
|
||||
"description": "Indicates whether the metrics should be enabled for eureka instances."
|
||||
}
|
||||
]
|
||||
}
|
||||
+2
-1
@@ -1 +1,2 @@
|
||||
org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration
|
||||
org.springframework.cloud.netflix.eureka.server.EurekaServerAutoConfiguration
|
||||
org.springframework.cloud.netflix.eureka.server.metrics.EurekaInstanceMetricsAutoConfiguration
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2013-2024 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.server;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.appinfo.LeaseInfo;
|
||||
|
||||
public final class EurekaInstanceFixture {
|
||||
|
||||
private EurekaInstanceFixture() {
|
||||
}
|
||||
|
||||
public static LeaseInfo getLeaseInfo() {
|
||||
LeaseInfo.Builder leaseBuilder = LeaseInfo.Builder.newBuilder();
|
||||
leaseBuilder.setRenewalIntervalInSecs(10);
|
||||
leaseBuilder.setDurationInSecs(15);
|
||||
return leaseBuilder.build();
|
||||
}
|
||||
|
||||
public static InstanceInfo getInstanceInfo(String appName, String hostName, String instanceId, int port,
|
||||
LeaseInfo leaseInfo) {
|
||||
InstanceInfo.Builder builder = InstanceInfo.Builder.newBuilder();
|
||||
builder.setAppName(appName);
|
||||
builder.setHostName(hostName);
|
||||
builder.setInstanceId(instanceId);
|
||||
builder.setPort(port);
|
||||
builder.setLeaseInfo(leaseInfo);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2013-2024 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.server;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tag;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
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.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.netflix.eureka.server.EurekaInstanceFixture.getInstanceInfo;
|
||||
import static org.springframework.cloud.netflix.eureka.server.EurekaInstanceFixture.getLeaseInfo;
|
||||
|
||||
/**
|
||||
* @author Wonchul Heo
|
||||
*/
|
||||
@SpringBootTest(classes = EurekaInstanceMonitorTests.Application.class,
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
value = { "spring.application.name=eureka", "eureka.server.metrics.enabled=true" })
|
||||
class EurekaInstanceMonitorTests {
|
||||
|
||||
private static final String FOO_APP_NAME = "FOO-APP-NAME";
|
||||
|
||||
private static final String BAR_APP_NAME = "BAR-APP-NAME";
|
||||
|
||||
@Autowired
|
||||
private InstanceRegistry instanceRegistry;
|
||||
|
||||
@Autowired
|
||||
private MeterRegistry meterRegistry;
|
||||
|
||||
private InstanceInfo fooInstanceInfo;
|
||||
|
||||
private InstanceInfo fooInstanceInfo2;
|
||||
|
||||
private InstanceInfo barInstanceInfo;
|
||||
|
||||
private InstanceInfo barInstanceInfo2;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
instanceRegistry.clearRegistry();
|
||||
meterRegistry.clear();
|
||||
fooInstanceInfo = getInstanceInfo(FOO_APP_NAME, "my-host-name", "my-host-name:8008", 8008, getLeaseInfo());
|
||||
fooInstanceInfo2 = getInstanceInfo(FOO_APP_NAME, "my-host-name", "my-host-name:8009", 8009, getLeaseInfo());
|
||||
barInstanceInfo = getInstanceInfo(BAR_APP_NAME, "my-host-name", "my-host-name:8010", 8010, getLeaseInfo());
|
||||
barInstanceInfo2 = getInstanceInfo(BAR_APP_NAME, "my-host-name", "my-host-name:8011", 8011, getLeaseInfo());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoRegistration() {
|
||||
assertThat(meterRegistry.find("eureka.server.instances").gauge()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMultipleRegistrations() {
|
||||
instanceRegistry.register(fooInstanceInfo, false);
|
||||
instanceRegistry.register(fooInstanceInfo2, false);
|
||||
instanceRegistry.register(barInstanceInfo, false);
|
||||
|
||||
final Map<Tags, Long> counts = Map.of(tags(fooInstanceInfo), 2L, tags(barInstanceInfo), 1L);
|
||||
assertEurekaInstance(counts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPartialDeregistrationAfterMultipleRegistrations() {
|
||||
instanceRegistry.register(fooInstanceInfo, false);
|
||||
instanceRegistry.register(fooInstanceInfo2, false);
|
||||
instanceRegistry.register(barInstanceInfo, false);
|
||||
instanceRegistry.register(barInstanceInfo2, false);
|
||||
|
||||
instanceRegistry.internalCancel(fooInstanceInfo.getAppName(), fooInstanceInfo.getInstanceId(), false);
|
||||
|
||||
final Map<Tags, Long> counts = Map.of(tags(fooInstanceInfo), 1L, tags(barInstanceInfo), 2L);
|
||||
assertEurekaInstance(counts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPartialDeregistrationAndThenRegistrationAfterMultipleRegistrations() {
|
||||
instanceRegistry.register(fooInstanceInfo, false);
|
||||
instanceRegistry.register(fooInstanceInfo2, false);
|
||||
instanceRegistry.register(barInstanceInfo, false);
|
||||
instanceRegistry.register(barInstanceInfo2, false);
|
||||
|
||||
instanceRegistry.internalCancel(fooInstanceInfo.getAppName(), fooInstanceInfo.getInstanceId(), false);
|
||||
instanceRegistry.register(fooInstanceInfo, false);
|
||||
|
||||
final Map<Tags, Long> counts = Map.of(tags(fooInstanceInfo), 2L, tags(barInstanceInfo), 2L);
|
||||
assertEurekaInstance(counts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPartialNonRenewalAfterMultipleRegistrations() {
|
||||
instanceRegistry.register(fooInstanceInfo, false);
|
||||
instanceRegistry.register(fooInstanceInfo2, false);
|
||||
instanceRegistry.register(barInstanceInfo, false);
|
||||
instanceRegistry.register(barInstanceInfo2, false);
|
||||
|
||||
instanceRegistry.statusUpdate(fooInstanceInfo.getAppName(), fooInstanceInfo.getInstanceId(),
|
||||
InstanceInfo.InstanceStatus.DOWN, null, false);
|
||||
|
||||
final Map<Tags, Long> meterRegistryCounts = Map.of(tags(fooInstanceInfo2), 2L);
|
||||
assertEurekaInstance(meterRegistryCounts);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPartialRenewalAfterMultipleRegistrations() {
|
||||
instanceRegistry.register(fooInstanceInfo, false);
|
||||
instanceRegistry.register(fooInstanceInfo2, false);
|
||||
instanceRegistry.register(barInstanceInfo, false);
|
||||
instanceRegistry.register(barInstanceInfo2, false);
|
||||
|
||||
instanceRegistry.statusUpdate(fooInstanceInfo.getAppName(), fooInstanceInfo.getInstanceId(),
|
||||
InstanceInfo.InstanceStatus.DOWN, null, false);
|
||||
instanceRegistry.statusUpdate(barInstanceInfo2.getAppName(), barInstanceInfo2.getInstanceId(),
|
||||
InstanceInfo.InstanceStatus.STARTING, null, false);
|
||||
instanceRegistry.renew(fooInstanceInfo.getAppName(), fooInstanceInfo.getInstanceId(), false);
|
||||
instanceRegistry.renew(barInstanceInfo2.getAppName(), barInstanceInfo2.getInstanceId(), false);
|
||||
|
||||
final Map<Tags, Long> counts = Map.of(tags(fooInstanceInfo), 1L, tags(fooInstanceInfo2), 1L,
|
||||
tags(barInstanceInfo), 1L, tags(barInstanceInfo2), 1L);
|
||||
assertEurekaInstance(counts);
|
||||
}
|
||||
|
||||
private static Tags tags(InstanceInfo instanceInfo) {
|
||||
return Tags.of(Tag.of("application", instanceInfo.getAppName()),
|
||||
Tag.of("status", instanceInfo.getStatus().name()));
|
||||
}
|
||||
|
||||
private void assertEurekaInstance(Map<Tags, Long> meterRegistryCounts) {
|
||||
meterRegistryCounts.forEach((tags,
|
||||
count) -> assertThat((long) meterRegistry.get("eureka.server.instances").tags(tags).gauge().value())
|
||||
.isEqualTo(count));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration
|
||||
@EnableEurekaServer
|
||||
protected static class Application {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2013-2024 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.server;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
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.metrics.EurekaInstanceTagsProvider;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.netflix.eureka.server.EurekaInstanceFixture.getInstanceInfo;
|
||||
import static org.springframework.cloud.netflix.eureka.server.EurekaInstanceFixture.getLeaseInfo;
|
||||
|
||||
/**
|
||||
* @author Wonchul Heo
|
||||
*/
|
||||
@SpringBootTest(classes = EurekaInstanceMonitorWithCustomTagsProviderTests.Application.class,
|
||||
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
value = { "spring.application.name=eureka", "eureka.server.metrics.enabled=true" })
|
||||
class EurekaInstanceMonitorWithCustomTagsProviderTests {
|
||||
|
||||
private static final String APP_NAME = "FOO-APP-NAME";
|
||||
|
||||
@Autowired
|
||||
private InstanceRegistry instanceRegistry;
|
||||
|
||||
@Autowired
|
||||
private MeterRegistry meterRegistry;
|
||||
|
||||
private InstanceInfo firstInstanceInfo;
|
||||
|
||||
private InstanceInfo secondInstanceInfo;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
instanceRegistry.clearRegistry();
|
||||
meterRegistry.clear();
|
||||
firstInstanceInfo = getInstanceInfo(APP_NAME, "my-host-name", "my-host-name:8008", 8008, getLeaseInfo());
|
||||
secondInstanceInfo = getInstanceInfo(APP_NAME, "my-host-name", "my-host-name:8009", 8009, getLeaseInfo());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoRegistration() {
|
||||
assertThat(meterRegistry.find("eureka.server.instances").gauge()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMultipleRegistrations() {
|
||||
instanceRegistry.register(firstInstanceInfo, false);
|
||||
instanceRegistry.register(secondInstanceInfo, false);
|
||||
|
||||
final Map<Tags, Long> counts = Map.of(tags(firstInstanceInfo), 1L, tags(secondInstanceInfo), 1L);
|
||||
assertEurekaInstance(counts);
|
||||
}
|
||||
|
||||
private static Tags tags(InstanceInfo instanceInfo) {
|
||||
return Tags.of("port", String.valueOf(instanceInfo.getPort()));
|
||||
}
|
||||
|
||||
private void assertEurekaInstance(Map<Tags, Long> meterRegistryCounts) {
|
||||
meterRegistryCounts.forEach((tags,
|
||||
count) -> assertThat((long) meterRegistry.get("eureka.server.instances").tags(tags).gauge().value())
|
||||
.isEqualTo(count));
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration
|
||||
@EnableEurekaServer
|
||||
protected static class Application {
|
||||
|
||||
@Bean
|
||||
EurekaInstanceTagsProvider customEurekaInstanceTagsProvider() {
|
||||
return instanceInfo -> Tags.of("port", String.valueOf(instanceInfo.getPort()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+22
-40
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2022 the original author or authors.
|
||||
* Copyright 2016-2024 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.
|
||||
@@ -16,21 +16,17 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.server;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.appinfo.LeaseInfo;
|
||||
import com.netflix.discovery.shared.Application;
|
||||
import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
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.boot.test.mock.mockito.SpyBean;
|
||||
import org.springframework.cloud.netflix.eureka.server.InstanceRegistryTests.TestApplication;
|
||||
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceCanceledEvent;
|
||||
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRegisteredEvent;
|
||||
@@ -41,7 +37,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.event.SmartApplicationListener;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.springframework.cloud.netflix.eureka.server.EurekaInstanceFixture.getInstanceInfo;
|
||||
import static org.springframework.cloud.netflix.eureka.server.EurekaInstanceFixture.getLeaseInfo;
|
||||
|
||||
/**
|
||||
* @author Bartlomiej Slota
|
||||
@@ -59,12 +56,13 @@ class InstanceRegistryTests {
|
||||
|
||||
private static final int PORT = 8008;
|
||||
|
||||
@SpyBean(PeerAwareInstanceRegistry.class)
|
||||
@Autowired
|
||||
private InstanceRegistry instanceRegistry;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
this.testEvents.applicationEvents.clear();
|
||||
this.instanceRegistry.clearRegistry();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
@@ -103,39 +101,41 @@ class InstanceRegistryTests {
|
||||
|
||||
@Test
|
||||
void testInternalCancel() {
|
||||
// registering instance info
|
||||
final InstanceInfo instanceInfo = getInstanceInfo(APP_NAME, HOST_NAME, INSTANCE_ID, PORT, null);
|
||||
instanceRegistry.register(instanceInfo, false);
|
||||
// calling tested method
|
||||
instanceRegistry.internalCancel(APP_NAME, HOST_NAME, false);
|
||||
instanceRegistry.internalCancel(APP_NAME, INSTANCE_ID, false);
|
||||
// event of proper type is registered
|
||||
assertThat(this.testEvents.applicationEvents.size()).isEqualTo(1);
|
||||
assertThat(this.testEvents.applicationEvents.get(0) instanceof EurekaInstanceCanceledEvent).isTrue();
|
||||
assertThat(this.testEvents.applicationEvents.size()).isEqualTo(2);
|
||||
assertThat(this.testEvents.applicationEvents.get(0) instanceof EurekaInstanceRegisteredEvent).isTrue();
|
||||
assertThat(this.testEvents.applicationEvents.get(1) instanceof EurekaInstanceCanceledEvent).isTrue();
|
||||
// event details are correct
|
||||
final EurekaInstanceCanceledEvent registeredEvent = (EurekaInstanceCanceledEvent) (this.testEvents.applicationEvents
|
||||
.get(0));
|
||||
.get(1));
|
||||
assertThat(registeredEvent.getAppName()).isEqualTo(APP_NAME);
|
||||
assertThat(registeredEvent.getServerId()).isEqualTo(HOST_NAME);
|
||||
assertThat(registeredEvent.getServerId()).isEqualTo(INSTANCE_ID);
|
||||
assertThat(registeredEvent.getSource()).isEqualTo(instanceRegistry);
|
||||
assertThat(registeredEvent.isReplication()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRenew() {
|
||||
// Creating two instances of the app
|
||||
// registering two instances of the app
|
||||
final InstanceInfo instanceInfo1 = getInstanceInfo(APP_NAME, HOST_NAME, INSTANCE_ID, PORT, null);
|
||||
final InstanceInfo instanceInfo2 = getInstanceInfo(APP_NAME, HOST_NAME, "my-host-name:8009", 8009, null);
|
||||
// creating application list with an app having two instances
|
||||
final Application application = new Application(APP_NAME, Arrays.asList(instanceInfo1, instanceInfo2));
|
||||
// stubbing application
|
||||
doReturn(application).when(instanceRegistry).getApplication(APP_NAME);
|
||||
instanceRegistry.register(instanceInfo1, false);
|
||||
instanceRegistry.register(instanceInfo2, false);
|
||||
// calling tested method
|
||||
instanceRegistry.renew(APP_NAME, INSTANCE_ID, false);
|
||||
instanceRegistry.renew(APP_NAME, "my-host-name:8009", false);
|
||||
// event of proper type is registered
|
||||
assertThat(this.testEvents.applicationEvents.size()).isEqualTo(2);
|
||||
assertThat(this.testEvents.applicationEvents.get(0) instanceof EurekaInstanceRenewedEvent).isTrue();
|
||||
assertThat(this.testEvents.applicationEvents.get(1) instanceof EurekaInstanceRenewedEvent).isTrue();
|
||||
assertThat(this.testEvents.applicationEvents.size()).isEqualTo(4);
|
||||
assertThat(this.testEvents.applicationEvents.get(2) instanceof EurekaInstanceRenewedEvent).isTrue();
|
||||
assertThat(this.testEvents.applicationEvents.get(3) instanceof EurekaInstanceRenewedEvent).isTrue();
|
||||
// event details are correct
|
||||
final EurekaInstanceRenewedEvent event1 = (EurekaInstanceRenewedEvent) (this.testEvents.applicationEvents
|
||||
.get(0));
|
||||
.get(2));
|
||||
assertThat(event1.getAppName()).isEqualTo(APP_NAME);
|
||||
assertThat(event1.getServerId()).isEqualTo(INSTANCE_ID);
|
||||
assertThat(event1.getSource()).isEqualTo(instanceRegistry);
|
||||
@@ -143,28 +143,10 @@ class InstanceRegistryTests {
|
||||
assertThat(event1.isReplication()).isFalse();
|
||||
|
||||
final EurekaInstanceRenewedEvent event2 = (EurekaInstanceRenewedEvent) (this.testEvents.applicationEvents
|
||||
.get(1));
|
||||
.get(3));
|
||||
assertThat(event2.getInstanceInfo()).isEqualTo(instanceInfo2);
|
||||
}
|
||||
|
||||
private LeaseInfo getLeaseInfo() {
|
||||
LeaseInfo.Builder leaseBuilder = LeaseInfo.Builder.newBuilder();
|
||||
leaseBuilder.setRenewalIntervalInSecs(10);
|
||||
leaseBuilder.setDurationInSecs(15);
|
||||
return leaseBuilder.build();
|
||||
}
|
||||
|
||||
private InstanceInfo getInstanceInfo(String appName, String hostName, String instanceId, int port,
|
||||
LeaseInfo leaseInfo) {
|
||||
InstanceInfo.Builder builder = InstanceInfo.Builder.newBuilder();
|
||||
builder.setAppName(appName);
|
||||
builder.setHostName(hostName);
|
||||
builder.setInstanceId(instanceId);
|
||||
builder.setPort(port);
|
||||
builder.setLeaseInfo(leaseInfo);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration
|
||||
@EnableEurekaServer
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.1.1-SNAPSHOT</version>
|
||||
<version>4.1.2</version>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
||||
<name>Spring Cloud Starter Netflix Eureka Client</name>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>4.1.1-SNAPSHOT</version>
|
||||
<version>4.1.2</version>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
|
||||
<name>Spring Cloud Starter Netflix Eureka Server</name>
|
||||
|
||||
Reference in New Issue
Block a user