From e1aff8f22e0d73bd4f65ef5d9c8505b18819cc0d Mon Sep 17 00:00:00 2001 From: Clement Escoffier Date: Sun, 26 Mar 2023 19:10:06 +0200 Subject: [PATCH] Add `path` to service instance. This allows describing services that are exposed behind an API gateway. --- api/revapi.json | 127 +----------------- .../smallrye/stork/api/ServiceInstance.java | 13 +- .../stork/api/ServiceInstanceTest.java | 6 + core/revapi.json | 8 +- .../stork/impl/DefaultServiceInstance.java | 35 ++++- .../ServiceInstanceWithStatGathering.java | 7 + .../io/smallrye/stork/utils/HostAndPort.java | 22 ++- .../stork/utils/StorkAddressUtils.java | 26 +++- .../CachingServiceDiscoveryRefreshTest.java | 6 +- .../stork/utils/StorkAddressUtilsTest.java | 38 +++++- load-balancer/least-requests/revapi.json | 17 +-- load-balancer/least-response-time/revapi.json | 16 --- .../power-of-two-choices/revapi.json | 17 +-- load-balancer/random/revapi.json | 17 +-- load-balancer/sticky/revapi.json | 16 --- service-discovery/composite/revapi.json | 17 +-- service-discovery/consul/revapi.json | 24 ---- .../consul/ConsulServiceDiscovery.java | 1 - service-discovery/dns/revapi.json | 17 +-- .../dns/DnsServiceDiscovery.java | 2 +- service-discovery/eureka/revapi.json | 32 ----- .../eureka/EurekaServiceDiscovery.java | 1 - service-discovery/knative/revapi.json | 17 +-- .../knative/KnativeServiceDiscovery.java | 3 +- service-discovery/kubernetes/revapi.json | 17 +-- .../KubernetesServiceDiscovery.java | 9 +- service-discovery/static-list/revapi.json | 17 +-- .../StaticListServiceDiscoveryProvider.java | 6 +- .../StaticListServiceDiscoveryCDITest.java | 19 +++ 29 files changed, 182 insertions(+), 371 deletions(-) diff --git a/api/revapi.json b/api/revapi.json index 42e62ca7..e444dede 100644 --- a/api/revapi.json +++ b/api/revapi.json @@ -27,131 +27,12 @@ "criticality" : "highlight", "minSeverity" : "POTENTIALLY_BREAKING", "minCriticality" : "documented", - "differences" : [{ - "ignore": true, - "code": "java.method.returnTypeTypeParametersChanged", - "old": "method io.smallrye.stork.api.Metadata io.smallrye.stork.api.Metadata>::empty()", - "new": "method & io.smallrye.stork.api.MetadataKey> io.smallrye.stork.api.Metadata io.smallrye.stork.api.Metadata & io.smallrye.stork.api.MetadataKey>::empty()", - "justification": "Refactored according with the actual type parameter change." - - }, + "differences" : [ { "ignore": true, - "code": "java.generics.elementNowParameterized", - "old": "method io.smallrye.stork.api.Metadata io.smallrye.stork.api.Metadata>::empty()", - "new": "method & io.smallrye.stork.api.MetadataKey> io.smallrye.stork.api.Metadata io.smallrye.stork.api.Metadata & io.smallrye.stork.api.MetadataKey>::empty()", - "justification": "Using a generic method that operates in a parametrized type." - - }, - { - "ignore": true, - "code": "java.generics.formalTypeParameterAdded", - "old": "method io.smallrye.stork.api.Metadata io.smallrye.stork.api.Metadata>::empty()", - "new": "method & io.smallrye.stork.api.MetadataKey> io.smallrye.stork.api.Metadata io.smallrye.stork.api.Metadata & io.smallrye.stork.api.MetadataKey>::empty()", - "typeParameter": "T extends java.lang.Enum & io.smallrye.stork.api.MetadataKey", - "justification": "Add a type parameter representing the element type according with the actual type parameter of the class." - - }, - { - "ignore": true, - "code": "java.method.returnTypeTypeParametersChanged", - "old": "method java.util.EnumMap io.smallrye.stork.api.Metadata>::getMetadata()", - "new": "method java.util.EnumMap io.smallrye.stork.api.Metadata & io.smallrye.stork.api.MetadataKey>::getMetadata()", - "justification": "Refactored according with the actual type parameter change." - - }, - { - "ignore": true, - "code": "java.method.parameterTypeParameterChanged", - "old": "parameter io.smallrye.stork.api.Metadata io.smallrye.stork.api.Metadata>::with(===T===, java.lang.Object)", - "new": "parameter io.smallrye.stork.api.Metadata io.smallrye.stork.api.Metadata & io.smallrye.stork.api.MetadataKey>::with(===T===, java.lang.Object)", - "parameterIndex": "0", - "justification": "Refactored according with the actual type parameter change." - - }, - { - "ignore": true, - "code": "java.method.returnTypeTypeParametersChanged", - "old": "method io.smallrye.stork.api.Metadata io.smallrye.stork.api.Metadata>::with(T, java.lang.Object)", - "new": "method io.smallrye.stork.api.Metadata io.smallrye.stork.api.Metadata & io.smallrye.stork.api.MetadataKey>::with(T, java.lang.Object)", - "justification": "Refactored according with the actual type parameter change." - - }, - { - "ignore": true, - "code": "java.generics.formalTypeParameterChanged", - "old": "class io.smallrye.stork.api.Metadata>", - "new": "class io.smallrye.stork.api.Metadata & io.smallrye.stork.api.MetadataKey>", - "justification": "Adjust the formal type parameter and remove bounded wildcard types used." - - }, - { - "ignore": true, - "code": "java.method.returnTypeChanged", - "old": "method io.smallrye.stork.api.config.LoadBalancerConfig io.smallrye.stork.api.ServiceDefinition::getLoadBalancer()", - "new": "method io.smallrye.stork.api.config.ConfigWithType io.smallrye.stork.api.ServiceDefinition::getLoadBalancer()", - "justification": "Refactored according with the renaming of the returned type." - }, - { - "ignore": true, - "code": "java.method.returnTypeChanged", - "old": "method io.smallrye.stork.api.config.ServiceDiscoveryConfig io.smallrye.stork.api.ServiceDefinition::getServiceDiscovery()", - "new": "method io.smallrye.stork.api.config.ConfigWithType io.smallrye.stork.api.ServiceDefinition::getServiceDiscovery()", - "justification": "Refactored according with the renaming of the returned type." - }, - { - "ignore": true, - "code": "java.method.parameterTypeChanged", - "old": "parameter io.smallrye.stork.api.ServiceDefinition io.smallrye.stork.api.ServiceDefinition::of(===io.smallrye.stork.api.config.ServiceDiscoveryConfig===)", - "new": "parameter io.smallrye.stork.api.ServiceDefinition io.smallrye.stork.api.ServiceDefinition::of(===io.smallrye.stork.api.config.ConfigWithType===)", - "parameterIndex": "0", - "justification": "Refactored according with the renaming of the parameter type." - - }, - { - "ignore": true, - "code": "java.method.parameterTypeChanged", - "old": "parameter io.smallrye.stork.api.ServiceDefinition io.smallrye.stork.api.ServiceDefinition::of(===io.smallrye.stork.api.config.ServiceDiscoveryConfig===, io.smallrye.stork.api.config.LoadBalancerConfig)", - "new": "parameter io.smallrye.stork.api.ServiceDefinition io.smallrye.stork.api.ServiceDefinition::of(===io.smallrye.stork.api.config.ConfigWithType===, io.smallrye.stork.api.config.ConfigWithType)", - "parameterIndex": "0", - "justification": "Refactored according with the renaming of the parameter type." - - }, - { - "ignore": true, - "code": "java.method.parameterTypeChanged", - "old": "parameter io.smallrye.stork.api.ServiceDefinition io.smallrye.stork.api.ServiceDefinition::of(io.smallrye.stork.api.config.ServiceDiscoveryConfig, ===io.smallrye.stork.api.config.LoadBalancerConfig===)", - "new": "parameter io.smallrye.stork.api.ServiceDefinition io.smallrye.stork.api.ServiceDefinition::of(io.smallrye.stork.api.config.ConfigWithType, ===io.smallrye.stork.api.config.ConfigWithType===)", - "parameterIndex": "1", - "justification": "Refactored according with the renaming of the returned type." - - }, - { - "ignore": true, - "code": "java.class.removed", - "old": "interface io.smallrye.stork.api.config.LoadBalancerConfig", - "justification": "Replaced by io.smallrye.stork.api.config.ConfigWithType." - - }, - { - "ignore": true, - "code": "java.method.returnTypeChanged", - "old": "method io.smallrye.stork.api.config.LoadBalancerConfig io.smallrye.stork.api.config.ServiceConfig::loadBalancer()", - "new": "method io.smallrye.stork.api.config.ConfigWithType io.smallrye.stork.api.config.ServiceConfig::loadBalancer()", - "justification": "Refactored according with the renaming of the returned type." - }, - { - "ignore": true, - "code": "java.method.returnTypeChanged", - "old": "method io.smallrye.stork.api.config.ServiceDiscoveryConfig io.smallrye.stork.api.config.ServiceConfig::serviceDiscovery()", - "new": "method io.smallrye.stork.api.config.ConfigWithType io.smallrye.stork.api.config.ServiceConfig::serviceDiscovery()", - "justification": "Refactored according with the renaming of the returned type." - }, - { - "ignore": true, - "code": "java.class.removed", - "old": "interface io.smallrye.stork.api.config.ServiceDiscoveryConfig", - "justification": "Replaced by io.smallrye.stork.api.config.ConfigWithType." + "code": "java.method.addedToInterface", + "new": "method java.util.Optional io.smallrye.stork.api.ServiceInstance::getPath()", + "justification": "New method to handle API gateways" } ] } diff --git a/api/src/main/java/io/smallrye/stork/api/ServiceInstance.java b/api/src/main/java/io/smallrye/stork/api/ServiceInstance.java index 722fb64e..cd80773a 100644 --- a/api/src/main/java/io/smallrye/stork/api/ServiceInstance.java +++ b/api/src/main/java/io/smallrye/stork/api/ServiceInstance.java @@ -3,6 +3,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Map; +import java.util.Optional; /** * Represents an instance of service. @@ -24,6 +25,14 @@ public interface ServiceInstance { */ int getPort(); + /** + * For service behind an API gateway or a proxy, this method return the path. + * When set, the final location of the service is composed of {@code $host:$port/$path}. + * + * @return the path if any. + */ + Optional getPath(); + /** * @return whether the communication should happen over a secure connection */ @@ -58,7 +67,7 @@ default boolean gatherStatistics() { * *
* When {@code gatherStatistics} is enabled, reports the start of an operation using this service instance. - * + *

* The load balancers that keep track of inflight operations should increase the counter on this method. * The load balancer that collect times of operations should only take into account operations that have * {@code measureTime} set to {@code true} @@ -70,7 +79,7 @@ default void recordStart(boolean measureTime) { /** * When {@code gatherStatistics} is enabled, reports a reply for an operation using this service instance. - * + *

* Should be called if and only if {@code recordStart(true)} has been called earlier */ default void recordReply() { diff --git a/api/src/test/java/io/smallrye/stork/api/ServiceInstanceTest.java b/api/src/test/java/io/smallrye/stork/api/ServiceInstanceTest.java index 4ba31ea8..d54d7bce 100644 --- a/api/src/test/java/io/smallrye/stork/api/ServiceInstanceTest.java +++ b/api/src/test/java/io/smallrye/stork/api/ServiceInstanceTest.java @@ -1,6 +1,7 @@ package io.smallrye.stork.api; import java.util.Map; +import java.util.Optional; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -26,6 +27,11 @@ public int getPort() { return 0; } + @Override + public Optional getPath() { + return Optional.empty(); + } + @Override public boolean isSecure() { return false; diff --git a/core/revapi.json b/core/revapi.json index 469f3a55..2c88212a 100644 --- a/core/revapi.json +++ b/core/revapi.json @@ -34,11 +34,9 @@ "differences" : [ { "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.impl.RoundRobinLoadBalancerProviderLoader", - "new": "class io.smallrye.stork.impl.RoundRobinLoadBalancerProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "Load Balancer can now be CDI beans" + "code": "java.method.addedToInterface", + "new": "method java.util.Optional io.smallrye.stork.api.ServiceInstance::getPath()", + "justification": "New method to handle API gateways" } ] } diff --git a/core/src/main/java/io/smallrye/stork/impl/DefaultServiceInstance.java b/core/src/main/java/io/smallrye/stork/impl/DefaultServiceInstance.java index 0e774fc4..06548704 100644 --- a/core/src/main/java/io/smallrye/stork/impl/DefaultServiceInstance.java +++ b/core/src/main/java/io/smallrye/stork/impl/DefaultServiceInstance.java @@ -2,11 +2,13 @@ import java.util.Collections; import java.util.Map; +import java.util.Optional; import io.smallrye.stork.api.Metadata; import io.smallrye.stork.api.MetadataKey; import io.smallrye.stork.api.ServiceInstance; +@SuppressWarnings("OptionalUsedAsFieldOrParameterType") public class DefaultServiceInstance implements ServiceInstance { private final long id; @@ -17,21 +19,45 @@ public class DefaultServiceInstance implements ServiceInstance { private final boolean secure; + private final Optional path; + private final Map labels; - private Metadata metadata; + private final Metadata metadata; + + public DefaultServiceInstance(long id, String host, int port, String path, boolean secure) { + this(id, host, port, Optional.ofNullable(path), secure, Collections.emptyMap(), + Metadata.empty()); + } + + public DefaultServiceInstance(long id, String host, int port, Optional path, boolean secure) { + this(id, host, port, path, secure, Collections.emptyMap(), + Metadata.empty()); + } public DefaultServiceInstance(long id, String host, int port, boolean secure) { - this(id, host, port, secure, Collections.emptyMap(), + this(id, host, port, Optional.empty(), secure, Collections.emptyMap(), Metadata.empty()); } + public DefaultServiceInstance(long id, String host, int port, boolean secure, Metadata metadata) { + this(id, host, port, Optional.empty(), secure, Collections.emptyMap(), + metadata); + } + public DefaultServiceInstance(long id, String host, int port, boolean secure, Map labels, Metadata metadata) { + this(id, host, port, Optional.empty(), secure, labels, metadata); + } + + public DefaultServiceInstance(long id, String host, int port, Optional path, boolean secure, + Map labels, + Metadata metadata) { this.id = id; this.host = host; this.port = port; this.secure = secure; + this.path = path; this.labels = Collections.unmodifiableMap(labels); this.metadata = metadata; } @@ -51,6 +77,11 @@ public int getPort() { return port; } + @Override + public Optional getPath() { + return path; + } + @Override public boolean isSecure() { return secure; diff --git a/core/src/main/java/io/smallrye/stork/impl/ServiceInstanceWithStatGathering.java b/core/src/main/java/io/smallrye/stork/impl/ServiceInstanceWithStatGathering.java index 7a915d33..c37caa2f 100644 --- a/core/src/main/java/io/smallrye/stork/impl/ServiceInstanceWithStatGathering.java +++ b/core/src/main/java/io/smallrye/stork/impl/ServiceInstanceWithStatGathering.java @@ -1,5 +1,7 @@ package io.smallrye.stork.impl; +import java.util.Optional; + import io.smallrye.stork.api.ServiceInstance; import io.smallrye.stork.spi.CallStatisticsCollector; @@ -34,6 +36,11 @@ public int getPort() { return delegate.getPort(); } + @Override + public Optional getPath() { + return delegate.getPath(); + } + @Override public boolean isSecure() { return delegate.isSecure(); diff --git a/core/src/main/java/io/smallrye/stork/utils/HostAndPort.java b/core/src/main/java/io/smallrye/stork/utils/HostAndPort.java index 2f93b6e1..29af513e 100644 --- a/core/src/main/java/io/smallrye/stork/utils/HostAndPort.java +++ b/core/src/main/java/io/smallrye/stork/utils/HostAndPort.java @@ -1,8 +1,11 @@ package io.smallrye.stork.utils; +import java.util.Optional; + /** * Structure representing a host:port address. */ +@SuppressWarnings("OptionalUsedAsFieldOrParameterType") public class HostAndPort { /** * The host. @@ -13,14 +16,31 @@ public class HostAndPort { */ public final int port; + /** + * The path, if any. + */ + public final Optional path; + /** * Creates a new HostAndPort * * @param host the host * @param port the port + * @param path the path, can be {@code null} */ - public HostAndPort(String host, int port) { + public HostAndPort(String host, int port, String path) { this.host = host; this.port = port; + this.path = Optional.ofNullable(path); + } + + /** + * Creates a new HostAndPort + * + * @param host the host + * @param port the port + */ + public HostAndPort(String host, int port) { + this(host, port, null); } } diff --git a/core/src/main/java/io/smallrye/stork/utils/StorkAddressUtils.java b/core/src/main/java/io/smallrye/stork/utils/StorkAddressUtils.java index 5d8d8c79..4d89f856 100644 --- a/core/src/main/java/io/smallrye/stork/utils/StorkAddressUtils.java +++ b/core/src/main/java/io/smallrye/stork/utils/StorkAddressUtils.java @@ -24,22 +24,36 @@ public static HostAndPort parseToHostAndPort(String address, if (address.charAt(0) == '[') { return parseIpV6AddressWithSquareBracket(address, defaultPort, configPlace); } else if (countColons(address) > 1) { + // IPv6. return new HostAndPort(address, defaultPort); } else { - return parseNonIpv6Adress(address, defaultPort, configPlace); + return parseNonIpv6Address(address, defaultPort, configPlace); } } - private static HostAndPort parseNonIpv6Adress(String serviceAddress, int defaultPort, String serviceName) { + private static HostAndPort parseNonIpv6Address(String serviceAddress, int defaultPort, String serviceName) { String[] hostAndMaybePort = serviceAddress.split(":"); switch (hostAndMaybePort.length) { - case 1: - return new HostAndPort(serviceAddress, defaultPort); + case 1: { + int idx = serviceAddress.indexOf("/"); + if (idx == -1) { + return new HostAndPort(serviceAddress, defaultPort); + } else { + return new HostAndPort(serviceAddress.substring(0, idx), defaultPort, + serviceAddress.substring(idx)); + } + } case 2: try { - int port = Integer.parseInt(hostAndMaybePort[1]); - return new HostAndPort(hostAndMaybePort[0], port); + int idx = hostAndMaybePort[1].indexOf("/"); + if (idx == -1) { + int port = Integer.parseInt(hostAndMaybePort[1]); + return new HostAndPort(hostAndMaybePort[0], port); + } else { + int port = Integer.parseInt(hostAndMaybePort[1].substring(0, idx)); + return new HostAndPort(hostAndMaybePort[0], port, hostAndMaybePort[1].substring(idx)); + } } catch (NumberFormatException nfe) { throw new IllegalArgumentException(format("Invalid port '%s' in address '%s' for service '%s'", hostAndMaybePort[1], serviceAddress, serviceName), nfe); diff --git a/core/src/test/java/io/smallrye/stork/impl/CachingServiceDiscoveryRefreshTest.java b/core/src/test/java/io/smallrye/stork/impl/CachingServiceDiscoveryRefreshTest.java index b77e9255..f4925dee 100644 --- a/core/src/test/java/io/smallrye/stork/impl/CachingServiceDiscoveryRefreshTest.java +++ b/core/src/test/java/io/smallrye/stork/impl/CachingServiceDiscoveryRefreshTest.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -42,8 +43,9 @@ void shouldTriggerSupplierOnceAndCompleteAllConsumersWhenDone() throws Interrupt public Uni> fetchNewServiceInstances(List previousInstances) { refreshCount.incrementAndGet(); return Uni.createFrom().emitter(e -> { - List results = asList(new DefaultServiceInstance(1, "localhost", 8406, false), - new DefaultServiceInstance(2, "localhost", 8407, false)); + List results = asList( + new DefaultServiceInstance(1, "localhost", 8406, Optional.empty(), false), + new DefaultServiceInstance(2, "localhost", 8407, Optional.empty(), false)); vertx.setTimer(2000, ignored -> e.complete(results)); }); } diff --git a/core/src/test/java/io/smallrye/stork/utils/StorkAddressUtilsTest.java b/core/src/test/java/io/smallrye/stork/utils/StorkAddressUtilsTest.java index b0681ee2..9f18ac47 100644 --- a/core/src/test/java/io/smallrye/stork/utils/StorkAddressUtilsTest.java +++ b/core/src/test/java/io/smallrye/stork/utils/StorkAddressUtilsTest.java @@ -13,6 +13,7 @@ void shouldParseIpv6WithoutPort() { "serviceUsingDefaultPort"); assertThat(result.host).isEqualTo(ipv6WithoutPort); assertThat(result.port).isEqualTo(8080); + assertThat(result.path).isEmpty(); } @Test @@ -24,6 +25,7 @@ void shouldParseIpv6WithSquareBracketsWithoutPort() { "serviceWithSquareBracketsUsingDefaultPort"); assertThat(result.host).isEqualTo(ipv6WithoutPort); assertThat(result.port).isEqualTo(8080); + assertThat(result.path).isEmpty(); } @Test @@ -36,6 +38,7 @@ void shouldParseIpv6WithPort() { HostAndPort result = StorkAddressUtils.parseToHostAndPort(toParse, 8080, "serviceUsingSpecifiedPort"); assertThat(result.host).isEqualTo(ipv6WithoutPort); assertThat(result.port).isEqualTo(1382); + assertThat(result.path).isEmpty(); } @Test @@ -44,15 +47,27 @@ void shouldParseIpV4WithoutPort() { HostAndPort result = StorkAddressUtils.parseToHostAndPort(ipV4WithoutPort, 8383, "serviceUsingIPv4AdressWithoutPort"); assertThat(result.host).isEqualTo(ipV4WithoutPort); assertThat(result.port).isEqualTo(8383); + assertThat(result.path).isEmpty(); } @Test void shouldParseIpV4WithPort() { String address = "127.0.0.1"; String addressWithPort = address + ":8787"; - HostAndPort result = StorkAddressUtils.parseToHostAndPort(addressWithPort, 8383, "serviceUsingIPv4AdressWithPort"); + HostAndPort result = StorkAddressUtils.parseToHostAndPort(addressWithPort, 8383, "serviceUsingIPv4AddressWithPort"); assertThat(result.host).isEqualTo(address); assertThat(result.port).isEqualTo(8787); + assertThat(result.path).isEmpty(); + } + + @Test + void shouldParseIpV4WithPortAndPath() { + String address = "127.0.0.1"; + String addressWithPort = address + ":8787/test"; + HostAndPort result = StorkAddressUtils.parseToHostAndPort(addressWithPort, 8383, "serviceUsingIPv4AddressWithPort"); + assertThat(result.host).isEqualTo(address); + assertThat(result.port).isEqualTo(8787); + assertThat(result.path).contains("/test"); } @Test @@ -64,12 +79,31 @@ void shouldParseHostnameWithoutPort() { } @Test - void shoyuldParseHostnameWithPort() { + void shouldParseHostnameWithoutPortButWithPath() { + String address = "my-host.com.pl/foo/bar"; + HostAndPort result = StorkAddressUtils.parseToHostAndPort(address, 8383, "serviceUsingHostnameWithoutPort"); + assertThat(result.host).isEqualTo("my-host.com.pl"); + assertThat(result.port).isEqualTo(8383); + assertThat(result.path).contains("/foo/bar"); + } + + @Test + void shouldParseHostnameWithPort() { String address = "my-host.com.pl"; String addressWithPort = address + ":8989"; HostAndPort result = StorkAddressUtils.parseToHostAndPort(addressWithPort, 8383, "serviceUsingHostnameWithPort"); assertThat(result.host).isEqualTo(address); assertThat(result.port).isEqualTo(8989); + assertThat(result.path).isEmpty(); + } + + @Test + void shouldParseHostnameWithPortWithPath() { + String addressWithPort = "my-host.com.pl:8989/test/123"; + HostAndPort result = StorkAddressUtils.parseToHostAndPort(addressWithPort, 8383, "serviceUsingHostnameWithPort"); + assertThat(result.host).isEqualTo("my-host.com.pl"); + assertThat(result.port).isEqualTo(8989); + assertThat(result.path).contains("/test/123"); } } diff --git a/load-balancer/least-requests/revapi.json b/load-balancer/least-requests/revapi.json index 379ff3ff..8946e9a8 100644 --- a/load-balancer/least-requests/revapi.json +++ b/load-balancer/least-requests/revapi.json @@ -25,22 +25,7 @@ "minSeverity" : "POTENTIALLY_BREAKING", "minCriticality" : "documented", "differences" : [ - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.loadbalancer.requests.LeastRequestsLoadBalancerProvider", - "new": "class io.smallrye.stork.loadbalancer.requests.LeastRequestsLoadBalancerProvider", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.loadbalancer.requests.LeastRequestsLoadBalancerProviderLoader", - "new": "class io.smallrye.stork.loadbalancer.requests.LeastRequestsLoadBalancerProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - } + ] } }, { diff --git a/load-balancer/least-response-time/revapi.json b/load-balancer/least-response-time/revapi.json index d6ef80d1..9856d0cb 100644 --- a/load-balancer/least-response-time/revapi.json +++ b/load-balancer/least-response-time/revapi.json @@ -25,22 +25,6 @@ "minSeverity" : "POTENTIALLY_BREAKING", "minCriticality" : "documented", "differences" : [ - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.loadbalancer.leastresponsetime.LeastResponseTimeLoadBalancerProvider", - "new": "class io.smallrye.stork.loadbalancer.leastresponsetime.LeastResponseTimeLoadBalancerProvider", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.loadbalancer.leastresponsetime.LeastResponseTimeLoadBalancerProviderLoader", - "new": "class io.smallrye.stork.loadbalancer.leastresponsetime.LeastResponseTimeLoadBalancerProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - } ] } }, { diff --git a/load-balancer/power-of-two-choices/revapi.json b/load-balancer/power-of-two-choices/revapi.json index a33571bf..044d5546 100644 --- a/load-balancer/power-of-two-choices/revapi.json +++ b/load-balancer/power-of-two-choices/revapi.json @@ -25,22 +25,7 @@ "minSeverity" : "POTENTIALLY_BREAKING", "minCriticality" : "documented", "differences" : [ - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.loadbalancer.poweroftwochoices.PowerOfTwoChoicesLoadBalancerProvider", - "new": "class io.smallrye.stork.loadbalancer.poweroftwochoices.PowerOfTwoChoicesLoadBalancerProvider", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.loadbalancer.poweroftwochoices.PowerOfTwoChoicesLoadBalancerProviderLoader", - "new": "class io.smallrye.stork.loadbalancer.poweroftwochoices.PowerOfTwoChoicesLoadBalancerProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - } + ] } }, { diff --git a/load-balancer/random/revapi.json b/load-balancer/random/revapi.json index 8bc0ca30..d94ca593 100644 --- a/load-balancer/random/revapi.json +++ b/load-balancer/random/revapi.json @@ -25,22 +25,7 @@ "minSeverity" : "POTENTIALLY_BREAKING", "minCriticality" : "documented", "differences" : [ - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.loadbalancer.random.RandomLoadBalancerProviderLoader", - "new": "class io.smallrye.stork.loadbalancer.random.RandomLoadBalancerProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.loadbalancer.random.RandomLoadBalancerProvider", - "new": "class io.smallrye.stork.loadbalancer.random.RandomLoadBalancerProvider", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" - } + ] } }, { diff --git a/load-balancer/sticky/revapi.json b/load-balancer/sticky/revapi.json index 65cb731c..5f8c0ead 100644 --- a/load-balancer/sticky/revapi.json +++ b/load-balancer/sticky/revapi.json @@ -30,22 +30,6 @@ "minSeverity": "POTENTIALLY_BREAKING", "minCriticality": "documented", "differences": [ - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.loadbalancer.random.StickyLoadBalancerProvider", - "new": "class io.smallrye.stork.loadbalancer.random.StickyLoadBalancerProvider", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.loadbalancer.random.StickyLoadBalancerProviderLoader", - "new": "class io.smallrye.stork.loadbalancer.random.StickyLoadBalancerProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - } ] } }, diff --git a/service-discovery/composite/revapi.json b/service-discovery/composite/revapi.json index 806d6d80..b7379ab5 100644 --- a/service-discovery/composite/revapi.json +++ b/service-discovery/composite/revapi.json @@ -25,22 +25,7 @@ "minSeverity" : "POTENTIALLY_BREAKING", "minCriticality" : "documented", "differences" : [ - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.composite.CompositeServiceDiscoveryProvider", - "new": "class io.smallrye.stork.servicediscovery.composite.CompositeServiceDiscoveryProvider", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.composite.CompositeServiceDiscoveryProviderLoader", - "new": "class io.smallrye.stork.servicediscovery.composite.CompositeServiceDiscoveryProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - } + ] } }, { diff --git a/service-discovery/consul/revapi.json b/service-discovery/consul/revapi.json index 0e0bad45..c5fcaafb 100644 --- a/service-discovery/consul/revapi.json +++ b/service-discovery/consul/revapi.json @@ -25,31 +25,7 @@ "minSeverity" : "POTENTIALLY_BREAKING", "minCriticality" : "documented", "differences" : [ - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.consul.ConsulServiceDiscoveryProviderLoader", - "new": "class io.smallrye.stork.servicediscovery.consul.ConsulServiceDiscoveryProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.consul.ConsulServiceDiscoveryProvider", - "new": "class io.smallrye.stork.servicediscovery.consul.ConsulServiceDiscoveryProvider", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.consul.ConsulServiceRegistrarProviderLoader", - "new": "class io.smallrye.stork.servicediscovery.consul.ConsulServiceRegistrarProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - } ] } }, { diff --git a/service-discovery/consul/src/main/java/io/smallrye/stork/servicediscovery/consul/ConsulServiceDiscovery.java b/service-discovery/consul/src/main/java/io/smallrye/stork/servicediscovery/consul/ConsulServiceDiscovery.java index e2b0099c..4bb5619c 100644 --- a/service-discovery/consul/src/main/java/io/smallrye/stork/servicediscovery/consul/ConsulServiceDiscovery.java +++ b/service-discovery/consul/src/main/java/io/smallrye/stork/servicediscovery/consul/ConsulServiceDiscovery.java @@ -76,7 +76,6 @@ private List toStorkServiceInstances(ServiceEntryList serviceEn if (address == null) { throw new IllegalArgumentException("Got null address for service " + serviceName); } - ServiceInstance matching = ServiceInstanceUtils.findMatching(previousInstances, address, port); if (matching != null) { serviceInstances.add(matching); diff --git a/service-discovery/dns/revapi.json b/service-discovery/dns/revapi.json index 2daa0a21..9e351da8 100644 --- a/service-discovery/dns/revapi.json +++ b/service-discovery/dns/revapi.json @@ -25,22 +25,7 @@ "minSeverity" : "POTENTIALLY_BREAKING", "minCriticality" : "documented", "differences" : [ - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.dns.DnsServiceDiscoveryProvider", - "new": "class io.smallrye.stork.servicediscovery.dns.DnsServiceDiscoveryProvider", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.dns.DnsServiceDiscoveryProviderLoader", - "new": "class io.smallrye.stork.servicediscovery.dns.DnsServiceDiscoveryProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - } + ] } }, { diff --git a/service-discovery/dns/src/main/java/io/smallrye/stork/servicediscovery/dns/DnsServiceDiscovery.java b/service-discovery/dns/src/main/java/io/smallrye/stork/servicediscovery/dns/DnsServiceDiscovery.java index b1c58110..a2c9487e 100644 --- a/service-discovery/dns/src/main/java/io/smallrye/stork/servicediscovery/dns/DnsServiceDiscovery.java +++ b/service-discovery/dns/src/main/java/io/smallrye/stork/servicediscovery/dns/DnsServiceDiscovery.java @@ -259,7 +259,7 @@ private ServiceInstance toStorkServiceInstance(String target, int port, int weig ServiceInstance matching = ServiceInstanceUtils.findMatching(previousInstances, target, port); if (matching == null) { return new DefaultServiceInstance(ServiceInstanceIds.next(), - target, port, secure, Collections.emptyMap(), dnsMetadata); + target, port, secure, dnsMetadata); } else { return matching; } diff --git a/service-discovery/eureka/revapi.json b/service-discovery/eureka/revapi.json index 62cfcd61..a4186133 100644 --- a/service-discovery/eureka/revapi.json +++ b/service-discovery/eureka/revapi.json @@ -25,38 +25,6 @@ "minSeverity" : "POTENTIALLY_BREAKING", "minCriticality" : "documented", "differences" : [ - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.eureka.EurekaServiceDiscoveryProvider", - "new": "class io.smallrye.stork.servicediscovery.eureka.EurekaServiceDiscoveryProvider", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.eureka.EurekaServiceRegistrarProvider", - "new": "class io.smallrye.stork.servicediscovery.eureka.EurekaServiceRegistrarProvider", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "ADD YOUR EXPLANATION FOR THE NECESSITY OF THIS CHANGE" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.eureka.EurekaServiceDiscoveryProviderLoader", - "new": "class io.smallrye.stork.servicediscovery.eureka.EurekaServiceDiscoveryProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.eureka.EurekaServiceRegistrarProviderLoader", - "new": "class io.smallrye.stork.servicediscovery.eureka.EurekaServiceRegistrarProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - } ] } }, { diff --git a/service-discovery/eureka/src/main/java/io/smallrye/stork/servicediscovery/eureka/EurekaServiceDiscovery.java b/service-discovery/eureka/src/main/java/io/smallrye/stork/servicediscovery/eureka/EurekaServiceDiscovery.java index f4babd4f..58c8c6a7 100644 --- a/service-discovery/eureka/src/main/java/io/smallrye/stork/servicediscovery/eureka/EurekaServiceDiscovery.java +++ b/service-discovery/eureka/src/main/java/io/smallrye/stork/servicediscovery/eureka/EurekaServiceDiscovery.java @@ -113,7 +113,6 @@ private List toStorkServiceInstances(Stream toStorkServiceInstances(List knServices, } serviceInstances - .add(new DefaultServiceInstance(ServiceInstanceIds.next(), host, -1, secure, + .add(new DefaultServiceInstance(ServiceInstanceIds.next(), host, -1, Optional.empty(), secure, labels, knativeMetadata .with(KnativeMetadataKey.META_KNATIVE_SERVICE_ID, knService.getFullResourceName()) diff --git a/service-discovery/kubernetes/revapi.json b/service-discovery/kubernetes/revapi.json index eff4d54b..62bb8d31 100644 --- a/service-discovery/kubernetes/revapi.json +++ b/service-discovery/kubernetes/revapi.json @@ -25,22 +25,7 @@ "minSeverity" : "POTENTIALLY_BREAKING", "minCriticality" : "documented", "differences" : [ - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.kubernetes.KubernetesServiceDiscoveryProvider", - "new": "class io.smallrye.stork.servicediscovery.kubernetes.KubernetesServiceDiscoveryProvider", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "ADD YOUR EThe loaders are now also exposed as CDI beans" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.kubernetes.KubernetesServiceDiscoveryProviderLoader", - "new": "class io.smallrye.stork.servicediscovery.kubernetes.KubernetesServiceDiscoveryProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "The loaders are now also exposed as CDI beans" - } + ] } }, { diff --git a/service-discovery/kubernetes/src/main/java/io/smallrye/stork/servicediscovery/kubernetes/KubernetesServiceDiscovery.java b/service-discovery/kubernetes/src/main/java/io/smallrye/stork/servicediscovery/kubernetes/KubernetesServiceDiscovery.java index d53309dc..d3612117 100644 --- a/service-discovery/kubernetes/src/main/java/io/smallrye/stork/servicediscovery/kubernetes/KubernetesServiceDiscovery.java +++ b/service-discovery/kubernetes/src/main/java/io/smallrye/stork/servicediscovery/kubernetes/KubernetesServiceDiscovery.java @@ -209,10 +209,11 @@ private List toStorkServiceInstances(Map> } //TODO add some useful metadata? Metadata k8sMetadata = Metadata.of(KubernetesMetadataKey.class); - serviceInstances.add(new DefaultServiceInstance(ServiceInstanceIds.next(), hostname, port, secure, - labels, - k8sMetadata.with(META_K8S_SERVICE_ID, hostname).with(META_K8S_NAMESPACE, podNamespace) - .with(META_K8S_PORT_PROTOCOL, protocol))); + serviceInstances.add( + new DefaultServiceInstance(ServiceInstanceIds.next(), hostname, port, Optional.empty(), secure, + labels, + k8sMetadata.with(META_K8S_SERVICE_ID, hostname).with(META_K8S_NAMESPACE, podNamespace) + .with(META_K8S_PORT_PROTOCOL, protocol))); } } } diff --git a/service-discovery/static-list/revapi.json b/service-discovery/static-list/revapi.json index b9cda203..f548e110 100644 --- a/service-discovery/static-list/revapi.json +++ b/service-discovery/static-list/revapi.json @@ -25,22 +25,7 @@ "minSeverity" : "POTENTIALLY_BREAKING", "minCriticality" : "documented", "differences" : [ - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.staticlist.StaticListServiceDiscoveryProvider", - "new": "class io.smallrye.stork.servicediscovery.staticlist.StaticListServiceDiscoveryProvider", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "the loaders are now also exposed as CDI beans" - }, - { - "ignore": true, - "code": "java.annotation.added", - "old": "class io.smallrye.stork.servicediscovery.staticlist.StaticListServiceDiscoveryProviderLoader", - "new": "class io.smallrye.stork.servicediscovery.staticlist.StaticListServiceDiscoveryProviderLoader", - "annotation": "@jakarta.enterprise.context.ApplicationScoped", - "justification": "the loaders are now also exposed as CDI beans" - } + ] } }, { diff --git a/service-discovery/static-list/src/main/java/io/smallrye/stork/servicediscovery/staticlist/StaticListServiceDiscoveryProvider.java b/service-discovery/static-list/src/main/java/io/smallrye/stork/servicediscovery/staticlist/StaticListServiceDiscoveryProvider.java index dce2b4aa..597938a1 100644 --- a/service-discovery/static-list/src/main/java/io/smallrye/stork/servicediscovery/staticlist/StaticListServiceDiscoveryProvider.java +++ b/service-discovery/static-list/src/main/java/io/smallrye/stork/servicediscovery/staticlist/StaticListServiceDiscoveryProvider.java @@ -1,6 +1,5 @@ package io.smallrye.stork.servicediscovery.staticlist; -import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -38,16 +37,15 @@ public ServiceDiscovery createServiceDiscovery(StaticConfiguration config, Strin } List addressList = new ArrayList<>(); for (String address : addresses.split(",")) { - URL url = null; address = address.trim(); try { HostAndPort hostAndPort = StorkAddressUtils.parseToHostAndPort(address, 80, "service '" + serviceName + "'"); addressList .add(new DefaultServiceInstance(ServiceInstanceIds.next(), hostAndPort.host, hostAndPort.port, - isSecure(config.getSecure(), hostAndPort.port))); + hostAndPort.path, isSecure(config.getSecure(), hostAndPort.port))); } catch (Exception e) { throw new IllegalArgumentException( - "Address not parseable to URL: " + url + " for service " + serviceName); + "Address not parseable to URL: " + address + " for service " + serviceName); } } diff --git a/service-discovery/static-list/src/test/java/io/smallrye/stork/servicediscovery/staticlist/StaticListServiceDiscoveryCDITest.java b/service-discovery/static-list/src/test/java/io/smallrye/stork/servicediscovery/staticlist/StaticListServiceDiscoveryCDITest.java index 2e029220..3d7b41a3 100644 --- a/service-discovery/static-list/src/test/java/io/smallrye/stork/servicediscovery/staticlist/StaticListServiceDiscoveryCDITest.java +++ b/service-discovery/static-list/src/test/java/io/smallrye/stork/servicediscovery/staticlist/StaticListServiceDiscoveryCDITest.java @@ -42,6 +42,8 @@ void setUp() { null, Map.of("address-list", "localhost:8082", "secure", "true")); config.addServiceConfig("third-service", null, "static", null, Map.of("address-list", "localhost:8083")); + config.addServiceConfig("fourth-service", null, "static", + null, Map.of("address-list", "localhost:8083/foo, localhost:8083/bar")); config.addServiceConfig("secured-service", null, "static", null, Map.of("address-list", "localhost:443, localhost")); @@ -77,6 +79,23 @@ void shouldGetAllServiceInstances() { assertThat(serviceInstances.stream().map(ServiceInstance::isSecure)).allSatisfy(b -> assertThat(b).isFalse()); } + @Test + void shouldParsePath() { + List serviceInstances = stork.getService("fourth-service") + .getInstances() + .await().atMost(Duration.ofSeconds(5)); + + assertThat(serviceInstances).hasSize(2); + assertThat(serviceInstances.stream().map(ServiceInstance::getHost)).containsExactlyInAnyOrder("localhost", + "localhost"); + assertThat(serviceInstances.stream().map(ServiceInstance::getPort)).containsExactlyInAnyOrder(8083, + 8083); + assertThat(serviceInstances.stream().map(ServiceInstance::getPath).map(s -> s.orElse(null))).containsExactlyInAnyOrder( + "/foo", + "/bar"); + assertThat(serviceInstances.stream().map(ServiceInstance::isSecure)).allSatisfy(b -> assertThat(b).isFalse()); + } + @Test void shouldFailOnMissingService() { assertThatThrownBy(() -> stork.getService("missing")).isInstanceOf(NoSuchServiceDefinitionException.class);