diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/XdsLoadBalanceService.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/XdsLoadBalanceService.java index de1ba0b5c1..5088fb09da 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/XdsLoadBalanceService.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/XdsLoadBalanceService.java @@ -33,6 +33,15 @@ public interface XdsLoadBalanceService { */ XdsLbPolicy getLbPolicyOfCluster(String clusterName); + /** + * get lb policy of cluster + * + * @param serviceName service name + * @param clusterName cluster name + * @return route rules + */ + XdsLbPolicy getLbPolicyOfCluster(String serviceName, String clusterName); + /** * get lb policy of service (base cluster) * diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/XdsRouteService.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/XdsRouteService.java index af4d2c6e96..b81026cc08 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/XdsRouteService.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/XdsRouteService.java @@ -42,4 +42,13 @@ public interface XdsRouteService { * @return route rules */ boolean isLocalityRoute(String clusterName); + + /** + * get lb policy of cluster + * + * @param serviceName service name + * @param clusterName cluster name + * @return route rules + */ + boolean isLocalityRoute(String serviceName, String clusterName); } diff --git a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/XdsServiceDiscovery.java b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/XdsServiceDiscovery.java index d6fcb0e82e..8b341a6e07 100644 --- a/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/XdsServiceDiscovery.java +++ b/sermant-agentcore/sermant-agentcore-core/src/main/java/io/sermant/core/service/xds/XdsServiceDiscovery.java @@ -46,6 +46,15 @@ public interface XdsServiceDiscovery { */ Optional getClusterServiceInstance(String clusterName); + /** + * get service instance of service cluster + * + * @param serviceName service name + * @param clusterName cluster name + * @return XdsClusterInstance + */ + Optional getClusterServiceInstance(String serviceName, String clusterName); + /** * subscribe service instance without tag by service name, the listener will be triggered when the service instance * changes diff --git a/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/discovery/XdsServiceDiscoveryImpl.java b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/discovery/XdsServiceDiscoveryImpl.java index 15da0514e7..7b40e243f5 100644 --- a/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/discovery/XdsServiceDiscoveryImpl.java +++ b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/discovery/XdsServiceDiscoveryImpl.java @@ -103,9 +103,12 @@ public Optional getClusterServiceInstance(String cluste if (!serviceNameOptional.isPresent()) { return Optional.empty(); } - String serviceName = serviceNameOptional.get(); + return getClusterServiceInstance(serviceName, clusterName); + } + @Override + public Optional getClusterServiceInstance(String serviceName, String clusterName) { // first check the cache and return if service instance exists if (XdsDataCache.isContainsRequestObserver(serviceName)) { return XdsDataCache.getClusterServiceInstance(serviceName, clusterName); diff --git a/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/loadbalance/XdsLoadBalanceServiceImpl.java b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/loadbalance/XdsLoadBalanceServiceImpl.java index 61fe6817ff..36890ed248 100644 --- a/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/loadbalance/XdsLoadBalanceServiceImpl.java +++ b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/loadbalance/XdsLoadBalanceServiceImpl.java @@ -45,6 +45,11 @@ public XdsLbPolicy getLbPolicyOfCluster(String clusterName) { return XdsLbPolicy.UNRECOGNIZED; } + @Override + public XdsLbPolicy getLbPolicyOfCluster(String serviceName, String clusterName) { + return XdsDataCache.getLbPolicyOfCluster(serviceName, clusterName); + } + @Override public XdsLbPolicy getBaseLbPolicyOfService(String serviceName) { return XdsDataCache.getBaseLbPolicyOfService(serviceName); diff --git a/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/route/XdsRouteServiceImpl.java b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/route/XdsRouteServiceImpl.java index 42be2fd3b5..d717f21994 100644 --- a/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/route/XdsRouteServiceImpl.java +++ b/sermant-agentcore/sermant-agentcore-implement/src/main/java/io/sermant/implement/service/xds/route/XdsRouteServiceImpl.java @@ -47,4 +47,9 @@ public boolean isLocalityRoute(String clusterName) { .map(serviceName -> XdsDataCache.isLocalityLb(serviceName, clusterName)) .orElse(false); } -} \ No newline at end of file + + @Override + public boolean isLocalityRoute(String serviceName, String clusterName) { + return XdsDataCache.isLocalityLb(serviceName, clusterName); + } +} diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/utils/XdsRouterUtils.java b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/utils/XdsRouterUtils.java index 9ba22daa30..0f87450e04 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/utils/XdsRouterUtils.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/utils/XdsRouterUtils.java @@ -45,6 +45,8 @@ public class XdsRouterUtils { */ private static XdsLocality selfServiceLocality; + private static volatile boolean localityObtainedFlag = false; + private XdsRouterUtils() { } @@ -54,13 +56,14 @@ private XdsRouterUtils() { * @return XdsLocality */ public static Optional getLocalityInfoOfSelfService() { - if (selfServiceLocality != null) { - return Optional.of(selfServiceLocality); + if (localityObtainedFlag) { + return Optional.ofNullable(selfServiceLocality); } synchronized (XdsRouterUtils.class) { - if (selfServiceLocality != null) { - return Optional.of(selfServiceLocality); + if (localityObtainedFlag) { + return Optional.ofNullable(selfServiceLocality); } + localityObtainedFlag = true; String podIp = NetworkUtils.getKubernetesPodIp(); if (StringUtils.isEmpty(podIp)) { return Optional.empty(); @@ -88,6 +91,15 @@ public static void updateServiceDiscovery(XdsServiceDiscovery xdsServiceDiscover } } + /** + * update localityObtainedFlag + * + * @param flag locality obtained flag + */ + public static void updateLocalityObtainedFlag(boolean flag) { + localityObtainedFlag = flag; + } + private static Optional getMatchedServiceInstanceByPodIp(Set serviceInstances, String podIp) { return serviceInstances.stream() diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/xds/XdsRouterHandler.java b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/xds/XdsRouterHandler.java index eb5dbdffe4..b0b9373b4a 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/xds/XdsRouterHandler.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/xds/XdsRouterHandler.java @@ -36,8 +36,10 @@ import io.sermant.router.common.utils.XdsRouterUtils; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Optional; import java.util.Random; import java.util.Set; @@ -151,13 +153,13 @@ private Set handleXdsRoute(XdsRoute route, String serviceName) // get service instance of cluster Optional loadAssigmentOptional = - serviceDiscovery.getClusterServiceInstance(cluster); + serviceDiscovery.getClusterServiceInstance(serviceName, cluster); if (!loadAssigmentOptional.isPresent()) { return serviceDiscovery.getServiceInstance(serviceName); } XdsClusterLoadAssigment clusterLoadAssigment = loadAssigmentOptional.get(); - if (!routeService.isLocalityRoute(clusterLoadAssigment.getClusterName())) { + if (!routeService.isLocalityRoute(serviceName, clusterLoadAssigment.getClusterName())) { Set serviceInstances = getServiceInstanceOfCluster(clusterLoadAssigment); return serviceInstances.isEmpty() ? serviceDiscovery.getServiceInstance(serviceName) : serviceInstances; } @@ -179,15 +181,34 @@ private Set handleXdsRoute(XdsRoute route, String serviceName) private Set getServiceInstanceOfLocalityCluster(XdsClusterLoadAssigment clusterLoadAssigment, XdsLocality locality) { return clusterLoadAssigment.getLocalityInstances().entrySet().stream() - .filter(xdsLocalitySetEntry -> xdsLocalitySetEntry.getKey().equals(locality)) + .filter(xdsLocalitySetEntry -> isSameLocality(locality, xdsLocalitySetEntry.getKey())) .flatMap(xdsLocalitySetEntry -> xdsLocalitySetEntry.getValue().stream()) .collect(Collectors.toSet()); } + private boolean isSameLocality(XdsLocality selfLocality, XdsLocality serviceLocality) { + if (!selfLocality.getRegion().equals(serviceLocality.getRegion())) { + return false; + } + if (StringUtils.isEmpty(selfLocality.getZone())) { + return true; + } + if (!selfLocality.getZone().equals(serviceLocality.getZone())) { + return false; + } + if (StringUtils.isEmpty(selfLocality.getSubZone())) { + return true; + } + return selfLocality.getSubZone().equals(serviceLocality.getSubZone()); + } + private Set getServiceInstanceOfCluster(XdsClusterLoadAssigment clusterLoadAssigment) { - return clusterLoadAssigment.getLocalityInstances().entrySet().stream() - .flatMap(instanceEntry -> instanceEntry.getValue().stream()) - .collect(Collectors.toSet()); + Set serviceInstances = new HashSet<>(); + for (Entry> xdsLocalitySetEntry : clusterLoadAssigment.getLocalityInstances() + .entrySet()) { + serviceInstances.addAll(xdsLocalitySetEntry.getValue()); + } + return serviceInstances; } private boolean isPathMatched(XdsPathMatcher matcher, String path) { @@ -195,8 +216,12 @@ private boolean isPathMatched(XdsPathMatcher matcher, String path) { } private boolean isHeadersMatched(List matchers, Map headers) { - return matchers.stream() - .allMatch(xdsHeaderMatcher -> xdsHeaderMatcher.isMatch(headers)); + for (XdsHeaderMatcher matcher : matchers) { + if (!matcher.isMatch(headers)) { + return false; + } + } + return true; } private String selectClusterByWeight(XdsWeightedClusters weightedClusters) { diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/xds/lb/XdsLoadBalancerFactory.java b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/xds/lb/XdsLoadBalancerFactory.java index 26f3de7d95..bb28932305 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/xds/lb/XdsLoadBalancerFactory.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/xds/lb/XdsLoadBalancerFactory.java @@ -75,15 +75,16 @@ private static XdsLoadBalancer getRandomLoadBalancer() { /** * getLoadBalancer * + * @param serviceName service name * @param clusterName cluster name * @return XdsLoadBalancer */ - public static XdsLoadBalancer getLoadBalancer(String clusterName) { + public static XdsLoadBalancer getLoadBalancer(String serviceName, String clusterName) { if (loadBalanceService == null) { LOGGER.severe("xDS service not open for xDS routing."); return getRoundRobinLoadBalancer(clusterName); } - XdsLbPolicy lbPolicy = loadBalanceService.getLbPolicyOfCluster(clusterName); + XdsLbPolicy lbPolicy = loadBalanceService.getLbPolicyOfCluster(serviceName, clusterName); switch (lbPolicy) { case RANDOM: return getRandomLoadBalancer(); diff --git a/sermant-plugins/sermant-router/router-common/src/test/java/io/sermant/router/common/utils/XdsRouterUtilTest.java b/sermant-plugins/sermant-router/router-common/src/test/java/io/sermant/router/common/utils/XdsRouterUtilTest.java index df7fbef0a1..ee0df602b7 100644 --- a/sermant-plugins/sermant-router/router-common/src/test/java/io/sermant/router/common/utils/XdsRouterUtilTest.java +++ b/sermant-plugins/sermant-router/router-common/src/test/java/io/sermant/router/common/utils/XdsRouterUtilTest.java @@ -89,6 +89,7 @@ public void testGetLocalityInfoOfSelfService() { // find matched service instance meta.setService("serviceA"); + XdsRouterUtils.updateLocalityObtainedFlag(false); localityInfo = XdsRouterUtils.getLocalityInfoOfSelfService(); Assert.assertTrue(localityInfo.isPresent()); Assert.assertEquals("127.0.0.1", localityInfo.get().getRegion()); diff --git a/sermant-plugins/sermant-router/router-common/src/test/java/io/sermant/router/common/xds/XdsRouterHandlerTest.java b/sermant-plugins/sermant-router/router-common/src/test/java/io/sermant/router/common/xds/XdsRouterHandlerTest.java index 57b70f9d7f..7045e0290f 100644 --- a/sermant-plugins/sermant-router/router-common/src/test/java/io/sermant/router/common/xds/XdsRouterHandlerTest.java +++ b/sermant-plugins/sermant-router/router-common/src/test/java/io/sermant/router/common/xds/XdsRouterHandlerTest.java @@ -57,6 +57,8 @@ public class XdsRouterHandlerTest { private static final String CLUSTER_NAME = "outbound|8080||serviceA.default.svc.cluster.local"; + private static final String SERVICE_NAME = "serviceA"; + private static MockedStatic serviceManager; private static MockedStatic xdsRouterUtil; @@ -72,7 +74,7 @@ public static void setUp() { XdsCoreService xdsCoreService = Mockito.mock(XdsCoreService.class); Mockito.when(xdsCoreService.getXdsRouteService()).thenReturn(routeService); Mockito.when(xdsCoreService.getXdsServiceDiscovery()).thenReturn(serviceDiscovery); - Mockito.when(routeService.isLocalityRoute(CLUSTER_NAME)).thenReturn(true); + Mockito.when(routeService.isLocalityRoute(SERVICE_NAME, CLUSTER_NAME)).thenReturn(true); Mockito.when(routeService.getServiceRoute("serviceA")).thenReturn(createXdsRoute()); serviceManager = Mockito.mockStatic(ServiceManager.class); @@ -84,7 +86,7 @@ public static void setUp() { Mockito.when(XdsRouterUtils.getLocalityInfoOfSelfService()).thenReturn(Optional.of(locality)); Mockito.when(serviceDiscovery.getServiceInstance("serviceA")).thenReturn(createServiceInstance4Service()); - Mockito.when(serviceDiscovery.getClusterServiceInstance(CLUSTER_NAME)) + Mockito.when(serviceDiscovery.getClusterServiceInstance(SERVICE_NAME, CLUSTER_NAME)) .thenReturn(Optional.of(createXdsClusterInstance(CLUSTER_NAME, Arrays.asList("test-region-1", "test-region-2")))); diff --git a/sermant-plugins/sermant-router/router-common/src/test/java/io/sermant/router/common/xds/lb/XdsLoadBalancerFactoryTest.java b/sermant-plugins/sermant-router/router-common/src/test/java/io/sermant/router/common/xds/lb/XdsLoadBalancerFactoryTest.java index d0ccae388f..4a4c629b90 100644 --- a/sermant-plugins/sermant-router/router-common/src/test/java/io/sermant/router/common/xds/lb/XdsLoadBalancerFactoryTest.java +++ b/sermant-plugins/sermant-router/router-common/src/test/java/io/sermant/router/common/xds/lb/XdsLoadBalancerFactoryTest.java @@ -21,10 +21,8 @@ import io.sermant.core.service.xds.XdsLoadBalanceService; import io.sermant.core.service.xds.entity.XdsLbPolicy; -import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; -import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.mockito.MockedStatic; @@ -59,21 +57,23 @@ public static void tearDown() { @Test public void testGetLoadBalancer() { // random - Mockito.when(loadBalanceService.getLbPolicyOfCluster("outbound|8080||serviceA.default.svc.cluster.local")) + Mockito.when(loadBalanceService.getLbPolicyOfCluster("serviceA", + "outbound|8080||serviceA.default.svc.cluster.local")) .thenReturn(XdsLbPolicy.RANDOM); XdsLoadBalancer loadBalancer = XdsLoadBalancerFactory - .getLoadBalancer("outbound|8080||serviceA.default.svc.cluster.local"); + .getLoadBalancer("serviceA", "outbound|8080||serviceA.default.svc.cluster.local"); Assert.assertEquals("io.sermant.router.common.xds.lb.XdsRandomLoadBalancer", loadBalancer.getClass().getCanonicalName()); // round robin - Mockito.when(loadBalanceService.getLbPolicyOfCluster("outbound|8080||serviceB.default.svc.cluster.local")) + Mockito.when(loadBalanceService.getLbPolicyOfCluster("serviceB", + "outbound|8080||serviceB.default.svc.cluster.local")) .thenReturn(XdsLbPolicy.ROUND_ROBIN); loadBalancer = XdsLoadBalancerFactory - .getLoadBalancer("outbound|8080||serviceB.default.svc.cluster.local"); + .getLoadBalancer("serviceB", "outbound|8080||serviceB.default.svc.cluster.local"); Assert.assertEquals("io.sermant.router.common.xds.lb.XdsRoundRobinLoadBalancer", loadBalancer.getClass().getCanonicalName()); Assert.assertEquals(loadBalancer, XdsLoadBalancerFactory - .getLoadBalancer("outbound|8080||serviceB.default.svc.cluster.local")); + .getLoadBalancer("serviceB", "outbound|8080||serviceB.default.svc.cluster.local")); } } \ No newline at end of file diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpAsyncClient4xInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpAsyncClient4xInterceptor.java index 2a23590146..8aef1da923 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpAsyncClient4xInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpAsyncClient4xInterceptor.java @@ -57,9 +57,9 @@ public class HttpAsyncClient4xInterceptor extends MarkInterceptor { private static final Logger LOGGER = LoggerFactory.getLogger(); - private static final int HTTPCONTEXT_INDEX = 2; + private static final int HTTP_CONTEXT_INDEX = 2; - private RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); /** * Pre trigger point @@ -77,9 +77,11 @@ public ExecuteContext doBefore(ExecuteContext context) throws Exception { } HttpAsyncRequestProducer httpAsyncRequestProducer = (HttpAsyncRequestProducer) httpAsyncRequestProducerArgument; - HttpRequest httpRequest = httpAsyncRequestProducer.generateRequest(); - handleXdsRouterAndUpdateHttpRequest(httpRequest, context); - Object argument = context.getArguments()[HTTPCONTEXT_INDEX]; + HttpRequestBase httpRequest = (HttpRequestBase) httpAsyncRequestProducer.generateRequest(); + if (handleXdsRouterAndUpdateHttpRequest(httpRequest, context)) { + return context; + } + Object argument = context.getArguments()[HTTP_CONTEXT_INDEX]; if (!(argument instanceof HttpContext)) { return context; } @@ -95,7 +97,7 @@ private void parseTags(HttpContext httpContext, HttpRequest httpRequest) { Object attribute = httpContext.getAttribute(FlowContextUtils.getTagName()); if (attribute != null) { Map> map = FlowContextUtils.decodeTags(String.valueOf(attribute)); - if (map != null && map.size() > 0) { + if (map != null && !map.isEmpty()) { ThreadLocalUtils.setRequestData(new RequestData( map, httpRequest.getRequestLine().getUri(), httpRequest.getRequestLine().getMethod())); } @@ -133,29 +135,31 @@ private Map getHeaders(HttpRequest httpRequest) { return headerMap; } - private void handleXdsRouterAndUpdateHttpRequest(HttpRequest httpRequest, ExecuteContext context) { + private boolean handleXdsRouterAndUpdateHttpRequest(HttpRequestBase httpRequest, ExecuteContext context) { if (!routerConfig.isEnabledXdsRoute()) { - return; + return false; } - URI uri = URI.create(httpRequest.getRequestLine().getUri()); + URI uri = httpRequest.getURI(); String host = uri.getHost(); - if (!BaseHttpRouterUtils.isXdsRouteRequired(host)) { - return; + String serviceName = host.split(RouterConstant.ESCAPED_POINT)[0]; + if (!BaseHttpRouterUtils.isXdsRouteRequired(serviceName)) { + return false; } // use xds route to find a service instance, and modify url by it Optional serviceInstanceOptional = BaseHttpRouterUtils - .chooseServiceInstanceByXds(host.split(RouterConstant.ESCAPED_POINT)[0], uri.getPath(), - getHeaders(httpRequest)); + .chooseServiceInstanceByXds(serviceName, uri.getPath(), getHeaders(httpRequest)); if (!serviceInstanceOptional.isPresent()) { - return; + return false; } ServiceInstance instance = serviceInstanceOptional.get(); try { context.getArguments()[0] = rebuildProducer(context, new URI(BaseHttpRouterUtils.rebuildUrlByXdsServiceInstance(uri, instance))); + return true; } catch (URISyntaxException e) { LOGGER.log(Level.WARNING, "Create uri using xds service instance failed.", e.getMessage()); + return false; } } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpClient4xInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpClient4xInterceptor.java index 9fd717d474..a0949cd601 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpClient4xInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpClient4xInterceptor.java @@ -52,28 +52,28 @@ public class HttpClient4xInterceptor extends MarkInterceptor { private static final Logger LOGGER = LoggerFactory.getLogger(); - private RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); /** * Pre-trigger point * * @param context Execution context * @return Execution context - * @throws Exception Execution exception */ @Override - public ExecuteContext doBefore(ExecuteContext context) throws Exception { + public ExecuteContext doBefore(ExecuteContext context) { LogUtils.printHttpRequestBeforePoint(context); Object[] arguments = context.getArguments(); + if (handleXdsRouterAndUpdateHttpRequest(arguments)) { + return context; + } + Object httpRequestObject = arguments[1]; if (!(httpRequestObject instanceof HttpRequestBase)) { return context; } final HttpRequestBase httpRequest = (HttpRequestBase) httpRequestObject; - - handleXdsRouterAndUpdateHttpRequest(arguments); - if (StringUtils.isBlank(FlowContextUtils.getTagName())) { return context; } @@ -124,30 +124,32 @@ private Map getHeaders(HttpRequestBase httpRequest) { return headerMap; } - private void handleXdsRouterAndUpdateHttpRequest(Object[] arguments) { + private boolean handleXdsRouterAndUpdateHttpRequest(Object[] arguments) { if (!routerConfig.isEnabledXdsRoute()) { - return; + return false; } HttpRequestBase httpRequest = (HttpRequestBase) arguments[1]; URI uri = httpRequest.getURI(); String host = uri.getHost(); - if (!BaseHttpRouterUtils.isXdsRouteRequired(host)) { - return; + String serviceName = host.split(RouterConstant.ESCAPED_POINT)[0]; + if (!BaseHttpRouterUtils.isXdsRouteRequired(serviceName)) { + return false; } // use xds route to find a service instance, and modify url by it Optional serviceInstanceOptional = BaseHttpRouterUtils - .chooseServiceInstanceByXds(host.split(RouterConstant.ESCAPED_POINT)[0], uri.getPath(), - getHeaders(httpRequest)); + .chooseServiceInstanceByXds(serviceName, uri.getPath(), getHeaders(httpRequest)); if (!serviceInstanceOptional.isPresent()) { - return; + return false; } ServiceInstance instance = serviceInstanceOptional.get(); try { httpRequest.setURI(new URI(BaseHttpRouterUtils.rebuildUrlByXdsServiceInstance(uri, instance))); arguments[0] = new HttpHost(instance.getHost(), instance.getPort()); + return true; } catch (URISyntaxException e) { LOGGER.log(Level.WARNING, "Create uri using xds service instance failed.", e.getMessage()); + return false; } } } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpUrlConnectionConnectInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpUrlConnectionConnectInterceptor.java index 6cd7decb9f..1408ea8432 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpUrlConnectionConnectInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/HttpUrlConnectionConnectInterceptor.java @@ -50,7 +50,7 @@ public class HttpUrlConnectionConnectInterceptor extends AbstractInterceptor { private static final Logger LOGGER = LoggerFactory.getLogger(); - private RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); @Override public ExecuteContext before(ExecuteContext context) { @@ -59,10 +59,11 @@ public ExecuteContext before(ExecuteContext context) { return context; } HttpURLConnection connection = (HttpURLConnection) context.getObject(); - Map> headers = connection.getRequestProperties(); - - handleXdsRouterAndUpdateHttpRequest(connection); + if (handleXdsRouterAndUpdateHttpRequest(connection)) { + return context; + } + Map> headers = connection.getRequestProperties(); String method = connection.getRequestMethod(); if (StringUtils.isBlank(FlowContextUtils.getTagName()) || CollectionUtils .isEmpty(headers.get(FlowContextUtils.getTagName()))) { @@ -101,30 +102,32 @@ public ExecuteContext onThrow(ExecuteContext context) throws Exception { return super.onThrow(context); } - private void handleXdsRouterAndUpdateHttpRequest(HttpURLConnection connection) { + private boolean handleXdsRouterAndUpdateHttpRequest(HttpURLConnection connection) { if (!routerConfig.isEnabledXdsRoute()) { - return; + return false; } Map> headers = connection.getRequestProperties(); URL url = connection.getURL(); String host = url.getHost(); - if (!BaseHttpRouterUtils.isXdsRouteRequired(host)) { - return; + String serviceName = host.split(RouterConstant.ESCAPED_POINT)[0]; + if (!BaseHttpRouterUtils.isXdsRouteRequired(serviceName)) { + return false; } // use xds route to find a service instance, and modify url by it Optional serviceInstanceOptional = BaseHttpRouterUtils - .chooseServiceInstanceByXds(host.split(RouterConstant.ESCAPED_POINT)[0], url.getPath(), - BaseHttpRouterUtils.processHeaders(headers)); + .chooseServiceInstanceByXds(serviceName, url.getPath(), BaseHttpRouterUtils.processHeaders(headers)); if (!serviceInstanceOptional.isPresent()) { - return; + return false; } ServiceInstance instance = serviceInstanceOptional.get(); try { ReflectUtils.setFieldValue(connection, "url", - new URL(BaseHttpRouterUtils.rebuildUrlByXdsServiceInstance(url, instance))); + new URL(url.getProtocol(), instance.getHost(), instance.getPort(), url.getFile())); + return true; } catch (MalformedURLException e) { LOGGER.log(Level.WARNING, "Create url using xds service instance failed.", e.getMessage()); + return false; } } } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/LoadBalancerInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/LoadBalancerInterceptor.java index 0342c827db..73607cab87 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/LoadBalancerInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/LoadBalancerInterceptor.java @@ -63,11 +63,11 @@ public ExecuteContext before(ExecuteContext context) { return context; } Object[] arguments = context.getArguments(); - List instances = (List) arguments[0]; - if (CollectionUtils.isEmpty(instances)) { + if (handleXdsRouterAndUpdateServiceInstance(serviceId, arguments)) { return context; } - if (handleXdsRouterAndUpdateServiceInstance(serviceId, arguments)) { + List instances = (List) arguments[0]; + if (CollectionUtils.isEmpty(instances)) { return context; } List targetInstances = loadBalancerService diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttp3ClientInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttp3ClientInterceptor.java index c85ae717e0..511b4e2647 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttp3ClientInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttp3ClientInterceptor.java @@ -47,28 +47,28 @@ public class OkHttp3ClientInterceptor extends MarkInterceptor { private static final String FIELD_NAME = "originalRequest"; - private RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); + private final RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class); /** * Pre-trigger point * * @param context Execution context * @return Execution context - * @throws Exception Execution exception */ @Override - public ExecuteContext doBefore(ExecuteContext context) throws Exception { + public ExecuteContext doBefore(ExecuteContext context) { LogUtils.printHttpRequestBeforePoint(context); final Optional rawRequest = getRequest(context); if (!rawRequest.isPresent()) { return context; } Request request = rawRequest.get(); + if (handleXdsRouterAndUpdateHttpRequest(context.getObject(), request)) { + return context; + } + URI uri = request.url().uri(); Headers headers = request.headers(); - - handleXdsRouterAndUpdateHttpRequest(context.getObject(), request); - if (StringUtils.isBlank(FlowContextUtils.getTagName())) { return context; } @@ -118,32 +118,35 @@ private Map getHeaders(Headers headers) { } private Request rebuildRequest(Request request, ServiceInstance serviceInstance) { + HttpUrl url = request.url().newBuilder() + .host(serviceInstance.getHost()) + .port(serviceInstance.getPort()) + .build(); return request.newBuilder() - .url(HttpUrl - .parse(BaseHttpRouterUtils - .rebuildUrlByXdsServiceInstance(request.url().uri(), serviceInstance))) + .url(url) .build(); } - private void handleXdsRouterAndUpdateHttpRequest(Object obj, Request request) { + private boolean handleXdsRouterAndUpdateHttpRequest(Object obj, Request request) { if (!routerConfig.isEnabledXdsRoute()) { - return; + return false; } - Headers headers = request.headers(); - URI uri = request.url().uri(); - String host = uri.getHost(); - if (!BaseHttpRouterUtils.isXdsRouteRequired(host)) { - return; + HttpUrl url = request.url(); + String host = url.host(); + String serviceName = host.split(RouterConstant.ESCAPED_POINT)[0]; + if (!BaseHttpRouterUtils.isXdsRouteRequired(serviceName)) { + return false; } // use xds route to find a service instance, and modify url by it Optional serviceInstanceOptional = BaseHttpRouterUtils - .chooseServiceInstanceByXds(host.split(RouterConstant.ESCAPED_POINT)[0], uri.getPath(), - getHeaders(headers)); + .chooseServiceInstanceByXds(serviceName, url.encodedPath(), + getHeaders(request.headers())); if (!serviceInstanceOptional.isPresent()) { - return; + return false; } ServiceInstance instance = serviceInstanceOptional.get(); ReflectUtils.setFieldValue(obj, "originalRequest", rebuildRequest(request, instance)); + return true; } } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttpClientInterceptorChainInterceptor.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttpClientInterceptorChainInterceptor.java index b095e28f51..ebed41e79b 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttpClientInterceptorChainInterceptor.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/interceptor/OkHttpClientInterceptorChainInterceptor.java @@ -29,7 +29,6 @@ import io.sermant.router.spring.utils.BaseHttpRouterUtils; import java.io.IOException; -import java.net.URI; import java.net.URL; import java.util.HashMap; import java.util.Map; @@ -88,44 +87,39 @@ private Map getHeaders(Request request) { return headerMap; } - private Request rebuildRequest(Request request, URI uri, ServiceInstance serviceInstance) { - URL url = null; + private Request rebuildRequest(Request request, URL url, ServiceInstance instance) { + URL newUrl = null; try { - url = new URL(BaseHttpRouterUtils.rebuildUrlByXdsServiceInstance(uri, serviceInstance)); + newUrl = new URL(url.getProtocol(), instance.getHost(), instance.getPort(), url.getFile()); } catch (IOException e) { LOGGER.log(Level.WARNING, "Convert url string to url failed.", e.getMessage()); return request; } return request.newBuilder() - .url(url) + .url(newUrl) .build(); } - private void handleXdsRouterAndUpdateHttpRequest(Object[] arguments) { + private boolean handleXdsRouterAndUpdateHttpRequest(Object[] arguments) { if (!routerConfig.isEnabledXdsRoute()) { - return; + return false; } Request request = (Request) arguments[0]; - URI uri = null; - try { - uri = request.uri(); - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Get uri from okhttp request failed.", e.getMessage()); - return; - } - String host = uri.getHost(); - if (!BaseHttpRouterUtils.isXdsRouteRequired(host)) { - return; + URL url = request.url(); + String host = url.getHost(); + String serviceName = host.split(RouterConstant.ESCAPED_POINT)[0]; + if (!BaseHttpRouterUtils.isXdsRouteRequired(serviceName)) { + return false; } // use xds route to find a service instance, and modify url by it Optional serviceInstanceOptional = BaseHttpRouterUtils - .chooseServiceInstanceByXds(host.split(RouterConstant.ESCAPED_POINT)[0], uri.getPath(), - getHeaders(request)); + .chooseServiceInstanceByXds(serviceName, url.getPath(), getHeaders(request)); if (!serviceInstanceOptional.isPresent()) { - return; + return false; } ServiceInstance instance = serviceInstanceOptional.get(); - arguments[0] = rebuildRequest(request, uri, instance); + arguments[0] = rebuildRequest(request, url, instance); + return true; } } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/BaseHttpRouterUtils.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/BaseHttpRouterUtils.java index bef8188451..8f8f0dbb19 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/BaseHttpRouterUtils.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/BaseHttpRouterUtils.java @@ -16,7 +16,6 @@ package io.sermant.router.spring.utils; -import io.sermant.core.common.LoggerFactory; import io.sermant.core.service.xds.entity.ServiceInstance; import io.sermant.core.utils.CollectionUtils; import io.sermant.core.utils.StringUtils; @@ -25,18 +24,13 @@ import io.sermant.router.common.xds.lb.XdsLoadBalancerFactory; import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Pattern; -import java.util.stream.Collectors; /** * BaseHttpUtils @@ -45,31 +39,11 @@ * @since 2024-09-09 **/ public class BaseHttpRouterUtils { - private static final Logger LOGGER = LoggerFactory.getLogger(); - - private static final Pattern IP_PATTERN = Pattern.compile("^([0-9]{1,3}\\.){3}[0-9]{1,3}$"); - private static final String LOCAL_HOST = "localhost"; private BaseHttpRouterUtils() { } - /** - * rebuild new url by XdsServiceInstance - * - * @param oldUrl old url - * @param serviceInstance xds service instance - * @return new url - */ - public static String rebuildUrlByXdsServiceInstance(URL oldUrl, ServiceInstance serviceInstance) { - try { - return rebuildUrlByXdsServiceInstance(oldUrl.toURI(), serviceInstance); - } catch (URISyntaxException e) { - LOGGER.log(Level.WARNING, "Convert url to uri failed.", e.getMessage()); - return StringUtils.EMPTY; - } - } - /** * rebuild new url by XdsServiceInstance * @@ -110,24 +84,29 @@ public static Optional chooseServiceInstanceByXds(String servic } List serviceInstanceList = new ArrayList<>(serviceInstanceByXdsRoute); XdsLoadBalancer loadBalancer = XdsLoadBalancerFactory - .getLoadBalancer(serviceInstanceList.get(0).getClusterName()); + .getLoadBalancer(serviceName, serviceInstanceList.get(0).getClusterName()); return Optional.of(loadBalancer.selectInstance(serviceInstanceList)); } /** * isXdsRouteRequired * - * @param host host + * @param serviceName serviceName * @return isXdsRouteRequired */ - public static boolean isXdsRouteRequired(String host) { - // if host is ip, so no xds routing required - if (StringUtils.isEmpty(host) || host.equals(LOCAL_HOST) || IP_PATTERN.matcher(host).matches()) { + public static boolean isXdsRouteRequired(String serviceName) { + // if service is localhost or started not with lowercase, so no xds routing required + if (StringUtils.isEmpty(serviceName) || serviceName.equals(LOCAL_HOST) + || !isStartWithLowercase(serviceName)) { return false; } return true; } + private static boolean isStartWithLowercase(String serviceName) { + return Character.isLowerCase(serviceName.charAt(0)); + } + /** * process headers, just get first value for every header * @@ -135,10 +114,11 @@ public static boolean isXdsRouteRequired(String host) { * @return processed headers */ public static Map processHeaders(Map> headers) { - return headers.entrySet().stream() - .collect(Collectors.toMap( - Entry::getKey, - entry -> CollectionUtils.isEmpty(entry.getValue()) ? "" : entry.getValue().get(0) - )); + Map processedHeaders = new HashMap<>(); + for (Entry> headerEntry : headers.entrySet()) { + processedHeaders.put(headerEntry.getKey(), + CollectionUtils.isEmpty(headerEntry.getValue()) ? null : headerEntry.getValue().get(0)); + } + return processedHeaders; } } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/SpringRouterUtils.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/SpringRouterUtils.java index 6bdb125434..b27638bb5d 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/SpringRouterUtils.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/utils/SpringRouterUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (C) 2022-2024 Huawei Technologies Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,11 +28,11 @@ import org.springframework.cloud.client.DefaultServiceInstance; +import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; /** * Reflection tool class @@ -58,9 +58,11 @@ private SpringRouterUtils() { */ public static List getSpringCloudServiceInstanceByXds( Set xdsServiceInstances) { - return xdsServiceInstances.stream() - .map(SpringRouterUtils::convertServiceInstance) - .collect(Collectors.toList()); + List serviceInstances = new ArrayList<>(); + for (ServiceInstance xdsServiceInstance : xdsServiceInstances) { + serviceInstances.add(convertServiceInstance(xdsServiceInstance)); + } + return serviceInstances; } /** @@ -69,11 +71,12 @@ public static List getSpringCl * @param xdsServiceInstances * @return spring cloud service instance */ - public static List getSpringCloudServerByXds( - Set xdsServiceInstances) { - return xdsServiceInstances.stream() - .map(SpringRouterUtils::convertServiceInstance2Server) - .collect(Collectors.toList()); + public static List getSpringCloudServerByXds(Set xdsServiceInstances) { + List servers = new ArrayList<>(); + for (ServiceInstance xdsServiceInstance : xdsServiceInstances) { + servers.add(convertServiceInstance2Server(xdsServiceInstance)); + } + return servers; } /** diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/OkHttpClientInterceptorChainInterceptorTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/OkHttpClientInterceptorChainInterceptorTest.java index 9448922f68..eec71f442a 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/OkHttpClientInterceptorChainInterceptorTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/interceptor/OkHttpClientInterceptorChainInterceptorTest.java @@ -77,16 +77,19 @@ public void testBefore() throws Exception { .header("Header1", "Value1") .build(); ExecuteContext context = ExecuteContext.forMemberMethod(obj, null, arguments, null, null); + mockedUtils + .when(() -> BaseHttpRouterUtils.isXdsRouteRequired("example")).thenCallRealMethod(); // service instance is null + mockedUtils + .when(() -> BaseHttpRouterUtils.chooseServiceInstanceByXds(Mockito.any(), Mockito.any(), Mockito.any())) + .thenReturn(Optional.ofNullable(null)); ExecuteContext result = interceptor.before(context); Request newRequest = (Request) result.getArguments()[0]; Assert.assertNotNull(newRequest); HttpUrl newUrl = newRequest.httpUrl(); Assert.assertEquals("http://example.default.svc.cluster.local/test", newUrl.toString()); - mockedUtils - .when(() -> BaseHttpRouterUtils.chooseServiceInstanceByXds(Mockito.any(), Mockito.any(), Mockito.any())) - .thenReturn(Optional.ofNullable(null)); + // service instance is not empty TestServiceInstance serviceInstance = new TestServiceInstance(); diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/utils/BaseHttpRouterUtilsTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/utils/BaseHttpRouterUtilsTest.java index bf5c2e392e..18c36b3c3e 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/utils/BaseHttpRouterUtilsTest.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/utils/BaseHttpRouterUtilsTest.java @@ -27,11 +27,8 @@ import io.sermant.core.service.xds.entity.XdsPathMatcher; import io.sermant.core.service.xds.entity.XdsRoute; import io.sermant.core.service.xds.entity.XdsRouteAction; -import io.sermant.core.service.xds.entity.XdsRouteAction.XdsClusterWeight; -import io.sermant.core.service.xds.entity.XdsRouteAction.XdsWeightedClusters; import io.sermant.core.service.xds.entity.XdsRouteMatch; import io.sermant.core.service.xds.entity.match.ExactMatchStrategy; -import io.sermant.router.common.xds.XdsRouterHandler; import io.sermant.router.common.xds.lb.XdsLoadBalancer; import io.sermant.router.common.xds.lb.XdsLoadBalancerFactory; import io.sermant.router.common.xds.lb.XdsRoundRobinLoadBalancer; @@ -47,7 +44,6 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -67,8 +63,12 @@ public class BaseHttpRouterUtilsTest { private static final String CLUSTER_NAME = "outbound|8080||serviceA.default.svc.cluster.local"; + private static final String SERVICE_NAME = "serviceA"; + private static MockedStatic serviceManager; + private static MockedStatic xdsLoadBalancerFactory; + private static XdsServiceDiscovery serviceDiscovery; @BeforeClass @@ -85,11 +85,13 @@ public static void setUp() { Mockito.when(xdsCoreService.getXdsServiceDiscovery()).thenReturn(serviceDiscovery); serviceManager = Mockito.mockStatic(ServiceManager.class); Mockito.when(ServiceManager.getService(XdsCoreService.class)).thenReturn(xdsCoreService); + xdsLoadBalancerFactory = Mockito.mockStatic(XdsLoadBalancerFactory.class); } @AfterClass public static void tearDown() { serviceManager.close(); + xdsLoadBalancerFactory.close(); } @Test @@ -99,20 +101,6 @@ public void testRebuildUrlByXdsServiceInstance() throws MalformedURLException, U testServiceInstance.setHost("127.0.0.1"); testServiceInstance.setPort(8080); - // use URL with query - URL oldUrl = new URL("http://example.com/test?param=value"); - Assert.assertEquals("http://127.0.0.1:8080/test?param=value", - BaseHttpRouterUtils.rebuildUrlByXdsServiceInstance(oldUrl, testServiceInstance)); - - // use URL without query - oldUrl = new URL("http://example.com/test"); - Assert.assertEquals("http://127.0.0.1:8080/test", - BaseHttpRouterUtils.rebuildUrlByXdsServiceInstance(oldUrl, testServiceInstance)); - - // use invalid URL - URL invalidOldUrl = new URL("http://invalid url"); - Assert.assertEquals("", BaseHttpRouterUtils.rebuildUrlByXdsServiceInstance(invalidOldUrl, testServiceInstance)); - // use URI URI oldUri = new URI("http://example.com/test?param=value"); Assert.assertEquals("http://127.0.0.1:8080/test?param=value", @@ -122,14 +110,13 @@ public void testRebuildUrlByXdsServiceInstance() throws MalformedURLException, U @Test public void testChooseServiceInstanceByXds() { XdsLoadBalancer loadBalancer = new XdsRoundRobinLoadBalancer(); - MockedStatic xdsLoadBalancerFactory = Mockito.mockStatic(XdsLoadBalancerFactory.class); - Mockito.when(XdsLoadBalancerFactory.getLoadBalancer(Mockito.any())).thenReturn(loadBalancer); + Mockito.when(XdsLoadBalancerFactory.getLoadBalancer(Mockito.any(), Mockito.any())).thenReturn(loadBalancer); Map headers = new HashMap<>(); headers.put("version", "v1"); // service instance is empty - Mockito.when(serviceDiscovery.getClusterServiceInstance(CLUSTER_NAME)) + Mockito.when(serviceDiscovery.getClusterServiceInstance(SERVICE_NAME, CLUSTER_NAME)) .thenReturn(Optional.of(createXdsClusterInstance(CLUSTER_NAME, new ArrayList<>()))); Optional result = BaseHttpRouterUtils .chooseServiceInstanceByXds("serviceA", "/test", headers); @@ -141,7 +128,7 @@ public void testChooseServiceInstanceByXds() { Assert.assertFalse(result.isPresent()); // route match and service instance is not empty - Mockito.when(serviceDiscovery.getClusterServiceInstance(CLUSTER_NAME)) + Mockito.when(serviceDiscovery.getClusterServiceInstance(SERVICE_NAME, CLUSTER_NAME)) .thenReturn(Optional.of(createXdsClusterInstance(CLUSTER_NAME, Arrays.asList("region-1")))); result = BaseHttpRouterUtils .chooseServiceInstanceByXds("serviceA", "/test", headers); @@ -157,13 +144,10 @@ public void testIsXdsRouteRequired() { // null Assert.assertFalse(BaseHttpRouterUtils.isXdsRouteRequired(null)); - // IPv4 - Assert.assertFalse(BaseHttpRouterUtils.isXdsRouteRequired("192.168.1.1")); - Assert.assertFalse(BaseHttpRouterUtils.isXdsRouteRequired("10.0.0.1")); - Assert.assertFalse(BaseHttpRouterUtils.isXdsRouteRequired("255.255.255.255")); + // start with number + Assert.assertFalse(BaseHttpRouterUtils.isXdsRouteRequired("192")); // host - Assert.assertTrue(BaseHttpRouterUtils.isXdsRouteRequired("example.com")); Assert.assertFalse(BaseHttpRouterUtils.isXdsRouteRequired("localhost")); } @@ -187,7 +171,7 @@ public void testProcessHeaders() { result = BaseHttpRouterUtils.processHeaders(headers); Assert.assertEquals(2, result.size()); Assert.assertEquals("Value1", result.get("Header1")); - Assert.assertEquals("", result.get("Header2")); + Assert.assertNull(result.get("Header2")); // header has null value headers = new HashMap<>(); @@ -197,7 +181,7 @@ public void testProcessHeaders() { result = BaseHttpRouterUtils.processHeaders(headers); Assert.assertEquals(2, result.size()); Assert.assertEquals("Value1", result.get("Header1")); - Assert.assertEquals("", result.get("Header2")); + Assert.assertNull(result.get("Header2")); } private static List createXdsRoute() {