From 51a76ad4f5bca6ce68dbc05f72f0cc34a29a03e8 Mon Sep 17 00:00:00 2001 From: minux Date: Mon, 19 Feb 2024 11:35:52 +0900 Subject: [PATCH] Autofill `homePageUrl` and `statusPageUrl` of an `InstanceInfo` in Eureka using path properties. (#5465) Motivation: Following up on the improvements introduced in https://github.com/line/armeria/pull/5369, it's beneficial to extend the autofill feature to include `homePageUrl` and `statusPageUrl` of an `InstanceInfo`. This enhancement streamlines configuration by automatically populating these URLs based on corresponding path properties. Modifications: - Introduce `homePageUrlPath` and `statusPageUrlPath` properties to `InstanceInfo` and their respective builders. - Implement autofill functionality for `homePageUrl` and `statusPageUrl` using the configured path properties. Result: - `homePageUrl` and `statusPageUrl` of an `InstanceInfo` in Eureka are correctly set if corresponding path properties are configured. - Close #5464 --- .../internal/common/eureka/InstanceInfo.java | 44 +++++++++++++++++-- .../server/eureka/EurekaUpdatingListener.java | 40 ++++++++++++++--- .../eureka/EurekaUpdatingListenerBuilder.java | 16 +++++++ .../server/eureka/InstanceInfoBuilder.java | 24 +++++++++- .../eureka/EurekaUpdatingListenerTest.java | 19 +++++--- 5 files changed, 124 insertions(+), 19 deletions(-) diff --git a/eureka/src/main/java/com/linecorp/armeria/internal/common/eureka/InstanceInfo.java b/eureka/src/main/java/com/linecorp/armeria/internal/common/eureka/InstanceInfo.java index 7f722434a350..a8edb005be84 100644 --- a/eureka/src/main/java/com/linecorp/armeria/internal/common/eureka/InstanceInfo.java +++ b/eureka/src/main/java/com/linecorp/armeria/internal/common/eureka/InstanceInfo.java @@ -23,6 +23,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonRootName; @@ -36,7 +37,7 @@ /** * An instance information. */ -@JsonIgnoreProperties(value = { "healthCheckUrlPath" }, ignoreUnknown = true) +@JsonIgnoreProperties(ignoreUnknown = true) @JsonRootName("instance") public final class InstanceInfo { @@ -61,9 +62,13 @@ public final class InstanceInfo { private final PortWrapper securePort; private final InstanceStatus status; + @Nullable + private final String homePageUrlPath; @Nullable private final String homePageUrl; @Nullable + private final String statusPageUrlPath; + @Nullable private final String statusPageUrl; @Nullable private final String healthCheckUrlPath; @@ -99,7 +104,7 @@ public InstanceInfo(@Nullable @JsonProperty("instanceId") String instanceId, @JsonProperty("leaseInfo") LeaseInfo leaseInfo, @Nullable @JsonProperty("metadata") Map metadata) { this(instanceId, appName, appGroupName, hostName, ipAddr, vipAddress, secureVipAddress, port, - securePort, status, homePageUrl, statusPageUrl, null, healthCheckUrl, + securePort, status, null, homePageUrl, null, statusPageUrl, null, healthCheckUrl, secureHealthCheckUrl, dataCenterInfo, leaseInfo, metadata); } @@ -116,7 +121,9 @@ public InstanceInfo(@Nullable String instanceId, PortWrapper port, PortWrapper securePort, InstanceStatus status, + @Nullable String homePageUrlPath, // Not in JSON @Nullable String homePageUrl, + @Nullable String statusPageUrlPath, // Not in JSON @Nullable String statusPageUrl, @Nullable String healthCheckUrlPath, // Not in JSON @Nullable String healthCheckUrl, @@ -134,7 +141,9 @@ public InstanceInfo(@Nullable String instanceId, this.port = requireNonNull(port, "port"); this.securePort = requireNonNull(securePort, "securePort"); this.status = requireNonNull(status, "status"); + this.homePageUrlPath = homePageUrlPath; this.homePageUrl = homePageUrl; + this.statusPageUrlPath = statusPageUrlPath; this.statusPageUrl = statusPageUrl; this.healthCheckUrlPath = healthCheckUrlPath; this.healthCheckUrl = healthCheckUrl; @@ -229,6 +238,17 @@ public InstanceStatus getStatus() { return status; } + /** + * Returns the home page URL path of this instance. + * + *

When set, {@link #getHomePageUrl()} will be built with {@link #getHostName()} and {@link #getPort()}. + */ + @Nullable + @JsonIgnore + public String getHomePageUrlPath() { + return homePageUrlPath; + } + /** * Returns the home page URL of this instance. */ @@ -237,6 +257,18 @@ public String getHomePageUrl() { return homePageUrl; } + /** + * Returns the status page URL path of this instance. + * + *

When set, {@link #getStatusPageUrl()} will be built with {@link #getHostName()} and + * {@link #getPort()}. + */ + @Nullable + @JsonIgnore + public String getStatusPageUrlPath() { + return statusPageUrlPath; + } + /** * Returns the status page URL of this instance. */ @@ -252,6 +284,7 @@ public String getStatusPageUrl() { * {@link #getPort()} or {@link #getSecurePort()} for {@link #getSecureHealthCheckUrl()}. */ @Nullable + @JsonIgnore public String getHealthCheckUrlPath() { return healthCheckUrlPath; } @@ -327,7 +360,9 @@ public boolean equals(Object o) { Objects.equal(port, that.port) && Objects.equal(securePort, that.securePort) && status == that.status && + Objects.equal(homePageUrlPath, that.homePageUrlPath) && Objects.equal(homePageUrl, that.homePageUrl) && + Objects.equal(statusPageUrlPath, that.statusPageUrlPath) && Objects.equal(statusPageUrl, that.statusPageUrl) && Objects.equal(healthCheckUrlPath, that.healthCheckUrlPath) && Objects.equal(healthCheckUrl, that.healthCheckUrl) && @@ -341,7 +376,8 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hashCode(instanceId, hostName, appName, appGroupName, ipAddr, vipAddress, secureVipAddress, port, securePort, status, - homePageUrl, statusPageUrl, healthCheckUrlPath, healthCheckUrl, + homePageUrlPath, homePageUrl, statusPageUrlPath, statusPageUrl, + healthCheckUrlPath, healthCheckUrl, secureHealthCheckUrl, dataCenterInfo, leaseInfo, metadata); } @@ -358,7 +394,9 @@ public String toString() { .add("port", port) .add("securePort", securePort) .add("status", status) + .add("homePageUrlPath", homePageUrlPath) .add("homePageUrl", homePageUrl) + .add("statusPageUrlPath", statusPageUrlPath) .add("statusPageUrl", statusPageUrl) .add("healthCheckUrlPath", healthCheckUrlPath) .add("healthCheckUrl", healthCheckUrl) diff --git a/eureka/src/main/java/com/linecorp/armeria/server/eureka/EurekaUpdatingListener.java b/eureka/src/main/java/com/linecorp/armeria/server/eureka/EurekaUpdatingListener.java index 2ae42674249a..712c044b3ba9 100644 --- a/eureka/src/main/java/com/linecorp/armeria/server/eureka/EurekaUpdatingListener.java +++ b/eureka/src/main/java/com/linecorp/armeria/server/eureka/EurekaUpdatingListener.java @@ -15,6 +15,7 @@ */ package com.linecorp.armeria.server.eureka; +import static com.google.common.base.Strings.isNullOrEmpty; import static com.linecorp.armeria.server.eureka.InstanceInfoBuilder.disabledPort; import static java.util.Objects.requireNonNull; @@ -225,6 +226,11 @@ private static InstanceInfo fillAndCreateNewInfo(InstanceInfo oldInfo, Server se } else { hostnameOrIpAddr = hostName; } + + final String homePageUrl = pageUrl(hostnameOrIpAddr, oldInfo.getHomePageUrlPath(), + oldInfo.getHomePageUrl(), portWrapper); + final String statusPageUrl = pageUrl(hostnameOrIpAddr, oldInfo.getStatusPageUrlPath(), + oldInfo.getStatusPageUrl(), portWrapper); final String healthCheckUrl = healthCheckUrl(hostnameOrIpAddr, oldInfo.getHealthCheckUrlPath(), oldInfo.getHealthCheckUrl(), portWrapper, healthCheckService, SessionProtocol.HTTP); @@ -235,7 +241,7 @@ private static InstanceInfo fillAndCreateNewInfo(InstanceInfo oldInfo, Server se return new InstanceInfo(instanceId, appName, oldInfo.getAppGroupName(), hostName, ipAddr, vipAddress, secureVipAddress, portWrapper, securePortWrapper, InstanceStatus.UP, - oldInfo.getHomePageUrl(), oldInfo.getStatusPageUrl(), healthCheckUrl, + homePageUrl, statusPageUrl, healthCheckUrl, secureHealthCheckUrl, oldInfo.getDataCenterInfo(), oldInfo.getLeaseInfo(), oldInfo.getMetadata()); } @@ -269,23 +275,43 @@ private static String vipAddress(@Nullable String vipAddress, String hostName, P return vipAddress != null ? vipAddress : hostName; } + @Nullable + private static String pageUrl(String hostnameOrIpAddr, @Nullable String pageUrlPath, + @Nullable String pageUrl, PortWrapper portWrapper) { + if (!isNullOrEmpty(pageUrl)) { + return pageUrl; + } + if (pageUrlPath == null || !portWrapper.isEnabled()) { // allow an empty String. + return null; + } + return concatPath(baseUrl(hostnameOrIpAddr, portWrapper, SessionProtocol.HTTP), pageUrlPath); + } + + private static String baseUrl(String hostnameOrIpAddr, PortWrapper portWrapper, + SessionProtocol sessionProtocol) { + return sessionProtocol.uriText() + "://" + + hostnameOrIpAddr(hostnameOrIpAddr) + ':' + portWrapper.getPort(); + } + + private static String concatPath(String baseURL, String path) { + return !path.isEmpty() && path.charAt(0) == '/' ? baseURL + path : baseURL + '/' + path; + } + @Nullable private static String healthCheckUrl(String hostnameOrIpAddr, @Nullable String oldHealthCheckUrlPath, @Nullable String oldHealthCheckUrl, PortWrapper portWrapper, Optional healthCheckService, SessionProtocol sessionProtocol) { - if (oldHealthCheckUrl != null) { + if (!isNullOrEmpty(oldHealthCheckUrl)) { return oldHealthCheckUrl; } if (!portWrapper.isEnabled() || !healthCheckService.isPresent()) { return null; } - final String baseURL = sessionProtocol.uriText() + "://" + - hostnameOrIpAddr(hostnameOrIpAddr) + ':' + portWrapper.getPort(); - if (oldHealthCheckUrlPath != null) { - return !oldHealthCheckUrlPath.isEmpty() && oldHealthCheckUrlPath.charAt(0) == '/' ? - baseURL + oldHealthCheckUrlPath : baseURL + '/' + oldHealthCheckUrlPath; + final String baseURL = baseUrl(hostnameOrIpAddr, portWrapper, sessionProtocol); + if (oldHealthCheckUrlPath != null) { // allow an empty String + return concatPath(baseURL, oldHealthCheckUrlPath); } final ServiceConfig healthCheckServiceConfig = healthCheckService.get(); final Route route = healthCheckServiceConfig.route(); diff --git a/eureka/src/main/java/com/linecorp/armeria/server/eureka/EurekaUpdatingListenerBuilder.java b/eureka/src/main/java/com/linecorp/armeria/server/eureka/EurekaUpdatingListenerBuilder.java index addfb57ff556..5d684bdaed52 100644 --- a/eureka/src/main/java/com/linecorp/armeria/server/eureka/EurekaUpdatingListenerBuilder.java +++ b/eureka/src/main/java/com/linecorp/armeria/server/eureka/EurekaUpdatingListenerBuilder.java @@ -286,6 +286,14 @@ public EurekaUpdatingListenerBuilder secureVipAddress(String secureVipAddress) { return this; } + /** + * Sets the home page URL path used to automatically create {@link #homePageUrl(String)}. + */ + public EurekaUpdatingListenerBuilder homePageUrlPath(String homePageUrlPath) { + instanceInfoBuilder.homePageUrlPath(homePageUrlPath); + return this; + } + /** * Sets the home page URL. */ @@ -294,6 +302,14 @@ public EurekaUpdatingListenerBuilder homePageUrl(String homePageUrl) { return this; } + /** + * Sets the status page URL path used to automatically create {@link #statusPageUrl(String)}. + */ + public EurekaUpdatingListenerBuilder statusPageUrlPath(String statusPageUrlPath) { + instanceInfoBuilder.statusPageUrlPath(statusPageUrlPath); + return this; + } + /** * Sets the status page URL. */ diff --git a/eureka/src/main/java/com/linecorp/armeria/server/eureka/InstanceInfoBuilder.java b/eureka/src/main/java/com/linecorp/armeria/server/eureka/InstanceInfoBuilder.java index 1398c9170f35..d01d603bac04 100644 --- a/eureka/src/main/java/com/linecorp/armeria/server/eureka/InstanceInfoBuilder.java +++ b/eureka/src/main/java/com/linecorp/armeria/server/eureka/InstanceInfoBuilder.java @@ -70,8 +70,12 @@ final class InstanceInfoBuilder { @Nullable private String secureVipAddress; @Nullable + private String homePageUrlPath; + @Nullable private String homePageUrl; @Nullable + private String statusPageUrlPath; + @Nullable private String statusPageUrl; @Nullable private String healthCheckUrlPath; @@ -180,6 +184,14 @@ InstanceInfoBuilder secureVipAddress(String secureVipAddress) { return this; } + /** + * Sets the home page URL path. + */ + InstanceInfoBuilder homePageUrlPath(String homePageUrlPath) { + this.homePageUrlPath = requireNonNull(homePageUrlPath, "homePageUrlPath"); + return this; + } + /** * Sets the home page URL. */ @@ -188,6 +200,14 @@ InstanceInfoBuilder homePageUrl(String homePageUrl) { return this; } + /** + * Sets the status page URL path. + */ + InstanceInfoBuilder statusPageUrlPath(String statusPageUrlPath) { + this.statusPageUrlPath = requireNonNull(statusPageUrlPath, "statusPageUrlPath"); + return this; + } + /** * Sets the status page URL. */ @@ -251,8 +271,8 @@ InstanceInfo build() { final LeaseInfo leaseInfo = new LeaseInfo(renewalIntervalSeconds, leaseDurationSeconds); return new InstanceInfo(instanceId, appName, appGroupName, hostname, ipAddr, vipAddress, secureVipAddress, port, securePort, InstanceStatus.UP, - homePageUrl, statusPageUrl, healthCheckUrlPath, healthCheckUrl, - secureHealthCheckUrl, + homePageUrlPath, homePageUrl, statusPageUrlPath, statusPageUrl, + healthCheckUrlPath, healthCheckUrl, secureHealthCheckUrl, new DataCenterInfo(dataCenterName, dataCenterMetadata), leaseInfo, metadata); } diff --git a/eureka/src/test/java/com/linecorp/armeria/server/eureka/EurekaUpdatingListenerTest.java b/eureka/src/test/java/com/linecorp/armeria/server/eureka/EurekaUpdatingListenerTest.java index c84df057edc2..1f05dbd24f84 100644 --- a/eureka/src/test/java/com/linecorp/armeria/server/eureka/EurekaUpdatingListenerTest.java +++ b/eureka/src/test/java/com/linecorp/armeria/server/eureka/EurekaUpdatingListenerTest.java @@ -256,18 +256,22 @@ void defaultInstanceId() throws IOException { } @ParameterizedTest - @CsvSource(value = { - "'',/", - "custom-health,/custom-health", - "/custom-health,/custom-health", + @CsvSource({ + "'',/,'',/,'',/", + "custom-health,/custom-health,home-page,/home-page,status-page,/status-page", + "/custom-health,/custom-health,/home-page,/home-page,/status-page,/status-page", }) - void customHealthCheckPath(String healthCheckUrlPath, String expectedHealthCheckUrlPath) + void customPaths(String healthCheckUrlPath, String expectedHealthCheckUrlPath, + String homePageUrlPath, String expectedHomePageUrlPath, + String statusPageUrlPath, String expectedStatusPageUrlPath) throws IOException { final EurekaUpdatingListener listener = EurekaUpdatingListener.builder(eurekaServer.httpUri()) .renewalInterval(Duration.ofSeconds(2)) .leaseDuration(Duration.ofSeconds(10)) .hostname("myhost") + .homePageUrlPath(homePageUrlPath) + .statusPageUrlPath(statusPageUrlPath) .healthCheckUrlPath(healthCheckUrlPath) .port(88) .securePort(8888) @@ -285,8 +289,9 @@ void customHealthCheckPath(String healthCheckUrlPath, String expectedHealthCheck await().until(() -> registerContentCaptor.get() != null); final InstanceInfo instanceInfo = mapper.readValue(registerContentCaptor.get().array(), InstanceInfo.class); - assertThat(instanceInfo.getHealthCheckUrl()) - .isEqualTo("http://myhost:88" + expectedHealthCheckUrlPath); + assertThat(instanceInfo.getHomePageUrl()).isEqualTo("http://myhost:88" + expectedHomePageUrlPath); + assertThat(instanceInfo.getStatusPageUrl()).isEqualTo("http://myhost:88" + expectedStatusPageUrlPath); + assertThat(instanceInfo.getHealthCheckUrl()).isEqualTo("http://myhost:88" + expectedHealthCheckUrlPath); assertThat(instanceInfo.getSecureHealthCheckUrl()) .isEqualTo("https://myhost:8888" + expectedHealthCheckUrlPath); application.stop().join();