mirror of
https://github.com/spring-cloud/spring-cloud-netflix.git
synced 2026-09-20 00:59:01 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d27038710 | ||
|
|
221eb0937c | ||
|
|
c2dcdacaa2 | ||
|
|
7fbf5a51de | ||
|
|
078db236b8 | ||
|
|
132cf9e4f7 | ||
|
|
147d50f2c2 | ||
|
|
ded713ecc1 | ||
|
|
890f1ef4d6 | ||
|
|
25796a27f0 | ||
|
|
327b126207 | ||
|
|
5298970764 | ||
|
|
6fef357742 | ||
|
|
5844550f9a | ||
|
|
c44426f579 | ||
|
|
b467a2f462 | ||
|
|
97ee8144be | ||
|
|
4ba8c4ae53 | ||
|
|
695787a326 | ||
|
|
e32db575b8 | ||
|
|
a30b87cdda | ||
|
|
20a3671055 | ||
|
|
2497900d3e | ||
|
|
c6a7ebb918 | ||
|
|
9d6e3523dd | ||
|
|
38e6b0b2b5 | ||
|
|
1229e07636 | ||
|
|
852e72f5e6 | ||
|
|
8b2b6b5115 | ||
|
|
f015f5cad4 | ||
|
|
612b6edb41 | ||
|
|
b633c8af96 | ||
|
|
079ae668c0 | ||
|
|
a5e038cf13 | ||
|
|
ec903900c9 | ||
|
|
9b6b0aba4e | ||
|
|
e5a52ee5ac | ||
|
|
6548e0dab6 | ||
|
|
2899b42107 | ||
|
|
a06f6e98bd | ||
|
|
2b51d15d87 | ||
|
|
cb3cc3234f | ||
|
|
b11c4c9b20 | ||
|
|
4b5d0a0b86 | ||
|
|
4fda5b40b8 | ||
|
|
719688f4c8 | ||
|
|
162b1c8a9b | ||
|
|
872d64494b | ||
|
|
96b10d40c3 | ||
|
|
28f1848b85 | ||
|
|
83c74b0017 | ||
|
|
a1a6ee244c | ||
|
|
6aafd20d60 | ||
|
|
1efa843ed8 | ||
|
|
eafecd3b6a | ||
|
|
e757479f85 | ||
|
|
c350c88267 | ||
|
|
827be605b3 | ||
|
|
8f9797627f | ||
|
|
75d77cd38e | ||
|
|
b518187da8 | ||
|
|
d5637172f2 | ||
|
|
b7bfc42697 | ||
|
|
53392471a5 |
@@ -23,7 +23,6 @@ Edit the files in the src/main/asciidoc/ directory instead.
|
||||
|
||||
image::https://circleci.com/gh/spring-cloud/spring-cloud-netflix/tree/main.svg?style=svg["CircleCI", link="https://circleci.com/gh/spring-cloud/spring-cloud-netflix/tree/main"]
|
||||
image::https://codecov.io/gh/spring-cloud/spring-cloud-netflix/branch/main/graph/badge.svg["Codecov", link="https://codecov.io/gh/spring-cloud/spring-cloud-netflix/branch/main"]
|
||||
image::https://api.codacy.com/project/badge/Grade/a6885a06921e4f72a0df0b7aabd6d118["Codacy code quality", link="https://www.codacy.com/app/Spring-Cloud/spring-cloud-netflix?utm_source=github.com&utm_medium=referral&utm_content=spring-cloud/spring-cloud-netflix&utm_campaign=Badge_Grade"]
|
||||
|
||||
|
||||
:doctype: book
|
||||
|
||||
+3
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.1.7</version>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-docs</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
@@ -18,6 +18,8 @@
|
||||
.*.eureka.*
|
||||
</configprops.inclusionPattern>
|
||||
<upload-docs-zip.phase>deploy</upload-docs-zip.phase>
|
||||
<!-- Don't upload docs jar to central / repo.spring.io -->
|
||||
<maven-deploy-plugin-default.phase>none</maven-deploy-plugin-default.phase>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -2,7 +2,6 @@ include::_attributes.adoc[]
|
||||
|
||||
image::https://circleci.com/gh/spring-cloud/spring-cloud-netflix/tree/main.svg?style=svg["CircleCI", link="https://circleci.com/gh/spring-cloud/spring-cloud-netflix/tree/main"]
|
||||
image::https://codecov.io/gh/spring-cloud/spring-cloud-netflix/branch/main/graph/badge.svg["Codecov", link="https://codecov.io/gh/spring-cloud/spring-cloud-netflix/branch/main"]
|
||||
image::https://api.codacy.com/project/badge/Grade/a6885a06921e4f72a0df0b7aabd6d118["Codacy code quality", link="https://www.codacy.com/app/Spring-Cloud/spring-cloud-netflix?utm_source=github.com&utm_medium=referral&utm_content=spring-cloud/spring-cloud-netflix&utm_campaign=Badge_Grade"]
|
||||
|
||||
|
||||
include::intro.adoc[]
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
|===
|
||||
|Name | Default | Description
|
||||
|
||||
|eureka.client.eureka-connection-idle-timeout-seconds | `30` | Indicates how much time (in seconds) that the HTTP connections to eureka server can stay idle before it can be closed. In the AWS environment, it is recommended that the values is 30 seconds or less, since the firewall cleans up the connection information after a few mins leaving the connection hanging in limbo.
|
||||
|eureka.client.eureka-server-connect-timeout-seconds | `5` | Indicates how long to wait (in seconds) before a connection to eureka server needs to timeout. Note that the connections in the client are pooled by org.apache.http.client.HttpClient and this setting affects the actual connection creation and also the wait time to get the connection from the pool.
|
||||
|eureka.client.eureka-connection-idle-timeout-seconds | `+++30+++` | Indicates how much time (in seconds) that the HTTP connections to eureka server can stay idle before it can be closed. In the AWS environment, it is recommended that the values is 30 seconds or less, since the firewall cleans up the connection information after a few mins leaving the connection hanging in limbo.
|
||||
|eureka.client.eureka-server-connect-timeout-seconds | `+++5+++` | Indicates how long to wait (in seconds) before a connection to eureka server needs to timeout. Note that the connections in the client are pooled by org.apache.http.client.HttpClient and this setting affects the actual connection creation and also the wait time to get the connection from the pool.
|
||||
|eureka.client.eureka-server-d-n-s-name | | Gets the DNS name to be queried to get the list of eureka servers.This information is not required if the contract returns the service urls by implementing serviceUrls. The DNS mechanism is used when useDnsForFetchingServiceUrls is set to true and the eureka client expects the DNS to configured a certain way so that it can fetch changing eureka servers dynamically. The changes are effective at runtime.
|
||||
|eureka.client.eureka-server-port | | Gets the port to be used to construct the service url to contact eureka server when the list of eureka servers come from the DNS.This information is not required if the contract returns the service urls eurekaServerServiceUrls(String). The DNS mechanism is used when useDnsForFetchingServiceUrls is set to true and the eureka client expects the DNS to configured a certain way so that it can fetch changing eureka servers dynamically. The changes are effective at runtime.
|
||||
|eureka.client.eureka-server-read-timeout-seconds | `8` | Indicates how long to wait (in seconds) before a read from eureka server needs to timeout.
|
||||
|eureka.client.eureka-server-total-connections | `200` | Gets the total number of connections that is allowed from eureka client to all eureka servers.
|
||||
|eureka.client.eureka-server-total-connections-per-host | `50` | Gets the total number of connections that is allowed from eureka client to a eureka server host.
|
||||
|eureka.client.eureka-server-read-timeout-seconds | `+++8+++` | Indicates how long to wait (in seconds) before a read from eureka server needs to timeout.
|
||||
|eureka.client.eureka-server-total-connections | `+++200+++` | Gets the total number of connections that is allowed from eureka client to all eureka servers.
|
||||
|eureka.client.eureka-server-total-connections-per-host | `+++50+++` | Gets the total number of connections that is allowed from eureka client to a eureka server host.
|
||||
|eureka.client.eureka-server-u-r-l-context | | Gets the URL context to be used to construct the service url to contact eureka server when the list of eureka servers come from the DNS. This information is not required if the contract returns the service urls from eurekaServerServiceUrls. The DNS mechanism is used when useDnsForFetchingServiceUrls is set to true and the eureka client expects the DNS to configured a certain way so that it can fetch changing eureka servers dynamically. The changes are effective at runtime.
|
||||
|eureka.client.eureka-service-url-poll-interval-seconds | `0` | Indicates how often(in seconds) to poll for changes to eureka server information. Eureka servers could be added or removed and this setting controls how soon the eureka clients should know about it.
|
||||
|eureka.client.prefer-same-zone-eureka | `true` | Indicates whether or not this instance should try to use the eureka server in the same zone for latency and/or other reason. Ideally eureka clients are configured to talk to servers in the same zone The changes are effective at runtime at the next registry fetch cycle as specified by registryFetchIntervalSeconds
|
||||
|eureka.client.register-with-eureka | `true` | Indicates whether or not this instance should register its information with eureka server for discovery by others. In some cases, you do not want your instances to be discovered whereas you just want do discover other instances.
|
||||
|eureka.server.peer-eureka-nodes-update-interval-ms | `0` |
|
||||
|eureka.server.peer-eureka-status-refresh-time-interval-ms | `0` |
|
||||
|ribbon.eureka.enabled | `true` | Enables the use of Eureka with Ribbon.
|
||||
|spring.cloud.loadbalancer.eureka.approximate-zone-from-hostname | `false` | Used to determine whether we should try to get the `zone` value from host name.
|
||||
|eureka.client.eureka-service-url-poll-interval-seconds | `+++0+++` | Indicates how often(in seconds) to poll for changes to eureka server information. Eureka servers could be added or removed and this setting controls how soon the eureka clients should know about it.
|
||||
|eureka.client.prefer-same-zone-eureka | `+++true+++` | Indicates whether or not this instance should try to use the eureka server in the same zone for latency and/or other reason. Ideally eureka clients are configured to talk to servers in the same zone The changes are effective at runtime at the next registry fetch cycle as specified by registryFetchIntervalSeconds
|
||||
|eureka.client.register-with-eureka | `+++true+++` | Indicates whether or not this instance should register its information with eureka server for discovery by others. In some cases, you do not want your instances to be discovered whereas you just want do discover other instances.
|
||||
|eureka.server.peer-eureka-nodes-update-interval-ms | `+++0+++` |
|
||||
|eureka.server.peer-eureka-status-refresh-time-interval-ms | `+++0+++` |
|
||||
|ribbon.eureka.enabled | `+++true+++` | Enables the use of Eureka with Ribbon.
|
||||
|spring.cloud.loadbalancer.eureka.approximate-zone-from-hostname | `+++false+++` | Used to determine whether we should try to get the `zone` value from host name.
|
||||
|
||||
|===
|
||||
@@ -80,6 +80,9 @@ See {github-code}/spring-cloud-netflix-eureka-client/src/main/java/org/springfra
|
||||
|
||||
To disable the Eureka Discovery Client, you can set `eureka.client.enabled` to `false`. Eureka Discovery Client will also be disabled when `spring.cloud.discovery.enabled` is set to `false`.
|
||||
|
||||
|
||||
NOTE: Specifying the version of the Spring Cloud Netflix Eureka server as a path parameter is not currently supported. This means you cannot set the version in the context path (`eurekaServerURLContext`). Instead, you can include the version in the server URL (for example, you can set `defaultZone: http://localhost:8761/eureka/v2`).
|
||||
|
||||
=== Authenticating with the Eureka Server
|
||||
|
||||
HTTP basic authentication is automatically added to your eureka client if one of the `eureka.client.serviceUrl.defaultZone` URLs has credentials embedded in it (curl style, as follows: `https://user:password@localhost:8761/eureka`).
|
||||
@@ -109,6 +112,19 @@ NOTE: Because of a limitation in Eureka, it is not possible to support per-serve
|
||||
|
||||
If you want to customize the RestTemplate used by the Eureka HTTP Client you may want to create a bean of `EurekaClientHttpRequestFactorySupplier` and provide your own logic for generating a `ClientHttpRequestFactory` instance.
|
||||
|
||||
All default timeout-related properties for RestTemplate used by the Eureka HTTP Client are set to infinite. Therefore, to specify the timeout values, you must specify the value directly with the properties in `eureka.client.rest-template-timeout`. (All timeout properties are in milliseconds.)
|
||||
|
||||
.application.yml
|
||||
[source,yaml]
|
||||
----
|
||||
eureka:
|
||||
client:
|
||||
rest-template-timeout:
|
||||
connect-timeout: 5000
|
||||
connect-request-timeout: 8000
|
||||
socket-timeout: 10000
|
||||
----
|
||||
|
||||
=== Status Page and Health Indicator
|
||||
|
||||
The status page and health indicators for a Eureka instance default to `/info` and `/health` respectively, which are the default locations of useful endpoints in a Spring Boot Actuator application.
|
||||
@@ -430,6 +446,10 @@ dependencyManagement {
|
||||
----
|
||||
====
|
||||
|
||||
=== `defaultOpenForTrafficCount` and its effect on EurekaServer warmup time
|
||||
|
||||
Netflix Eureka's `waitTimeInMsWhenSyncEmpty` setting is not taken into account in Spring Cloud Eureka server at the beginning. In order to enable the warmup time, set `eureka.server.defaultOpenForTrafficCount=0`.
|
||||
|
||||
[[spring-cloud-eureka-server-zones-and-regions]]
|
||||
=== High Availability, Zones and Regions
|
||||
|
||||
|
||||
@@ -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>3.1.1</version>
|
||||
<version>3.1.7</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>3.1.1</version>
|
||||
<version>3.1.8</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
<scm>
|
||||
@@ -21,8 +21,10 @@
|
||||
</scm>
|
||||
<properties>
|
||||
<bintray.package>netflix</bintray.package>
|
||||
<spring-cloud-commons.version>3.1.1</spring-cloud-commons.version>
|
||||
<spring-cloud-config.version>3.1.1</spring-cloud-config.version>
|
||||
<spring-cloud-commons.version>3.1.7</spring-cloud-commons.version>
|
||||
<spring-cloud-config.version>3.1.8</spring-cloud-config.version>
|
||||
<testcontainers.version>1.17.6</testcontainers.version>
|
||||
<mockserverclient.version>5.15.0</mockserverclient.version>
|
||||
|
||||
<!-- Sonar -->
|
||||
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
|
||||
@@ -81,6 +83,7 @@
|
||||
<ignoredResourcePattern>plugin.properties</ignoredResourcePattern>
|
||||
<ignoredResourcePattern>mozilla/public-suffix-list.txt</ignoredResourcePattern>
|
||||
</ignoredResourcePatterns>
|
||||
<checkTestClasspath>false</checkTestClasspath>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
@@ -146,6 +149,22 @@
|
||||
<version>${eureka-jersey.version}</version>
|
||||
</dependency>
|
||||
<!-- end eureka deps -->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>mockserver</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${testcontainers.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mock-server</groupId>
|
||||
<artifactId>mockserver-client-java</artifactId>
|
||||
<version>${mockserverclient.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<reporting>
|
||||
|
||||
@@ -4,7 +4,7 @@ set -o errexit
|
||||
|
||||
mkdir -p target
|
||||
|
||||
SCRIPT_URL="https://raw.githubusercontent.com/spring-cloud-samples/brewery/main/runAcceptanceTests.sh"
|
||||
SCRIPT_URL="https://raw.githubusercontent.com/spring-cloud-samples/brewery/3.1.x/runAcceptanceTests.sh"
|
||||
AT_WHAT_TO_TEST="EUREKA"
|
||||
|
||||
cd target
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-dependencies-parent</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.1.8</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-dependencies</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.1.7</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>spring-cloud-netflix-dependencies</name>
|
||||
<description>Spring Cloud Netflix Dependencies</description>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.1.7</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-eureka-client-tls-tests</artifactId>
|
||||
@@ -115,6 +115,12 @@
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.1.7</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-eureka-client</artifactId>
|
||||
@@ -40,7 +40,7 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-config-server</artifactId>
|
||||
<optional>true</optional>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
@@ -140,5 +140,20 @@
|
||||
<artifactId>reactor-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>mockserver</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mock-server</groupId>
|
||||
<artifactId>mockserver-client-java</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
+46
-36
@@ -19,19 +19,21 @@ package org.springframework.cloud.netflix.eureka;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.netflix.appinfo.HealthCheckHandler;
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthContributor;
|
||||
import org.springframework.boot.actuate.health.CompositeReactiveHealthContributor;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthContributor;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.NamedContributor;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthContributor;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.actuate.health.StatusAggregator;
|
||||
@@ -58,6 +60,7 @@ import org.springframework.util.Assert;
|
||||
* @author Spencer Gibb
|
||||
* @author Nowrin Anwar Joyita
|
||||
* @author Bertrand Renuart
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @see HealthCheckHandler
|
||||
* @see StatusAggregator
|
||||
*/
|
||||
@@ -67,7 +70,7 @@ public class EurekaHealthCheckHandler
|
||||
private static final Map<Status, InstanceInfo.InstanceStatus> STATUS_MAPPING = new HashMap<Status, InstanceInfo.InstanceStatus>() {
|
||||
{
|
||||
put(Status.UNKNOWN, InstanceStatus.UNKNOWN);
|
||||
put(Status.OUT_OF_SERVICE, InstanceStatus.OUT_OF_SERVICE);
|
||||
put(Status.OUT_OF_SERVICE, InstanceStatus.DOWN);
|
||||
put(Status.DOWN, InstanceStatus.DOWN);
|
||||
put(Status.UP, InstanceStatus.UP);
|
||||
}
|
||||
@@ -77,14 +80,14 @@ public class EurekaHealthCheckHandler
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private Map<String, HealthIndicator> healthIndicators = new HashMap<>();
|
||||
private Map<String, HealthContributor> healthContributors = new HashMap<>();
|
||||
|
||||
/**
|
||||
* {@code true} until the context is stopped.
|
||||
*/
|
||||
private boolean running = true;
|
||||
|
||||
private Map<String, ReactiveHealthIndicator> reactiveHealthIndicators = new HashMap<>();
|
||||
private Map<String, ReactiveHealthContributor> reactiveHealthContributors = new HashMap<>();
|
||||
|
||||
public EurekaHealthCheckHandler(StatusAggregator statusAggregator) {
|
||||
this.statusAggregator = statusAggregator;
|
||||
@@ -99,39 +102,28 @@ public class EurekaHealthCheckHandler
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
final Map<String, HealthIndicator> healthIndicators = applicationContext.getBeansOfType(HealthIndicator.class);
|
||||
final Map<String, ReactiveHealthIndicator> reactiveHealthIndicators = applicationContext
|
||||
.getBeansOfType(ReactiveHealthIndicator.class);
|
||||
|
||||
populateHealthIndicators(healthIndicators);
|
||||
populateReactiveHealthIndicators(reactiveHealthIndicators);
|
||||
populateHealthContributors(applicationContext.getBeansOfType(HealthContributor.class));
|
||||
reactiveHealthContributors.putAll(applicationContext.getBeansOfType(ReactiveHealthContributor.class));
|
||||
}
|
||||
|
||||
void populateHealthIndicators(Map<String, HealthIndicator> healthIndicators) {
|
||||
for (Map.Entry<String, HealthIndicator> entry : healthIndicators.entrySet()) {
|
||||
void populateHealthContributors(Map<String, HealthContributor> healthContributors) {
|
||||
for (Map.Entry<String, HealthContributor> entry : healthContributors.entrySet()) {
|
||||
// ignore EurekaHealthIndicator and flatten the rest of the composite
|
||||
// otherwise there is a never ending cycle of down. See gh-643
|
||||
if (entry.getValue() instanceof DiscoveryCompositeHealthContributor) {
|
||||
DiscoveryCompositeHealthContributor indicator = (DiscoveryCompositeHealthContributor) entry.getValue();
|
||||
indicator.forEach(contributor -> {
|
||||
if (!(contributor.getContributor() instanceof EurekaHealthIndicator)) {
|
||||
this.healthIndicators.put(contributor.getName(),
|
||||
(HealthIndicator) contributor.getContributor());
|
||||
indicator.getIndicators().forEach((name, discoveryHealthIndicator) -> {
|
||||
if (!(discoveryHealthIndicator instanceof EurekaHealthIndicator)) {
|
||||
this.healthContributors.put(name, (HealthIndicator) discoveryHealthIndicator::health);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.healthIndicators.put(entry.getKey(), entry.getValue());
|
||||
this.healthContributors.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void populateReactiveHealthIndicators(Map<String, ReactiveHealthIndicator> reactiveHealthIndicators) {
|
||||
for (Map.Entry<String, ReactiveHealthIndicator> entry : reactiveHealthIndicators.entrySet()) {
|
||||
this.reactiveHealthIndicators.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InstanceStatus getStatus(InstanceStatus instanceStatus) {
|
||||
if (running) {
|
||||
@@ -151,21 +143,39 @@ public class EurekaHealthCheckHandler
|
||||
}
|
||||
|
||||
protected Status getStatus(StatusAggregator statusAggregator) {
|
||||
Status status;
|
||||
|
||||
Set<Status> statusSet = new HashSet<>();
|
||||
if (healthIndicators != null) {
|
||||
statusSet.addAll(healthIndicators.values().stream().map(HealthIndicator::health).map(Health::getStatus)
|
||||
.collect(Collectors.toSet()));
|
||||
for (HealthContributor contributor : healthContributors.values()) {
|
||||
processContributor(statusSet, contributor);
|
||||
}
|
||||
|
||||
if (reactiveHealthIndicators != null) {
|
||||
statusSet.addAll(reactiveHealthIndicators.values().stream().map(ReactiveHealthIndicator::health)
|
||||
.map(Mono::block).filter(Objects::nonNull).map(Health::getStatus).collect(Collectors.toSet()));
|
||||
for (ReactiveHealthContributor contributor : reactiveHealthContributors.values()) {
|
||||
processContributor(statusSet, contributor);
|
||||
}
|
||||
return statusAggregator.getAggregateStatus(statusSet);
|
||||
}
|
||||
|
||||
status = statusAggregator.getAggregateStatus(statusSet);
|
||||
return status;
|
||||
private void processContributor(Set<Status> statusSet, HealthContributor contributor) {
|
||||
if (contributor instanceof CompositeHealthContributor) {
|
||||
for (NamedContributor<HealthContributor> contrib : (CompositeHealthContributor) contributor) {
|
||||
processContributor(statusSet, contrib.getContributor());
|
||||
}
|
||||
}
|
||||
else if (contributor instanceof HealthIndicator) {
|
||||
statusSet.add(((HealthIndicator) contributor).health().getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
private void processContributor(Set<Status> statusSet, ReactiveHealthContributor contributor) {
|
||||
if (contributor instanceof CompositeReactiveHealthContributor) {
|
||||
for (NamedContributor<ReactiveHealthContributor> contrib : (CompositeReactiveHealthContributor) contributor) {
|
||||
processContributor(statusSet, contrib.getContributor());
|
||||
}
|
||||
}
|
||||
else if (contributor instanceof ReactiveHealthIndicator) {
|
||||
Health health = ((ReactiveHealthIndicator) contributor).health().block();
|
||||
if (health != null) {
|
||||
statusSet.add(health.getStatus());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected InstanceStatus mapToInstanceStatus(Status status) {
|
||||
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* Properties for configuring timeouts used in {@link RestTemplate} required by
|
||||
* {@link RestTemplateEurekaHttpClient}.
|
||||
*
|
||||
* @author Jiwon Jeon
|
||||
* @since 3.1.6
|
||||
*/
|
||||
@ConfigurationProperties("eureka.client.rest-template-timeout")
|
||||
public class RestTemplateTimeoutProperties {
|
||||
|
||||
/**
|
||||
* Default values are set to -1 according to {@link RequestConfig .DEFAULT}.
|
||||
*/
|
||||
private int connectTimeout = -1;
|
||||
|
||||
private int connectRequestTimeout = -1;
|
||||
|
||||
private int socketTimeout = -1;
|
||||
|
||||
public int getConnectTimeout() {
|
||||
return connectTimeout;
|
||||
}
|
||||
|
||||
public int getConnectRequestTimeout() {
|
||||
return connectRequestTimeout;
|
||||
}
|
||||
|
||||
public int getSocketTimeout() {
|
||||
return socketTimeout;
|
||||
}
|
||||
|
||||
public void setConnectTimeout(int connectTimeout) {
|
||||
this.connectTimeout = connectTimeout;
|
||||
}
|
||||
|
||||
public void setConnectRequestTimeout(int connectRequestTimeout) {
|
||||
this.connectRequestTimeout = connectRequestTimeout;
|
||||
}
|
||||
|
||||
public void setSocketTimeout(int socketTimeout) {
|
||||
this.socketTimeout = socketTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RestTemplateTimeoutProperties that = (RestTemplateTimeoutProperties) o;
|
||||
|
||||
return connectTimeout == that.connectTimeout && connectRequestTimeout == that.connectRequestTimeout
|
||||
&& socketTimeout == that.socketTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(connectTimeout, connectRequestTimeout, socketTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RestTemplateTimeoutProperties{" + ", connectTimeout=" + connectTimeout + ", connectRequestTimeout="
|
||||
+ connectRequestTimeout + ", socketTimeout=" + socketTimeout + '}';
|
||||
}
|
||||
|
||||
}
|
||||
+6
-2
@@ -31,9 +31,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClas
|
||||
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.cloud.configuration.SSLContextFactory;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.MutableDiscoveryClientOptionalArgs;
|
||||
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.RestTemplateDiscoveryClientOptionalArgs;
|
||||
@@ -46,6 +48,7 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(RestTemplateTimeoutProperties.class)
|
||||
public class DiscoveryClientOptionalArgsConfiguration {
|
||||
|
||||
protected static final Log logger = LogFactory.getLog(DiscoveryClientOptionalArgsConfiguration.class);
|
||||
@@ -75,8 +78,9 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
|
||||
EurekaClientHttpRequestFactorySupplier defaultEurekaClientHttpRequestFactorySupplier() {
|
||||
return new DefaultEurekaClientHttpRequestFactorySupplier();
|
||||
EurekaClientHttpRequestFactorySupplier defaultEurekaClientHttpRequestFactorySupplier(
|
||||
RestTemplateTimeoutProperties restTemplateTimeoutProperties) {
|
||||
return new DefaultEurekaClientHttpRequestFactorySupplier(restTemplateTimeoutProperties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+7
-6
@@ -24,9 +24,9 @@ import com.netflix.discovery.EurekaClient;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.config.server.config.ConfigServerProperties;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -36,21 +36,22 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties
|
||||
@ConditionalOnClass({ EurekaInstanceConfigBean.class, EurekaClient.class, ConfigServerProperties.class })
|
||||
@ConditionalOnClass(value = { EurekaInstanceConfigBean.class, EurekaClient.class },
|
||||
name = "org.springframework.cloud.config.server.config.ConfigServerProperties")
|
||||
public class EurekaClientConfigServerAutoConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private EurekaInstanceConfig instance;
|
||||
|
||||
@Autowired(required = false)
|
||||
private ConfigServerProperties server;
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (this.instance == null || this.server == null) {
|
||||
if (this.instance == null) {
|
||||
return;
|
||||
}
|
||||
String prefix = this.server.getPrefix();
|
||||
String prefix = this.env.getProperty("spring.cloud.config.server.prefix");
|
||||
if (StringUtils.hasText(prefix) && !StringUtils.hasText(this.instance.getMetadataMap().get("configPath"))) {
|
||||
this.instance.getMetadataMap().put("configPath", prefix);
|
||||
}
|
||||
|
||||
+46
-19
@@ -16,11 +16,18 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.config;
|
||||
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import org.springframework.boot.BootstrapContext;
|
||||
import org.springframework.boot.BootstrapRegistry;
|
||||
import org.springframework.boot.BootstrapRegistryInitializer;
|
||||
import org.springframework.boot.context.properties.bind.BindHandler;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.config.client.ConfigClientProperties;
|
||||
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
@@ -37,33 +44,53 @@ public class EurekaConfigServerBootstrapper implements BootstrapRegistryInitiali
|
||||
if (!ClassUtils.isPresent("org.springframework.cloud.config.client.ConfigServerInstanceProvider", null)) {
|
||||
return;
|
||||
}
|
||||
registry.registerIfAbsent(EurekaClientConfigBean.class, context -> {
|
||||
Binder binder = context.get(Binder.class);
|
||||
if (!getDiscoveryEnabled(binder)) {
|
||||
return null;
|
||||
|
||||
// It is important that we pass a lambda for the Function or else we will get a
|
||||
// ClassNotFoundException when config is not on the classpath
|
||||
registry.registerIfAbsent(ConfigServerInstanceProvider.Function.class, EurekaFunction::create);
|
||||
}
|
||||
|
||||
private static Boolean getDiscoveryEnabled(Binder binder) {
|
||||
return binder.bind(ConfigClientProperties.CONFIG_DISCOVERY_ENABLED, Boolean.class).orElse(false)
|
||||
&& binder.bind("eureka.client.enabled", Boolean.class).orElse(true)
|
||||
&& binder.bind("spring.cloud.discovery.enabled", Boolean.class).orElse(true);
|
||||
}
|
||||
|
||||
final static class EurekaFunction implements ConfigServerInstanceProvider.Function {
|
||||
|
||||
private final BootstrapContext context;
|
||||
|
||||
static EurekaFunction create(BootstrapContext context) {
|
||||
return new EurekaFunction(context);
|
||||
}
|
||||
|
||||
private EurekaFunction(BootstrapContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ServiceInstance> apply(String serviceId, Binder binder, BindHandler bindHandler, Log log) {
|
||||
if (binder == null || !getDiscoveryEnabled(binder)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return binder.bind(EurekaClientConfigBean.PREFIX, EurekaClientConfigBean.class)
|
||||
EurekaClientConfigBean config = binder.bind(EurekaClientConfigBean.PREFIX, EurekaClientConfigBean.class)
|
||||
.orElseGet(EurekaClientConfigBean::new);
|
||||
});
|
||||
|
||||
registry.registerIfAbsent(ConfigServerInstanceProvider.Function.class, context -> {
|
||||
Binder binder = context.get(Binder.class);
|
||||
if (!getDiscoveryEnabled(binder)) {
|
||||
return null;
|
||||
}
|
||||
EurekaClientConfigBean config = context.get(EurekaClientConfigBean.class);
|
||||
EurekaHttpClient httpClient = new RestTemplateTransportClientFactory(
|
||||
context.getOrElse(TlsProperties.class, null),
|
||||
context.getOrElse(EurekaClientHttpRequestFactorySupplier.class,
|
||||
new DefaultEurekaClientHttpRequestFactorySupplier()))
|
||||
.newClient(HostnameBasedUrlRandomizer.randomEndpoint(config, binder));
|
||||
return new EurekaConfigServerInstanceProvider(httpClient, config)::getInstances;
|
||||
});
|
||||
}
|
||||
return new EurekaConfigServerInstanceProvider(httpClient, config).getInstances(serviceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ServiceInstance> apply(String serviceId) {
|
||||
// This should never be called now but is here for backward
|
||||
// compatibility
|
||||
return apply(serviceId, null, null, null);
|
||||
}
|
||||
|
||||
private Boolean getDiscoveryEnabled(Binder binder) {
|
||||
return binder.bind(ConfigClientProperties.CONFIG_DISCOVERY_ENABLED, Boolean.class).orElse(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+28
@@ -19,10 +19,12 @@ package org.springframework.cloud.netflix.eureka.http;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
|
||||
import org.springframework.cloud.netflix.eureka.RestTemplateTimeoutProperties;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -32,10 +34,26 @@ import org.springframework.lang.Nullable;
|
||||
* {@link HttpClients}.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Jiwon Jeon
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public class DefaultEurekaClientHttpRequestFactorySupplier implements EurekaClientHttpRequestFactorySupplier {
|
||||
|
||||
private final RestTemplateTimeoutProperties restTemplateTimeoutProperties;
|
||||
|
||||
/**
|
||||
* @deprecated in favour of
|
||||
* {@link DefaultEurekaClientHttpRequestFactorySupplier#DefaultEurekaClientHttpRequestFactorySupplier(RestTemplateTimeoutProperties)}
|
||||
*/
|
||||
@Deprecated
|
||||
public DefaultEurekaClientHttpRequestFactorySupplier() {
|
||||
this.restTemplateTimeoutProperties = new RestTemplateTimeoutProperties();
|
||||
}
|
||||
|
||||
public DefaultEurekaClientHttpRequestFactorySupplier(RestTemplateTimeoutProperties restTemplateTimeoutProperties) {
|
||||
this.restTemplateTimeoutProperties = restTemplateTimeoutProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientHttpRequestFactory get(SSLContext sslContext, @Nullable HostnameVerifier hostnameVerifier) {
|
||||
HttpClientBuilder httpClientBuilder = HttpClients.custom();
|
||||
@@ -45,10 +63,20 @@ public class DefaultEurekaClientHttpRequestFactorySupplier implements EurekaClie
|
||||
if (hostnameVerifier != null) {
|
||||
httpClientBuilder = httpClientBuilder.setSSLHostnameVerifier(hostnameVerifier);
|
||||
}
|
||||
if (restTemplateTimeoutProperties != null) {
|
||||
httpClientBuilder.setDefaultRequestConfig(buildRequestConfig());
|
||||
}
|
||||
|
||||
CloseableHttpClient httpClient = httpClientBuilder.build();
|
||||
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
|
||||
requestFactory.setHttpClient(httpClient);
|
||||
return requestFactory;
|
||||
}
|
||||
|
||||
private RequestConfig buildRequestConfig() {
|
||||
return RequestConfig.custom().setConnectTimeout(restTemplateTimeoutProperties.getConnectTimeout())
|
||||
.setConnectionRequestTimeout(restTemplateTimeoutProperties.getConnectRequestTimeout())
|
||||
.setSocketTimeout(restTemplateTimeoutProperties.getSocketTimeout()).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-18
@@ -148,8 +148,7 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
|
||||
converter.setObjectMapper(new ObjectMapper().setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE));
|
||||
|
||||
SimpleModule jsonModule = new SimpleModule();
|
||||
jsonModule.setSerializerModifier(createJsonSerializerModifier()); // keyFormatter,
|
||||
// compact));
|
||||
jsonModule.setSerializerModifier(createJsonSerializerModifier());
|
||||
converter.getObjectMapper().registerModule(jsonModule);
|
||||
|
||||
converter.getObjectMapper().configure(SerializationFeature.WRAP_ROOT_VALUE, true);
|
||||
@@ -157,25 +156,10 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
|
||||
converter.getObjectMapper().addMixIn(Applications.class, ApplicationsJsonMixIn.class);
|
||||
converter.getObjectMapper().addMixIn(InstanceInfo.class, InstanceInfoJsonMixIn.class);
|
||||
|
||||
// converter.getObjectMapper().addMixIn(DataCenterInfo.class,
|
||||
// DataCenterInfoXmlMixIn.class);
|
||||
// converter.getObjectMapper().addMixIn(InstanceInfo.PortWrapper.class,
|
||||
// PortWrapperXmlMixIn.class);
|
||||
// converter.getObjectMapper().addMixIn(Application.class,
|
||||
// ApplicationXmlMixIn.class);
|
||||
// converter.getObjectMapper().addMixIn(Applications.class,
|
||||
// ApplicationsXmlMixIn.class);
|
||||
|
||||
return converter;
|
||||
}
|
||||
|
||||
public static BeanSerializerModifier createJsonSerializerModifier() { // final
|
||||
// KeyFormatter
|
||||
// keyFormatter,
|
||||
// final
|
||||
// boolean
|
||||
// compactMode)
|
||||
// {
|
||||
public static BeanSerializerModifier createJsonSerializerModifier() {
|
||||
return new BeanSerializerModifier() {
|
||||
@Override
|
||||
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc,
|
||||
|
||||
+40
-45
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
@@ -28,12 +26,12 @@ import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpResponse;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpResponse.EurekaHttpResponseBuilder;
|
||||
import com.netflix.discovery.util.StringUtil;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.reactive.function.BodyInserters;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -46,8 +44,6 @@ import static com.netflix.discovery.shared.transport.EurekaHttpResponse.anEureka
|
||||
*/
|
||||
public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private WebClient webClient;
|
||||
|
||||
public WebClientEurekaHttpClient(WebClient webClient) {
|
||||
@@ -56,16 +52,18 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Void> register(InstanceInfo info) {
|
||||
return webClient.post().uri("apps/" + info.getAppName(), Void.class).body(BodyInserters.fromValue(info))
|
||||
return webClient.post().uri("apps/" + info.getAppName()).body(BodyInserters.fromValue(info))
|
||||
.header(HttpHeaders.ACCEPT_ENCODING, "gzip")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).exchange()
|
||||
.map(response -> eurekaHttpResponse(response)).block();
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).retrieve()
|
||||
.onStatus(HttpStatus::isError, this::ignoreError).toBodilessEntity().map(this::eurekaHttpResponse)
|
||||
.block();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Void> cancel(String appName, String id) {
|
||||
return webClient.delete().uri("apps/" + appName + '/' + id, Void.class).exchange()
|
||||
.map(response -> eurekaHttpResponse(response)).block();
|
||||
return webClient.delete().uri("apps/" + appName + '/' + id).retrieve()
|
||||
.onStatus(HttpStatus::isError, this::ignoreError).toBodilessEntity().map(this::eurekaHttpResponse)
|
||||
.block();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,14 +73,15 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
+ "&lastDirtyTimestamp=" + info.getLastDirtyTimestamp().toString()
|
||||
+ (overriddenStatus != null ? "&overriddenstatus=" + overriddenStatus.name() : "");
|
||||
|
||||
ClientResponse response = webClient.put().uri(urlPath, InstanceInfo.class)
|
||||
ResponseEntity<InstanceInfo> response = webClient.put().uri(urlPath)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).exchange().block();
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).retrieve()
|
||||
.onStatus(HttpStatus::isError, this::ignoreError).toEntity(InstanceInfo.class).block();
|
||||
|
||||
EurekaHttpResponseBuilder<InstanceInfo> builder = anEurekaHttpResponse(statusCodeValueOf(response),
|
||||
InstanceInfo.class).headers(headersOf(response));
|
||||
|
||||
InstanceInfo entity = response.toEntity(InstanceInfo.class).block().getBody();
|
||||
InstanceInfo entity = response.getBody();
|
||||
|
||||
if (entity != null) {
|
||||
builder.entity(entity);
|
||||
@@ -98,9 +97,9 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
String urlPath = "apps/" + appName + '/' + id + "/status?value=" + newStatus.name() + "&lastDirtyTimestamp="
|
||||
+ info.getLastDirtyTimestamp().toString();
|
||||
|
||||
return webClient.put().uri(urlPath, Void.class)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).exchange()
|
||||
.map(response -> eurekaHttpResponse(response)).block();
|
||||
return webClient.put().uri(urlPath).header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.retrieve().onStatus(HttpStatus::isError, this::ignoreError).toBodilessEntity()
|
||||
.map(this::eurekaHttpResponse).block();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,9 +107,9 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
String urlPath = "apps/" + appName + '/' + id + "/status?lastDirtyTimestamp="
|
||||
+ info.getLastDirtyTimestamp().toString();
|
||||
|
||||
return webClient.delete().uri(urlPath, Void.class)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).exchange()
|
||||
.map(response -> eurekaHttpResponse(response)).block();
|
||||
return webClient.delete().uri(urlPath).header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.retrieve().onStatus(HttpStatus::isError, this::ignoreError).toBodilessEntity()
|
||||
.map(this::eurekaHttpResponse).block();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,13 +124,14 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
url = url + (urlPath.contains("?") ? "&" : "?") + "regions=" + StringUtil.join(regions);
|
||||
}
|
||||
|
||||
ClientResponse response = webClient.get().uri(url, Applications.class)
|
||||
ResponseEntity<Applications> response = webClient.get().uri(url)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).exchange().block();
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).retrieve()
|
||||
.onStatus(HttpStatus::isError, this::ignoreError).toEntity(Applications.class).block();
|
||||
|
||||
int statusCode = statusCodeValueOf(response);
|
||||
|
||||
Applications body = response.toEntity(Applications.class).block().getBody();
|
||||
Applications body = response.getBody();
|
||||
|
||||
return anEurekaHttpResponse(statusCode, statusCode == HttpStatus.OK.value() && body != null ? body : null)
|
||||
.headers(headersOf(response)).build();
|
||||
@@ -155,11 +155,12 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
@Override
|
||||
public EurekaHttpResponse<Application> getApplication(String appName) {
|
||||
|
||||
ClientResponse response = webClient.get().uri("apps/" + appName, Application.class)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).exchange().block();
|
||||
ResponseEntity<Application> response = webClient.get().uri("apps/" + appName)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).retrieve()
|
||||
.onStatus(HttpStatus::isError, this::ignoreError).toEntity(Application.class).block();
|
||||
|
||||
int statusCode = statusCodeValueOf(response);
|
||||
Application body = response.toEntity(Application.class).block().getBody();
|
||||
Application body = response.getBody();
|
||||
|
||||
Application application = statusCode == HttpStatus.OK.value() && body != null ? body : null;
|
||||
|
||||
@@ -177,11 +178,12 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
}
|
||||
|
||||
private EurekaHttpResponse<InstanceInfo> getInstanceInternal(String urlPath) {
|
||||
ClientResponse response = webClient.get().uri(urlPath, InstanceInfo.class)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).exchange().block();
|
||||
ResponseEntity<InstanceInfo> response = webClient.get().uri(urlPath)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).retrieve()
|
||||
.onStatus(HttpStatus::isError, this::ignoreError).toEntity(InstanceInfo.class).block();
|
||||
|
||||
int statusCode = statusCodeValueOf(response);
|
||||
InstanceInfo body = response.toEntity(InstanceInfo.class).block().getBody();
|
||||
InstanceInfo body = response.getBody();
|
||||
|
||||
return anEurekaHttpResponse(statusCode, statusCode == HttpStatus.OK.value() && body != null ? body : null)
|
||||
.headers(headersOf(response)).build();
|
||||
@@ -196,26 +198,19 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
return this.webClient;
|
||||
}
|
||||
|
||||
private static Map<String, String> headersOf(ClientResponse response) {
|
||||
ClientResponse.Headers httpHeaders = response.headers();
|
||||
if (httpHeaders == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
HttpHeaders asHeaders = httpHeaders.asHttpHeaders();
|
||||
if (asHeaders == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
asHeaders.entrySet().stream()
|
||||
.forEach(entry -> entry.getValue().stream().forEach(v -> headers.put(entry.getKey(), v)));
|
||||
return headers;
|
||||
private Mono<? extends Throwable> ignoreError(ClientResponse response) {
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
private int statusCodeValueOf(ClientResponse response) {
|
||||
return response.statusCode().value();
|
||||
private static Map<String, String> headersOf(ResponseEntity<?> response) {
|
||||
return response.getHeaders().toSingleValueMap();
|
||||
}
|
||||
|
||||
private EurekaHttpResponse<Void> eurekaHttpResponse(ClientResponse response) {
|
||||
private int statusCodeValueOf(ResponseEntity<?> response) {
|
||||
return response.getStatusCode().value();
|
||||
}
|
||||
|
||||
private EurekaHttpResponse<Void> eurekaHttpResponse(ResponseEntity<?> response) {
|
||||
return anEurekaHttpResponse(statusCodeValueOf(response)).headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
|
||||
+115
-14
@@ -16,18 +16,23 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthContributor;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthContributor;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.NamedContributor;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.SimpleStatusAggregator;
|
||||
import org.springframework.cloud.client.discovery.health.DiscoveryClientHealthIndicator;
|
||||
@@ -44,6 +49,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
* @author Nowrin Anwar Joyita
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
class EurekaHealthCheckHandlerTests {
|
||||
|
||||
@@ -63,7 +69,7 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAllUp() throws Exception {
|
||||
void testAllUp() {
|
||||
initialize(UpHealthConfiguration.class, ReactiveUpHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
|
||||
@@ -71,7 +77,7 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHealthCheckNotReturnedWhenStopped() throws Exception {
|
||||
void testHealthCheckNotReturnedWhenStopped() {
|
||||
initialize(UpHealthConfiguration.class);
|
||||
|
||||
healthCheckHandler.stop();
|
||||
@@ -84,7 +90,7 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDownWithBlockingIndicators() throws Exception {
|
||||
void testDownWithBlockingIndicators() {
|
||||
initialize(UpHealthConfiguration.class, DownHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
|
||||
@@ -92,7 +98,7 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDownWithReactiveIndicators() throws Exception {
|
||||
void testDownWithReactiveIndicators() {
|
||||
initialize(UpHealthConfiguration.class, ReactiveDownHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
|
||||
@@ -100,7 +106,7 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDownWhenBlockingIndicatorUpAndReactiveDown() throws Exception {
|
||||
void testDownWhenBlockingIndicatorUpAndReactiveDown() {
|
||||
initialize(ReactiveUpHealthConfiguration.class, DownHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = this.healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
|
||||
@@ -108,7 +114,7 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDownWhenBlockingIndicatorDownAndReactiveUp() throws Exception {
|
||||
void testDownWhenBlockingIndicatorDownAndReactiveUp() {
|
||||
initialize(ReactiveUpHealthConfiguration.class, ReactiveDownHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = this.healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
|
||||
@@ -116,7 +122,7 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnknown() throws Exception {
|
||||
void testUnknown() {
|
||||
initialize(FatalHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
|
||||
@@ -124,15 +130,38 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // FIXME: 3.0.0
|
||||
void testEurekaIgnored() throws Exception {
|
||||
void testEurekaIgnored() {
|
||||
initialize(EurekaDownHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UP);
|
||||
assertThat(status).isEqualTo(InstanceStatus.UP);
|
||||
}
|
||||
|
||||
private void initialize(Class<?>... configurations) throws Exception {
|
||||
@Test
|
||||
void testCompositeComponentsDown() {
|
||||
initialize(CompositeComponentsDownHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UP);
|
||||
assertThat(status).isEqualTo(InstanceStatus.DOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCompositeComponentsUp() {
|
||||
initialize(CompositeComponentsUpHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UP);
|
||||
assertThat(status).isEqualTo(InstanceStatus.UP);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCompositeComponentsOneDown() {
|
||||
initialize(CompositeComponentsOneDownHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UP);
|
||||
assertThat(status).isEqualTo(InstanceStatus.DOWN);
|
||||
}
|
||||
|
||||
private void initialize(Class<?>... configurations) {
|
||||
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(configurations);
|
||||
healthCheckHandler.setApplicationContext(applicationContext);
|
||||
healthCheckHandler.afterPropertiesSet();
|
||||
@@ -144,7 +173,7 @@ class EurekaHealthCheckHandlerTests {
|
||||
public HealthIndicator healthIndicator() {
|
||||
return new AbstractHealthIndicator() {
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
builder.up();
|
||||
}
|
||||
};
|
||||
@@ -158,7 +187,7 @@ class EurekaHealthCheckHandlerTests {
|
||||
public HealthIndicator healthIndicator() {
|
||||
return new AbstractHealthIndicator() {
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
builder.down();
|
||||
}
|
||||
};
|
||||
@@ -172,7 +201,7 @@ class EurekaHealthCheckHandlerTests {
|
||||
public HealthIndicator healthIndicator() {
|
||||
return new AbstractHealthIndicator() {
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
builder.status("fatal");
|
||||
}
|
||||
};
|
||||
@@ -238,4 +267,76 @@ class EurekaHealthCheckHandlerTests {
|
||||
|
||||
}
|
||||
|
||||
protected static class CompositeComponentsDownHealthConfiguration {
|
||||
|
||||
@Bean
|
||||
public CompositeHealthContributor compositeHealthContributor() {
|
||||
return new TestCompositeHealthContributor(InstanceStatus.DOWN, InstanceStatus.DOWN);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static class CompositeComponentsUpHealthConfiguration {
|
||||
|
||||
@Bean
|
||||
public CompositeHealthContributor compositeHealthContributor() {
|
||||
return new TestCompositeHealthContributor(InstanceStatus.UP, InstanceStatus.UP);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected static class CompositeComponentsOneDownHealthConfiguration {
|
||||
|
||||
@Bean
|
||||
public CompositeHealthContributor compositeHealthContributor() {
|
||||
return new TestCompositeHealthContributor(InstanceStatus.UP, InstanceStatus.DOWN);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestCompositeHealthContributor implements CompositeHealthContributor {
|
||||
|
||||
private final Map<String, HealthContributor> contributorMap = new HashMap<>();
|
||||
|
||||
TestCompositeHealthContributor(InstanceStatus firstContributorStatus, InstanceStatus secondContributorStatus) {
|
||||
contributorMap.put("first", new AbstractHealthIndicator() {
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
builder.status(firstContributorStatus.name());
|
||||
}
|
||||
});
|
||||
contributorMap.put("second", new AbstractHealthIndicator() {
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) {
|
||||
builder.status(secondContributorStatus.name());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public HealthContributor getContributor(String name) {
|
||||
return contributorMap.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<NamedContributor<HealthContributor>> iterator() {
|
||||
Iterator<Map.Entry<String, HealthContributor>> iterator = contributorMap.entrySet().iterator();
|
||||
return new Iterator<NamedContributor<HealthContributor>>() {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedContributor<HealthContributor> next() {
|
||||
Map.Entry<String, HealthContributor> entry = iterator.next();
|
||||
return NamedContributor.of(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2013-2023 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.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.BeanDescription;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationConfig;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
|
||||
import com.fasterxml.jackson.databind.ser.std.BeanSerializerBase;
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.discovery.converters.jackson.serializer.InstanceInfoJsonBeanSerializer;
|
||||
import com.netflix.discovery.shared.Application;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockserver.client.MockServerClient;
|
||||
import org.testcontainers.containers.MockServerContainer;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.config.environment.Environment;
|
||||
import org.springframework.cloud.config.environment.PropertySource;
|
||||
import org.springframework.cloud.netflix.eureka.http.EurekaApplications;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockserver.model.HttpRequest.request;
|
||||
import static org.mockserver.model.HttpResponse.response;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@Testcontainers
|
||||
public class EurekaConfigServerBootstrapperIT {
|
||||
|
||||
public static final DockerImageName MOCKSERVER_IMAGE = DockerImageName.parse("mockserver/mockserver")
|
||||
.withTag("mockserver-" + MockServerClient.class.getPackage().getImplementationVersion());
|
||||
|
||||
@Container
|
||||
static MockServerContainer mockServer = new MockServerContainer(MOCKSERVER_IMAGE);
|
||||
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@BeforeEach
|
||||
void before() {
|
||||
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void after() {
|
||||
this.context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contextLoads() throws JsonProcessingException {
|
||||
Environment environment = new Environment("test", "default");
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("hello", "world");
|
||||
PropertySource p = new PropertySource("p1", properties);
|
||||
environment.add(p);
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
SimpleModule jsonModule = new SimpleModule();
|
||||
jsonModule.setSerializerModifier(createJsonSerializerModifier());
|
||||
objectMapper.registerModule(jsonModule);
|
||||
try (MockServerClient mockServerClient = new MockServerClient(mockServer.getHost(),
|
||||
mockServer.getMappedPort(MockServerContainer.PORT))) {
|
||||
mockServerClient.when(request().withPath("/application/default"))
|
||||
.respond(response().withBody(objectMapper.writeValueAsString(environment))
|
||||
.withHeader("content-type", "application/json"));
|
||||
InstanceInfo configServerInstanceInfo = InstanceInfo.Builder.newBuilder()
|
||||
.setVIPAddress("eureka-configserver").setInstanceId("eureka-configserver")
|
||||
.setAppName("eureka-configserver").setStatus(InstanceInfo.InstanceStatus.UP)
|
||||
.enablePort(InstanceInfo.PortType.UNSECURE, true).setHostName("localhost")
|
||||
.setPort(mockServer.getMappedPort(MockServerContainer.PORT)).build();
|
||||
Application configServer = new Application("eureka-configserver",
|
||||
Collections.singletonList(configServerInstanceInfo));
|
||||
EurekaApplications eurekaApplications = new EurekaApplications("hashcode", 0L,
|
||||
Collections.singletonList(configServer));
|
||||
mockServerClient.when(request().withPath("/apps/"))
|
||||
.respond(response()
|
||||
.withBody("{\"applications\":" + objectMapper.writeValueAsString(eurekaApplications) + "}")
|
||||
.withHeader("content-type", "application/json"));
|
||||
this.context = setup().run();
|
||||
assertThat(this.context.getEnvironment().getProperty("hello")).isEqualTo("world");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static BeanSerializerModifier createJsonSerializerModifier() {
|
||||
return new BeanSerializerModifier() {
|
||||
@Override
|
||||
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc,
|
||||
JsonSerializer<?> serializer) {
|
||||
if (beanDesc.getBeanClass().isAssignableFrom(InstanceInfo.class)) {
|
||||
return new InstanceInfoJsonBeanSerializer((BeanSerializerBase) serializer, false);
|
||||
}
|
||||
return serializer;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
SpringApplicationBuilder setup(String... env) {
|
||||
SpringApplicationBuilder builder = new SpringApplicationBuilder(TestConfig.class)
|
||||
.properties(addDefaultEnv(env));
|
||||
return builder;
|
||||
}
|
||||
|
||||
private String[] addDefaultEnv(String[] env) {
|
||||
Set<String> set = new LinkedHashSet<>();
|
||||
if (env != null && env.length > 0) {
|
||||
set.addAll(Arrays.asList(env));
|
||||
}
|
||||
set.add("spring.config.import=classpath:bootstrapper.yaml");
|
||||
set.add("spring.cloud.config.enabled=true");
|
||||
set.add("spring.cloud.service-registry.auto-registration.enabled=false");
|
||||
set.add("eureka.client.serviceUrl.defaultZone=http://" + mockServer.getHost() + ":"
|
||||
+ mockServer.getMappedPort(MockServerContainer.PORT));
|
||||
return set.toArray(new String[0]);
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
static class TestConfig {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+47
-7
@@ -16,39 +16,79 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.config;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.context.properties.bind.BindHandler;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.cloud.config.client.ConfigClientProperties;
|
||||
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
|
||||
import org.springframework.web.client.ResourceAccessException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
class EurekaConfigServerBootstrapperTests {
|
||||
|
||||
@Test
|
||||
void notEnabledDoesNotAddInstanceProviderFn() {
|
||||
void notEnabledReturnsEmptyList() {
|
||||
new SpringApplicationBuilder(TestConfig.class)
|
||||
.properties("spring.cloud.service-registry.auto-registration.enabled=false")
|
||||
.addBootstrapRegistryInitializer(registry -> registry.addCloseListener(event -> {
|
||||
ConfigServerInstanceProvider.Function providerFn = event.getBootstrapContext()
|
||||
.get(ConfigServerInstanceProvider.Function.class);
|
||||
assertThat(providerFn).as("ConfigServerInstanceProvider.Function was created when it shouldn't")
|
||||
.isNull();
|
||||
assertThat(providerFn.apply("id")).as("Should return empty list").isEmpty();
|
||||
})).run().close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void discoveryClientNotEnabledProvidesEmptyList() {
|
||||
new SpringApplicationBuilder(TestConfig.class)
|
||||
.properties("spring.cloud.config.discovery.enabled=true", "spring.cloud.discovery.enabled=false",
|
||||
"spring.cloud.service-registry.auto-registration.enabled=false")
|
||||
.addBootstrapRegistryInitializer(registry -> registry.addCloseListener(event -> {
|
||||
ConfigServerInstanceProvider.Function providerFn = event.getBootstrapContext()
|
||||
.get(ConfigServerInstanceProvider.Function.class);
|
||||
Binder binder = event.getBootstrapContext().get(Binder.class);
|
||||
BindHandler bindHandler = event.getBootstrapContext().get(BindHandler.class);
|
||||
assertThat(providerFn.apply("id", binder, bindHandler, mock(Log.class)))
|
||||
.as("Should return empty list").isEmpty();
|
||||
})).run().close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void eurekaClientNotEnabledProvidesEmptyList() {
|
||||
new SpringApplicationBuilder(TestConfig.class)
|
||||
.properties("spring.cloud.config.discovery.enabled=true", "eureka.client.enabled=false",
|
||||
"spring.cloud.service-registry.auto-registration.enabled=false")
|
||||
.addBootstrapRegistryInitializer(registry -> registry.addCloseListener(event -> {
|
||||
ConfigServerInstanceProvider.Function providerFn = event.getBootstrapContext()
|
||||
.get(ConfigServerInstanceProvider.Function.class);
|
||||
Binder binder = event.getBootstrapContext().get(Binder.class);
|
||||
BindHandler bindHandler = event.getBootstrapContext().get(BindHandler.class);
|
||||
assertThat(providerFn.apply("id", binder, bindHandler, mock(Log.class)))
|
||||
.as("Should return empty list").isEmpty();
|
||||
})).run().close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void enabledAddsInstanceProviderFn() {
|
||||
new SpringApplicationBuilder(TestConfig.class)
|
||||
.properties("spring.cloud.config.discovery.enabled=true",
|
||||
"spring.cloud.service-registry.auto-registration.enabled=false")
|
||||
.properties("spring.config.import: classpath:bootstrapper.yaml",
|
||||
ConfigClientProperties.PREFIX + ".enabled=true")
|
||||
.addBootstrapRegistryInitializer(registry -> registry.addCloseListener(event -> {
|
||||
ConfigServerInstanceProvider.Function providerFn = event.getBootstrapContext()
|
||||
.get(ConfigServerInstanceProvider.Function.class);
|
||||
assertThat(providerFn).as("ConfigServerInstanceProvider.Function was not created when it should.")
|
||||
.isNotNull();
|
||||
Binder binder = event.getBootstrapContext().get(Binder.class);
|
||||
BindHandler bindHandler = event.getBootstrapContext().get(BindHandler.class);
|
||||
assertThatThrownBy(() -> providerFn.apply("id", binder, bindHandler, mock(Log.class)))
|
||||
.isInstanceOf(ResourceAccessException.class)
|
||||
.hasMessageContaining("I/O error on GET request for \"http://localhost:8761/eureka/apps/\"")
|
||||
.as("Should have tried to connect to Eureka to fetch instances.");
|
||||
})).run().close();
|
||||
}
|
||||
|
||||
|
||||
+15
-2
@@ -36,6 +36,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* Tests the Eureka health check handler.
|
||||
*
|
||||
* @author Jakub Narloch
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@SpringBootTest(classes = EurekaHealthCheckTests.EurekaHealthCheckApplication.class,
|
||||
webEnvironment = WebEnvironment.RANDOM_PORT, value = { "eureka.client.healthcheck.enabled=true", "debug=true" })
|
||||
@@ -47,12 +48,24 @@ class EurekaHealthCheckTests {
|
||||
|
||||
@Test
|
||||
void shouldRegisterService() {
|
||||
System.setProperty("status", "UP");
|
||||
|
||||
InstanceInfo.InstanceStatus status = this.discoveryClient.getHealthCheckHandler()
|
||||
.getStatus(InstanceInfo.InstanceStatus.UNKNOWN);
|
||||
|
||||
assertThat(status).isNotNull();
|
||||
assertThat(status).isEqualTo(InstanceInfo.InstanceStatus.OUT_OF_SERVICE);
|
||||
assertThat(status).isEqualTo(InstanceInfo.InstanceStatus.UP);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMapOutOfServiceToDown() {
|
||||
System.setProperty("status", "OUT_OF_SERVICE");
|
||||
|
||||
InstanceInfo.InstanceStatus status = this.discoveryClient.getHealthCheckHandler()
|
||||
.getStatus(InstanceInfo.InstanceStatus.UNKNOWN);
|
||||
|
||||
assertThat(status).isNotNull();
|
||||
assertThat(status).isEqualTo(InstanceInfo.InstanceStatus.DOWN);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -61,7 +74,7 @@ class EurekaHealthCheckTests {
|
||||
|
||||
@Bean
|
||||
public HealthIndicator healthIndicator() {
|
||||
return () -> new Health.Builder().outOfService().build();
|
||||
return () -> new Health.Builder().status(System.getProperty("status")).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ import static com.netflix.appinfo.InstanceInfo.DEFAULT_SECURE_PORT;
|
||||
import static org.springframework.util.Assert.isTrue;
|
||||
|
||||
/**
|
||||
* Mocked Eureka Server
|
||||
* Mocked Eureka Server.
|
||||
*
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
spring:
|
||||
config:
|
||||
import: "optional:configserver:"
|
||||
cloud:
|
||||
config:
|
||||
enabled: true
|
||||
discovery:
|
||||
service-id: eureka-configserver
|
||||
enabled: true
|
||||
service-registry:
|
||||
auto-registration:
|
||||
enabled: false
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.1.7</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-eureka-server</artifactId>
|
||||
@@ -177,14 +177,14 @@
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<groupId>org.webjars.npm</groupId>
|
||||
<artifactId>jquery</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.6.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<groupId>org.webjars.npm</groupId>
|
||||
<artifactId>bootstrap</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<version>5.1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
|
||||
+21
-2
@@ -48,6 +48,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Gang Li
|
||||
* @author Weix Sun
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("${eureka.dashboard.path:/}")
|
||||
@@ -58,8 +59,20 @@ public class EurekaController {
|
||||
|
||||
private ApplicationInfoManager applicationInfoManager;
|
||||
|
||||
private final EurekaProperties eurekaProperties;
|
||||
|
||||
/**
|
||||
* @deprecated in favour of
|
||||
* {@link EurekaController#EurekaController(ApplicationInfoManager, EurekaProperties)}
|
||||
*/
|
||||
@Deprecated
|
||||
public EurekaController(ApplicationInfoManager applicationInfoManager) {
|
||||
this(applicationInfoManager, null);
|
||||
}
|
||||
|
||||
public EurekaController(ApplicationInfoManager applicationInfoManager, EurekaProperties eurekaProperties) {
|
||||
this.applicationInfoManager = applicationInfoManager;
|
||||
this.eurekaProperties = eurekaProperties;
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET)
|
||||
@@ -116,8 +129,14 @@ public class EurekaController {
|
||||
private void populateHeader(Map<String, Object> model) {
|
||||
model.put("currentTime", StatusResource.getCurrentTimeAsString());
|
||||
model.put("upTime", StatusInfo.getUpTime());
|
||||
model.put("environment", "N/A"); // FIXME:
|
||||
model.put("datacenter", "N/A"); // FIXME:
|
||||
if (eurekaProperties != null) {
|
||||
model.put("environment", eurekaProperties.getEnvironment());
|
||||
model.put("datacenter", eurekaProperties.getDatacenter());
|
||||
}
|
||||
else {
|
||||
model.put("environment", "N/A");
|
||||
model.put("datacenter", "N/A");
|
||||
}
|
||||
PeerAwareInstanceRegistry registry = getRegistry();
|
||||
model.put("registry", registry);
|
||||
model.put("isBelowRenewThreshold", registry.isBelowRenewThresold() == 1);
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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.server;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Configuration properties for the Eureka deployment.
|
||||
*
|
||||
* @author Weix Sun
|
||||
*/
|
||||
@ConfigurationProperties("eureka")
|
||||
public class EurekaProperties {
|
||||
|
||||
/**
|
||||
* Eureka environment. Defaults to "test".
|
||||
*/
|
||||
private String environment = "test";
|
||||
|
||||
/**
|
||||
* Eureka datacenter. Defaults to "default".
|
||||
*/
|
||||
private String datacenter = "default";
|
||||
|
||||
public String getEnvironment() {
|
||||
return environment;
|
||||
}
|
||||
|
||||
public void setEnvironment(String environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
public String getDatacenter() {
|
||||
return datacenter;
|
||||
}
|
||||
|
||||
public void setDatacenter(String datacenter) {
|
||||
this.datacenter = datacenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
EurekaProperties that = (EurekaProperties) o;
|
||||
return Objects.equals(datacenter, that.datacenter) && Objects.equals(environment, that.environment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(environment, datacenter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("EurekaProperties{");
|
||||
sb.append("environment='").append(environment).append('\'');
|
||||
sb.append(", datacenter=").append(datacenter);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
+5
-3
@@ -73,11 +73,13 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
* @author Gunnar Hillert
|
||||
* @author Biju Kunjummen
|
||||
* @author Fahim Farook
|
||||
* @author Weix Sun
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(EurekaServerInitializerConfiguration.class)
|
||||
@ConditionalOnBean(EurekaServerMarkerConfiguration.Marker.class)
|
||||
@EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class })
|
||||
@EnableConfigurationProperties({ EurekaDashboardProperties.class, InstanceRegistryProperties.class,
|
||||
EurekaProperties.class })
|
||||
@PropertySource("classpath:/eureka/server.properties")
|
||||
public class EurekaServerAutoConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@@ -113,8 +115,8 @@ public class EurekaServerAutoConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true)
|
||||
public EurekaController eurekaController() {
|
||||
return new EurekaController(this.applicationInfoManager);
|
||||
public EurekaController eurekaController(EurekaProperties eurekaProperties) {
|
||||
return new EurekaController(this.applicationInfoManager, eurekaProperties);
|
||||
}
|
||||
|
||||
static {
|
||||
|
||||
+1
-6
@@ -38,6 +38,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Weix Sun
|
||||
*/
|
||||
public class EurekaServerBootstrap {
|
||||
|
||||
@@ -67,7 +68,6 @@ public class EurekaServerBootstrap {
|
||||
|
||||
public void contextInitialized(ServletContext context) {
|
||||
try {
|
||||
initEurekaEnvironment();
|
||||
initEurekaServerContext();
|
||||
|
||||
context.setAttribute(EurekaServerContext.class.getName(), this.serverContext);
|
||||
@@ -93,11 +93,6 @@ public class EurekaServerBootstrap {
|
||||
log.info("Eureka Service is now shutdown...");
|
||||
}
|
||||
|
||||
protected void initEurekaEnvironment() throws Exception {
|
||||
log.info("Setting the eureka configuration..");
|
||||
|
||||
}
|
||||
|
||||
protected void initEurekaServerContext() throws Exception {
|
||||
// For backward compatibility
|
||||
JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), XStream.PRIORITY_VERY_HIGH);
|
||||
|
||||
+5
-14
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.server;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.netflix.appinfo.ApplicationInfoManager;
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.discovery.EurekaClient;
|
||||
@@ -97,18 +95,11 @@ public class InstanceRegistry extends PeerAwareInstanceRegistryImpl implements A
|
||||
@Override
|
||||
public boolean renew(final String appName, final String serverId, boolean isReplication) {
|
||||
log("renew " + appName + " serverId " + serverId + ", isReplication {}" + isReplication);
|
||||
List<Application> applications = getSortedApplications();
|
||||
for (Application input : applications) {
|
||||
if (input.getName().equals(appName)) {
|
||||
InstanceInfo instance = null;
|
||||
for (InstanceInfo info : input.getInstances()) {
|
||||
if (info.getId().equals(serverId)) {
|
||||
instance = info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
publishEvent(new EurekaInstanceRenewedEvent(this, appName, serverId, instance, isReplication));
|
||||
break;
|
||||
Application application = getApplication(appName);
|
||||
if (application != null) {
|
||||
InstanceInfo instanceInfo = application.getByInstanceId(serverId);
|
||||
if (instanceInfo != null) {
|
||||
publishEvent(new EurekaInstanceRenewedEvent(this, appName, serverId, instanceInfo, isReplication));
|
||||
}
|
||||
}
|
||||
return super.renew(appName, serverId, isReplication);
|
||||
|
||||
+11
-16
@@ -1,22 +1,17 @@
|
||||
<#import "/spring.ftl" as spring />
|
||||
<nav class="navbar navbar-default" role="navigation">
|
||||
<nav class="navbar navbar-expand-md navbar-dark" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="<@spring.url dashboardPath/>"><span></span></a>
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li>
|
||||
<a href="<@spring.url dashboardPath/>">Home</a>
|
||||
<a class="navbar-brand my-auto" href="<@spring.url dashboardPath/>"><span></span></a>
|
||||
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#navbarContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarContent">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-2" href="<@spring.url dashboardPath/>">Home</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="<@spring.url dashboardPath/>/lastn">Last 1000 since startup</a>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link px-2" href="<@spring.url dashboardPath/>/lastn">Last 1000 since startup</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
<#import "/spring.ftl" as spring />
|
||||
<!doctype html>
|
||||
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
|
||||
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
|
||||
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<base href="<@spring.url basePath/>">
|
||||
<title>Eureka - Last N events</title>
|
||||
<link rel="stylesheet" type="text/css" href="eureka/css/wro.css">
|
||||
</head>
|
||||
<body id="three">
|
||||
|
||||
<!--[if lt IE 7]>
|
||||
<p>You are using an <strong>outdated</strong> browser. Please upgrade your browser to improve your experience.</p>
|
||||
<![endif]-->
|
||||
<script type="text/javascript">
|
||||
if ( document.documentMode ) {
|
||||
document.write('<p>You are using an <strong>outdated</strong> browser. Please upgrade your browser to improve your experience.</p>');
|
||||
}
|
||||
</script>
|
||||
|
||||
<#include "header.ftlh">
|
||||
|
||||
<div class="container-fluid xd-container">
|
||||
<#include "navbar.ftlh">
|
||||
|
||||
<div id="xd-jobs" class="tab-pane active col-md-12">
|
||||
<div id="xd-jobs" class="tab-pane col-md-12">
|
||||
<ul class="nav nav-tabs" role="tablist" id="myTab">
|
||||
<li class="active"><a data-toggle="tab" href="#cancelled">Last 1000 cancelled leases</a></li>
|
||||
<li><a data-toggle="tab" href="#registered">Last 1000 newly registered leases</a></li>
|
||||
<li class="nav-item"><a href="<@spring.url dashboardPath/>/lastn#cancelled" class="nav-link p-2" data-bs-toggle="tab">Last 1000 cancelled leases</a></li>
|
||||
<li class="nav-item"><a href="<@spring.url dashboardPath/>/lastn#registered" class="nav-link p-2 active" data-bs-toggle="tab">Last 1000 newly registered leases</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane" id="cancelled">
|
||||
@@ -42,7 +40,7 @@
|
||||
<tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab-pane" id="registered">
|
||||
<div class="tab-pane active" id="registered">
|
||||
<table id='lastNRegistered' class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr><th>Timestamp</th><th>Lease</th></tr>
|
||||
@@ -62,10 +60,5 @@
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="eureka/js/wro.js" ></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$('#myTab a:last').tab('show')
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
</#if>
|
||||
|
||||
<h1>DS Replicas</h1>
|
||||
<ul class="list-group">
|
||||
<ul class="list-group mb-3">
|
||||
<#list replicas as replica>
|
||||
<li class="list-group-item"><a href="${replica.value}">${replica.key}</a></li>
|
||||
</#list>
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
<#import "/spring.ftl" as spring />
|
||||
<!doctype html>
|
||||
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
|
||||
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
|
||||
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<base href="<@spring.url basePath/>">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Eureka</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
@@ -17,6 +13,12 @@
|
||||
</head>
|
||||
|
||||
<body id="one">
|
||||
<script type="text/javascript">
|
||||
if ( document.documentMode ) {
|
||||
document.write('<p>You are using an <strong>outdated</strong> browser. Please upgrade your browser to improve your experience.</p>');
|
||||
}
|
||||
</script>
|
||||
|
||||
<#include "header.ftlh">
|
||||
<div class="container-fluid xd-container">
|
||||
<#include "navbar.ftlh">
|
||||
@@ -103,11 +105,5 @@
|
||||
</table>
|
||||
</div>
|
||||
<script type="text/javascript" src="eureka/js/wro.js" ></script>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$('table.stripeable tr:odd').addClass('odd');
|
||||
$('table.stripeable tr:even').addClass('even');
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
.navbar {
|
||||
border-top: 4px solid #6db33f;
|
||||
background-color: #34302d;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-bottom: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
}
|
||||
.navbar a.navbar-brand {
|
||||
background: url("../images/spring-logo-eureka.png") -1px -1px no-repeat;
|
||||
margin: 12px 0 6px;
|
||||
width: 300px;
|
||||
height: 46px;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
padding: 0;
|
||||
}
|
||||
.navbar a.navbar-brand span {
|
||||
display: block;
|
||||
width: 300px;
|
||||
height: 46px;
|
||||
background: url("../images/spring-logo-eureka.png") -1px -48px no-repeat;
|
||||
opacity: 0;
|
||||
transition: opacity 0.12s ease-in-out;
|
||||
-moz-transition: opacity 0.12s ease-in-out;
|
||||
-webkit-transition: opacity 0.12s ease-in-out;
|
||||
}
|
||||
.navbar a:hover.navbar-brand span {
|
||||
opacity: 1;
|
||||
}
|
||||
.nav-link, .navbar-text {
|
||||
color: #34302d;
|
||||
font-family: "montserratregular", sans-serif;
|
||||
text-shadow: none;
|
||||
font-size: 14px;
|
||||
padding: 28px 20px;
|
||||
transition: all 0.15s;
|
||||
-moz-transition: all 0.15s;
|
||||
-webkit-transition: all 0.15s;
|
||||
}
|
||||
.navbar .nav-link:link {
|
||||
color: #f1f1f1;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.navbar .nav-item .nav-link:hover {
|
||||
color: #f1f1f1;
|
||||
background-color: #6db33f;
|
||||
}
|
||||
.navbar-toggler {
|
||||
color: #f1f1f1;
|
||||
border-width: 0;
|
||||
}
|
||||
table {
|
||||
border-color: #34302D;
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
.navbar {
|
||||
border-top: 4px solid #6db33f;
|
||||
background-color: #34302d;
|
||||
margin-bottom: 0px;
|
||||
border-bottom: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.navbar a.navbar-brand {
|
||||
background: url("../images/spring-logo-eureka.png") -1px -1px no-repeat;
|
||||
margin: 12px 0 6px;
|
||||
width: 300px;
|
||||
height: 46px;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.navbar a.navbar-brand span {
|
||||
display: block;
|
||||
width: 300px;
|
||||
height: 46px;
|
||||
background: url("../images/spring-logo-eureka.png") -1px -48px no-repeat;
|
||||
opacity: 0;
|
||||
-moz-transition: opacity 0.12s ease-in-out;
|
||||
-webkit-transition: opacity 0.12s ease-in-out;
|
||||
-o-transition: opacity 0.12s ease-in-out;
|
||||
}
|
||||
|
||||
.navbar a:hover.navbar-brand span {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.navbar li > a, .navbar-text {
|
||||
font-family: "montserratregular", sans-serif;
|
||||
text-shadow: none;
|
||||
font-size: 14px;
|
||||
|
||||
/* line-height: 14px; */
|
||||
padding: 28px 20px;
|
||||
transition: all 0.15s;
|
||||
-webkit-transition: all 0.15s;
|
||||
-moz-transition: all 0.15s;
|
||||
-o-transition: all 0.15s;
|
||||
-ms-transition: all 0.15s;
|
||||
}
|
||||
|
||||
.navbar li > a {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.navbar .navbar-text {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.navbar li:hover > a {
|
||||
color: #eeeeee;
|
||||
background-color: #6db33f;
|
||||
}
|
||||
|
||||
.navbar-toggle {
|
||||
border-width: 0;
|
||||
|
||||
.icon-bar + .icon-bar {
|
||||
margin-top: 3px;
|
||||
}
|
||||
.icon-bar {
|
||||
width: 19px;
|
||||
height: 3px;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
@import "typography.css";
|
||||
@import "header.css";
|
||||
@import "responsive.css";
|
||||
|
||||
a:link {
|
||||
color: #5fa134;
|
||||
}
|
||||
a:hover {
|
||||
color: #5fa134;
|
||||
}
|
||||
body {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
.table > thead > tr > th {
|
||||
background-color: #34302D;
|
||||
color: #f1f1f1;
|
||||
}
|
||||
.table-filter {
|
||||
background-color: #34302D;
|
||||
padding: 9px 12px;
|
||||
}
|
||||
.nav-tabs .nav-link {
|
||||
color: #838789;
|
||||
}
|
||||
.nav-tabs .nav-link.active, .nav-tabs .nav-link.active:hover {
|
||||
color: #f1f1f1;
|
||||
background-color: #34302D;
|
||||
border-color: #34302D;
|
||||
}
|
||||
.btn-default {
|
||||
border-width: 2px;
|
||||
transition: border 0.15s;
|
||||
-webkit-transition: border 0.15s;
|
||||
-moz-transition: border 0.15s;
|
||||
-o-transition: border 0.15s;
|
||||
-ms-transition: border 0.15s;
|
||||
color: #f1f1f1;
|
||||
background-color: #34302D;
|
||||
border-color: #6db33f;
|
||||
}
|
||||
.btn-default:hover, .btn-default:focus, .btn-default:active, .btn-default.active, .open .dropdown-toggle.btn-default {
|
||||
background-color: #34302D;
|
||||
border-color: #34302D;
|
||||
}
|
||||
.container .text-muted {
|
||||
margin: 20px 0;
|
||||
}
|
||||
code {
|
||||
font-size: 80%;
|
||||
}
|
||||
.xd-container {
|
||||
margin-top: 40px;
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
h1 {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.index-page--subtitle {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
margin: 0 0 30px;
|
||||
}
|
||||
.form-horizontal button.btn-inverse {
|
||||
margin-left: 32px;
|
||||
}
|
||||
#job-params-modal .modal-dialog {
|
||||
width: 90%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
[ng-cloak].splash {
|
||||
display: block !important;
|
||||
}
|
||||
[ng-cloak] {
|
||||
display: none;
|
||||
}
|
||||
.splash {
|
||||
background: #6db33f;
|
||||
color: #34302D;
|
||||
display: none;
|
||||
}
|
||||
.error-page {
|
||||
margin-top: 100px;
|
||||
text-align: center;
|
||||
}
|
||||
.error-page .error-title {
|
||||
font-size: 24px;
|
||||
line-height: 24px;
|
||||
margin: 30px 0 0;
|
||||
}
|
||||
table td {
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
table td .progress {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
table td.action-column {
|
||||
width: 1px;
|
||||
}
|
||||
.help-block {
|
||||
color: #f1f1f1;
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
@spring-green: #6db33f;
|
||||
@spring-dark-green: #5fa134;
|
||||
@spring-brown: #34302D;
|
||||
@spring-grey: #838789;
|
||||
@spring-light-grey: #f1f1f1;
|
||||
|
||||
@body-bg: @spring-light-grey;
|
||||
@text-color: @spring-light-grey;
|
||||
@link-color: @spring-dark-green;
|
||||
@link-hover-color: @spring-dark-green;
|
||||
|
||||
@navbar-default-link-color: @spring-light-grey;
|
||||
@navbar-default-link-active-color: @spring-light-grey;
|
||||
@navbar-default-link-hover-color: @spring-light-grey;
|
||||
@navbar-default-link-hover-bg: @spring-green;
|
||||
@navbar-default-toggle-icon-bar-bg: @spring-light-grey;
|
||||
@navbar-default-toggle-hover-bg: transparent;
|
||||
@navbar-default-link-active-bg: @spring-green;
|
||||
|
||||
@border-radius-base: 0;
|
||||
@border-radius-large: 0;
|
||||
@border-radius-small: 0;
|
||||
|
||||
@btn-default-color: @spring-light-grey;
|
||||
@btn-default-bg: @spring-brown;
|
||||
@btn-default-border: @spring-green;
|
||||
|
||||
@nav-tabs-active-link-hover-color: @spring-light-grey;
|
||||
@nav-tabs-active-link-hover-bg: @spring-brown;
|
||||
@nav-tabs-active-link-hover-border-color: @spring-brown;
|
||||
@nav-tabs-border-color: @spring-brown;
|
||||
@table-border-color: @spring-brown;
|
||||
|
||||
@import "typography.less";
|
||||
@import "header.less";
|
||||
|
||||
.table > thead > tr > th {
|
||||
background-color: lighten(@spring-brown, 3%);
|
||||
color: @spring-light-grey;
|
||||
}
|
||||
|
||||
.table-filter {
|
||||
background-color: @spring-brown;
|
||||
padding: 9px 12px;
|
||||
}
|
||||
|
||||
.nav > li > a {
|
||||
color: @spring-grey;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
border-width: 2px;
|
||||
transition: border 0.15s;
|
||||
-webkit-transition: border 0.15s;
|
||||
-moz-transition: border 0.15s;
|
||||
-o-transition: border 0.15s;
|
||||
-ms-transition: border 0.15s;
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active,
|
||||
&.active,
|
||||
.open .dropdown-toggle& {
|
||||
background-color: @spring-brown;
|
||||
border-color: @spring-brown;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.container .text-muted {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
.xd-container {
|
||||
margin-top: 40px;
|
||||
margin-bottom: 100px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 15px
|
||||
}
|
||||
|
||||
.index-page--subtitle {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
margin: 0 0 30px;
|
||||
}
|
||||
|
||||
.form-horizontal button.btn-inverse {
|
||||
margin-left: 32px;
|
||||
}
|
||||
|
||||
#job-params-modal .modal-dialog {
|
||||
width: 90%;
|
||||
margin-left:auto;
|
||||
margin-right:auto;
|
||||
}
|
||||
|
||||
[ng-cloak].splash {
|
||||
display: block !important;
|
||||
}
|
||||
[ng-cloak] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.splash {
|
||||
background: @spring-green;
|
||||
color: @spring-brown;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.error-page {
|
||||
margin-top: 100px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.error-page .error-title {
|
||||
font-size: 24px;
|
||||
line-height: 24px;
|
||||
margin: 30px 0 0;
|
||||
}
|
||||
|
||||
table td {
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
|
||||
table td .progress {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
table td.action-column {
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
.help-block {
|
||||
color: lighten(@text-color, 0%); // lighten the text some for contrast
|
||||
}
|
||||
|
||||
@import "responsive.less";
|
||||
@@ -0,0 +1,23 @@
|
||||
@media (max-width: 768px) {
|
||||
.navbar a.navbar-brand {
|
||||
background: url("../images/spring-logo-eureka-mobile.png") 0 center no-repeat;
|
||||
}
|
||||
.homepage-billboard .homepage-subtitle {
|
||||
font-size: 21px;
|
||||
line-height: 21px;
|
||||
}
|
||||
.navbar a.navbar-brand span {
|
||||
display: none;
|
||||
}
|
||||
.navbar {
|
||||
border-top-width: 0;
|
||||
}
|
||||
.xd-container {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.index-page--subtitle {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
@media (max-width: 768px) {
|
||||
.navbar-toggle {
|
||||
position:absolute;
|
||||
z-index: 9999;
|
||||
left:0px;
|
||||
top:0px;
|
||||
}
|
||||
|
||||
.navbar a.navbar-brand {
|
||||
display: block;
|
||||
margin: 0 auto 0 auto;
|
||||
width: 200px;
|
||||
height: 50px;
|
||||
float: none;
|
||||
background: url("../images/spring-logo-eureka-mobile.png") 0 center no-repeat;
|
||||
}
|
||||
|
||||
.homepage-billboard .homepage-subtitle {
|
||||
font-size: 21px;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.navbar a.navbar-brand span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
border-top-width: 0;
|
||||
}
|
||||
|
||||
.xd-container {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.index-page--subtitle {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
@font-face {
|
||||
font-family: 'varela_roundregular';
|
||||
src: url('../fonts/varela_round-webfont.eot');
|
||||
src: url('../fonts/varela_round-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/varela_round-webfont.woff') format('woff'), url('../fonts/varela_round-webfont.ttf') format('truetype'), url('../fonts/varela_round-webfont.svg#varela_roundregular') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'montserratregular';
|
||||
src: url('../fonts/montserrat-webfont.eot');
|
||||
src: url('../fonts/montserrat-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/montserrat-webfont.woff') format('woff'), url('../fonts/montserrat-webfont.ttf') format('truetype'), url('../fonts/montserrat-webfont.svg#montserratregular') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
body, h1, h2, h3, p, input {
|
||||
margin: 0;
|
||||
font-weight: 400;
|
||||
font-family: "varela_roundregular", sans-serif;
|
||||
color: #34302d;
|
||||
}
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
font-family: "montserratregular", sans-serif;
|
||||
}
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
line-height: 24px;
|
||||
margin-bottom: 10px;
|
||||
font-family: "montserratregular", sans-serif;
|
||||
}
|
||||
h3 {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
margin-bottom: 10px;
|
||||
font-weight: 700;
|
||||
}
|
||||
strong {
|
||||
font-weight: 700;
|
||||
font-family: "montserratregular", sans-serif;
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
@font-face {
|
||||
font-family: 'varela_roundregular';
|
||||
src: url('../fonts/varela_round-webfont.eot');
|
||||
src: url('../fonts/varela_round-webfont.eot?#iefix') format('embedded-opentype'),
|
||||
url('../fonts/varela_round-webfont.woff') format('woff'),
|
||||
url('../fonts/varela_round-webfont.ttf') format('truetype'),
|
||||
url('../fonts/varela_round-webfont.svg#varela_roundregular') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'montserratregular';
|
||||
src: url('../fonts/montserrat-webfont.eot');
|
||||
src: url('../fonts/montserrat-webfont.eot?#iefix') format('embedded-opentype'),
|
||||
url('../fonts/montserrat-webfont.woff') format('woff'),
|
||||
url('../fonts/montserrat-webfont.ttf') format('truetype'),
|
||||
url('../fonts/montserrat-webfont.svg#montserratregular') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
body, h1, h2, h3, p, input {
|
||||
margin: 0;
|
||||
font-weight: 400;
|
||||
font-family: "varela_roundregular", sans-serif;
|
||||
color: #34302d;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
line-height: 30px;
|
||||
font-family: "montserratregular", sans-serif;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
line-height: 24px;
|
||||
margin-bottom: 10px;
|
||||
font-family: "montserratregular", sans-serif;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
margin-bottom: 10px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
p {
|
||||
//font-size: 15px;
|
||||
//line-height: 24px;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 700;
|
||||
font-family: "montserratregular", sans-serif;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#List of preProcessors
|
||||
preProcessors=cssImport
|
||||
|
||||
#List of postProcessors
|
||||
postProcessors=less4j,jsMin
|
||||
postProcessors=jsMin
|
||||
@@ -1,8 +1,8 @@
|
||||
<groups xmlns="http://www.isdc.ro/wro">
|
||||
<group name="wro">
|
||||
<css>webjar:bootstrap/3.2.0/less/bootstrap.less</css>
|
||||
<css>file:@.project.basedir.@/src/main/wro/main.less</css>
|
||||
<js>webjar:jquery/3.5.1/jquery.min.js</js>
|
||||
<js>webjar:bootstrap/3.2.0/js/bootstrap.min.js</js>
|
||||
<css>webjar:bootstrap/5.1.3/dist/css/bootstrap.min.css</css>
|
||||
<css>file:@.project.basedir.@/src/main/wro/main.css</css>
|
||||
<js>webjar:jquery/3.6.0/jquery.min.js</js>
|
||||
<js>webjar:bootstrap/5.1.3/dist/js/bootstrap.min.js</js>
|
||||
</group>
|
||||
</groups>
|
||||
+2
-2
@@ -57,9 +57,9 @@ class ApplicationDashboardPathTests {
|
||||
// The "DS Replicas"
|
||||
assertThat(body.contains("<h1>Instances currently registered with Eureka</h1>")).isTrue();
|
||||
// The Home
|
||||
assertThat(body.contains("<a href=\"/dashboard\">Home</a>")).isTrue();
|
||||
assertThat(body.contains("<a class=\"nav-link px-2\" href=\"/dashboard\">Home</a>")).isTrue();
|
||||
// The Lastn
|
||||
assertThat(body.contains("<a href=\"/dashboard/lastn\">Last")).isTrue();
|
||||
assertThat(body.contains("<a class=\"nav-link px-2\" href=\"/dashboard/lastn\">Last")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+4
-1
@@ -96,10 +96,13 @@ class EurekaControllerTests {
|
||||
void testStatus() throws Exception {
|
||||
Map<String, Object> model = new HashMap<>();
|
||||
|
||||
EurekaController controller = new EurekaController(infoManager);
|
||||
EurekaController controller = new EurekaController(infoManager, new EurekaProperties());
|
||||
|
||||
controller.status(new MockHttpServletRequest("GET", "/"), model);
|
||||
|
||||
assertThat((String) model.get("environment")).isEqualTo("test");
|
||||
assertThat((String) model.get("datacenter")).isEqualTo("default");
|
||||
|
||||
Map<String, Object> app = getFirst(model, "apps");
|
||||
Map<String, Object> instanceInfo = getFirst(app, "instanceInfos");
|
||||
Map<String, Object> instance = getFirst(instanceInfo, "instances");
|
||||
|
||||
+2
-5
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -125,10 +124,8 @@ class InstanceRegistryTests {
|
||||
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));
|
||||
final List<Application> applications = new ArrayList<>();
|
||||
applications.add(application);
|
||||
// stubbing applications list
|
||||
doReturn(applications).when(instanceRegistry).getSortedApplications();
|
||||
// stubbing application
|
||||
doReturn(application).when(instanceRegistry).getApplication(APP_NAME);
|
||||
// calling tested method
|
||||
instanceRegistry.renew(APP_NAME, INSTANCE_ID, false);
|
||||
instanceRegistry.renew(APP_NAME, "my-host-name:8009", false);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.1.7</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>3.1.1</version>
|
||||
<version>3.1.7</version>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
|
||||
<name>Spring Cloud Starter Netflix Eureka Server</name>
|
||||
|
||||
@@ -12,4 +12,5 @@
|
||||
<suppress files=".*TestAutoConfiguration\.java" checks="HideUtilityClassConstructor"/>
|
||||
<suppress files=".*TestAutoConfiguration\.java" checks="JavadocStyle"/>
|
||||
<suppress files=".*TestAutoConfiguration\.java" checks="JavadocStyle"/>
|
||||
<suppress files=".*Tests\.java" checks="JavadocVariable"/>
|
||||
</suppressions>
|
||||
Reference in New Issue
Block a user