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 62a246b2a3..43fa8ea0fb 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 b11c240570..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); } + + @Override + public boolean isLocalityRoute(String serviceName, String clusterName) { + return XdsDataCache.isLocalityLb(serviceName, clusterName); + } } diff --git a/sermant-plugins/sermant-router/config/config.yaml b/sermant-plugins/sermant-router/config/config.yaml index f3114ac1d9..73177033dc 100644 --- a/sermant-plugins/sermant-router/config/config.yaml +++ b/sermant-plugins/sermant-router/config/config.yaml @@ -3,6 +3,8 @@ router.plugin: enabled-registry-plugin-adaptation: false # whether to use xds route enabled-xds-route: false + # whether to use xds route for httpclient, httpasyncclient, okhttp, httpurlconnection + enabled-simple-http-route: false # whether to use secure protocol to invoke spring cloud downstream service with xds route, example: http or https enabled-springcloud-xds-route-secure: false # Whether to use request information for routing diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/config/RouterConfig.java b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/config/RouterConfig.java index 7074430330..b0c616c7a3 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/config/RouterConfig.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/config/RouterConfig.java @@ -72,6 +72,12 @@ public class RouterConfig implements PluginConfig { @ConfigFieldKey("enabled-xds-route") private boolean enabledXdsRoute; + /** + * whether to use xds route for httpclient, httpasyncclient, okhttp, httpurlconnection + */ + @ConfigFieldKey("enabled-simple-http-route") + private boolean enabledSimpleHttpRoute; + /** * whether to use secure protocol to invoke downstream service with xds route, example: http or https */ @@ -224,6 +230,14 @@ public void setEnabledXdsRoute(boolean enabledXdsRoute) { this.enabledXdsRoute = enabledXdsRoute; } + public boolean isEnabledSimpleHttpRoute() { + return enabledSimpleHttpRoute; + } + + public void setEnabledSimpleHttpRoute(boolean enabledSimpleHttpRoute) { + this.enabledSimpleHttpRoute = enabledSimpleHttpRoute; + } + public boolean isEnabledSpringCloudXdsRouteSecure() { return enabledSpringCloudXdsRouteSecure; } diff --git a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricsManager.java b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricsManager.java index 3024bed093..1a0029b076 100644 --- a/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricsManager.java +++ b/sermant-plugins/sermant-router/router-common/src/main/java/io/sermant/router/common/metric/MetricsManager.java @@ -57,13 +57,13 @@ public class MetricsManager { static { try { metricService = ServiceManager.getService(MetricService.class); - TAG_KEY_MAP.put("service","service_meta_service"); - TAG_KEY_MAP.put("version","service_meta_version"); - TAG_KEY_MAP.put("application","service_meta_application"); - TAG_KEY_MAP.put("zone","service_meta_zone"); - TAG_KEY_MAP.put("project","service_meta_project"); - TAG_KEY_MAP.put("environment","service_meta_environment"); - TAG_KEY_MAP.put("parameters","service_meta_parameters"); + TAG_KEY_MAP.put("service", "service_meta_service"); + TAG_KEY_MAP.put("version", "service_meta_version"); + TAG_KEY_MAP.put("application", "service_meta_application"); + TAG_KEY_MAP.put("zone", "service_meta_zone"); + TAG_KEY_MAP.put("project", "service_meta_project"); + TAG_KEY_MAP.put("environment", "service_meta_environment"); + TAG_KEY_MAP.put("parameters", "service_meta_parameters"); } catch (IllegalArgumentException e) { LOGGER.log(Level.SEVERE, "Failed to load metrics service", e); } @@ -92,7 +92,7 @@ public static void addOrUpdateCounterMetricValue(String metricName, Map(); } - tagsMap.put(RouterConstant.SCOPE,"service-router"); + tagsMap.put(RouterConstant.SCOPE, "service-router"); Counter counter = COUNT_MAP.computeIfAbsent(new MetricInfo(metricName, tagsMap), metricInfo -> metricService.counter(metricName, Tags.of(tagsMap))); counter.increment(value); @@ -130,6 +130,27 @@ private static void collectRequestCountMetric(String address) { addOrUpdateCounterMetricValue(RouterConstant.ROUTER_REQUEST_COUNT, tagsMap, 1); } + /** + * collect xDS router destination tag count metric + * + * @param cluster cluster name + */ + public static void collectXdsRouterDestinationTagCountMetric(String cluster) { + if (!ROUTER_CONFIG.isEnableMetric()) { + return; + } + Map tagsMap = new HashMap<>(); + MetricsManager.getAllTagKey().forEach(key -> tagsMap.put(key, StringUtils.EMPTY)); + tagsMap.put(RouterConstant.SERVICE_META_PARAMETERS, "cluster: " + cluster); + if (StringUtils.isEmpty(DubboCache.INSTANCE.getAppName())) { + tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, AppCache.INSTANCE.getAppName()); + } else { + tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, DubboCache.INSTANCE.getAppName()); + } + tagsMap.put(RouterConstant.PROTOCOL, RouterConstant.XDS_PROTOCOL); + MetricsManager.addOrUpdateCounterMetricValue(RouterConstant.ROUTER_DESTINATION_TAG_COUNT, tagsMap, 1); + } + /** * Get the key of the metric tag * 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..09cc36ae4b 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 } } + /** + * updateServiceDiscovery + * + * @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 2795aee114..2e3c7491c8 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 @@ -33,16 +33,14 @@ import io.sermant.core.service.xds.entity.XdsRouteMatch; import io.sermant.core.utils.CollectionUtils; import io.sermant.core.utils.StringUtils; -import io.sermant.router.common.cache.AppCache; -import io.sermant.router.common.cache.DubboCache; -import io.sermant.router.common.constants.RouterConstant; import io.sermant.router.common.metric.MetricsManager; import io.sermant.router.common.utils.XdsRouterUtils; import java.util.Collections; -import java.util.HashMap; +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; @@ -153,26 +151,17 @@ private Set handleXdsRoute(XdsRoute route, String serviceName) if (routeAction.isWeighted()) { cluster = selectClusterByWeight(routeAction.getWeightedClusters()); } - Map tagsMap = new HashMap<>(); - MetricsManager.getAllTagKey().forEach(key -> tagsMap.put(key, StringUtils.EMPTY)); - tagsMap.put(RouterConstant.SERVICE_META_PARAMETERS, "cluster: " + cluster); - if (StringUtils.isEmpty(DubboCache.INSTANCE.getAppName())) { - tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, AppCache.INSTANCE.getAppName()); - } else { - tagsMap.put(RouterConstant.CLIENT_SERVICE_NAME, DubboCache.INSTANCE.getAppName()); - } - tagsMap.put(RouterConstant.PROTOCOL, RouterConstant.XDS_PROTOCOL); - MetricsManager.addOrUpdateCounterMetricValue(RouterConstant.ROUTER_DESTINATION_TAG_COUNT, tagsMap, 1); + MetricsManager.collectXdsRouterDestinationTagCountMetric(cluster); // 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; } @@ -194,15 +183,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) { @@ -210,8 +218,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 28118d793c..f575a02774 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 0856d1c8fb..f1e29fffa4 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 @@ -31,6 +31,7 @@ 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.metric.MetricsManager; import io.sermant.router.common.utils.XdsRouterUtils; import org.junit.AfterClass; @@ -57,10 +58,14 @@ 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; + private static MockedStatic metricsManager; + private static XdsLocality locality1; private static XdsLocality locality3; @@ -72,7 +77,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 +89,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")))); @@ -93,12 +98,15 @@ public static void setUp() { locality3 = new XdsLocality(); locality3.setRegion("test-region-3"); + + metricsManager = Mockito.mockStatic(MetricsManager.class); } @AfterClass public static void tearDown() { serviceManager.close(); xdsRouterUtil.close(); + metricsManager.close(); } @Test 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 7d83e88940..0ec8ff3885 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")); } } diff --git a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/declarer/BaseRegistryPluginAdaptationDeclarer.java b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/declarer/BaseRegistryPluginAdaptationDeclarer.java index 230205bca2..bbb6e1bb46 100644 --- a/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/declarer/BaseRegistryPluginAdaptationDeclarer.java +++ b/sermant-plugins/sermant-router/spring-router-plugin/src/main/java/io/sermant/router/spring/declarer/BaseRegistryPluginAdaptationDeclarer.java @@ -38,6 +38,7 @@ public BaseRegistryPluginAdaptationDeclarer() { @Override public boolean isEnabled() { - return routerConfig.isEnabledXdsRoute() || routerConfig.isEnabledRegistryPluginAdaptation(); + return (routerConfig.isEnabledXdsRoute() && routerConfig.isEnabledSimpleHttpRoute()) + || routerConfig.isEnabledRegistryPluginAdaptation(); } } 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 ad138cca70..275cc67d2b 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 @@ -81,8 +81,10 @@ public ExecuteContext doBefore(ExecuteContext context) throws Exception { } HttpAsyncRequestProducer httpAsyncRequestProducer = (HttpAsyncRequestProducer) httpAsyncRequestProducerArgument; - HttpRequest httpRequest = httpAsyncRequestProducer.generateRequest(); - handleXdsRouterAndUpdateHttpRequest(httpRequest, context); + HttpRequestBase httpRequest = (HttpRequestBase) httpAsyncRequestProducer.generateRequest(); + if (handleXdsRouterAndUpdateHttpRequest(httpRequest, context)) { + return context; + } Object argument = context.getArguments()[HTTP_CONTEXT_INDEX]; if (!(argument instanceof HttpContext)) { return context; @@ -157,29 +159,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 0ef3a38ac2..3a2f9ef853 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 @@ -72,8 +72,9 @@ public ExecuteContext doBefore(ExecuteContext context) { return context; } final HttpRequestBase httpRequest = (HttpRequestBase) httpRequestObject; - - handleXdsRouterAndUpdateHttpRequest(arguments); + if (handleXdsRouterAndUpdateHttpRequest(arguments)) { + return context; + } MetricThreadLocal.setFlag(true); if (StringUtils.isBlank(FlowContextUtils.getTagName())) { return context; @@ -139,30 +140,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 0771e0e46a..7d0ca05959 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 @@ -61,9 +61,11 @@ public ExecuteContext before(ExecuteContext context) { return context; } HttpURLConnection connection = (HttpURLConnection) context.getObject(); - Map> headers = connection.getRequestProperties(); + if (handleXdsRouterAndUpdateHttpRequest(connection)) { + return context; + } - handleXdsRouterAndUpdateHttpRequest(connection); + Map> headers = connection.getRequestProperties(); MetricThreadLocal.setFlag(true); String method = connection.getRequestMethod(); if (StringUtils.isBlank(FlowContextUtils.getTagName()) || CollectionUtils @@ -114,30 +116,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 dc675b6314..f134f47f8a 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 088c2b736e..532be184a8 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 @@ -65,10 +65,12 @@ public ExecuteContext doBefore(ExecuteContext context) { 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); MetricThreadLocal.setFlag(true); if (StringUtils.isBlank(FlowContextUtils.getTagName())) { return context; @@ -133,32 +135,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 11b9771fac..6d69e67682 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 @@ -31,7 +31,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; @@ -106,44 +105,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..233a21e92c 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 @@ -25,18 +25,15 @@ 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 @@ -54,22 +51,6 @@ public class BaseHttpRouterUtils { 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 +91,30 @@ 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) + || isNotStartWithLowercase(serviceName)) { return false; } return true; } + private static boolean isNotStartWithLowercase(String serviceName) { + char firstChar = serviceName.charAt(0); + return firstChar < 'a' || firstChar > 'z'; + } + /** * process headers, just get first value for every header * @@ -135,10 +122,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()) ? "" : 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 3f94e082db..f3c9e51813 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 @@ -28,12 +28,12 @@ import org.springframework.cloud.client.DefaultServiceInstance; +import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; /** * Reflection tool class @@ -110,9 +110,11 @@ public static Enumeration getHeaders(Object obj, String key) { */ 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; } /** @@ -121,11 +123,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/utils/BaseHttpRouterUtilsTest.java b/sermant-plugins/sermant-router/spring-router-plugin/src/test/java/io/sermant/router/spring/utils/BaseHttpRouterUtilsTest.java index 3ce3a7000e..1b29066719 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,9 @@ 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.metric.MetricsManager; 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 +45,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 +64,14 @@ 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 metricsManager; + + private static MockedStatic xdsLoadBalancerFactory; + private static XdsServiceDiscovery serviceDiscovery; @BeforeClass @@ -85,11 +88,14 @@ public static void setUp() { Mockito.when(xdsCoreService.getXdsServiceDiscovery()).thenReturn(serviceDiscovery); serviceManager = Mockito.mockStatic(ServiceManager.class); Mockito.when(ServiceManager.getService(XdsCoreService.class)).thenReturn(xdsCoreService); + metricsManager = Mockito.mockStatic(MetricsManager.class); } @AfterClass public static void tearDown() { serviceManager.close(); + metricsManager.close(); + xdsLoadBalancerFactory.close(); } @Test @@ -99,20 +105,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 +114,14 @@ 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); + xdsLoadBalancerFactory = Mockito.mockStatic(XdsLoadBalancerFactory.class); + 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 +133,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 +149,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")); }