add router actuator endpoint. (#523)

pull/524/head
Haotian Zhang 2 years ago committed by GitHub
parent 452bbdd49b
commit aa53605159
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -18,3 +18,4 @@
- [Fix typo & Code optimization](https://github.com/Tencent/spring-cloud-tencent/pull/512)
- [BeanFactoryUtils returns all beans including beans defined in ancestor bean factories](https://github.com/Tencent/spring-cloud-tencent/pull/517)
- [fix:add spring-cloud-starter-bootstrap dependency for example](https://github.com/Tencent/spring-cloud-tencent/pull/521)
- [Feature: Add router actuate endpoint](https://github.com/Tencent/spring-cloud-tencent/pull/523)

@ -13,7 +13,6 @@
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.config.endpoint;

@ -13,7 +13,6 @@
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.config.endpoint;

@ -39,13 +39,13 @@ import org.springframework.cloud.client.discovery.DiscoveryClient;
* @author shuiqingliu
*/
@Endpoint(id = "polaris-discovery")
public class PolarisDiscoveryEndPoint {
public class PolarisDiscoveryEndpoint {
private final PolarisDiscoveryProperties polarisDiscoveryProperties;
private final DiscoveryClient polarisDiscoveryClient;
private final PolarisDiscoveryHandler polarisDiscoveryHandler;
public PolarisDiscoveryEndPoint(PolarisDiscoveryProperties polarisDiscoveryProperties,
public PolarisDiscoveryEndpoint(PolarisDiscoveryProperties polarisDiscoveryProperties,
DiscoveryClient polarisDiscoveryClient, PolarisDiscoveryHandler polarisDiscoveryHandler) {
this.polarisDiscoveryProperties = polarisDiscoveryProperties;
this.polarisDiscoveryClient = polarisDiscoveryClient;
@ -54,16 +54,16 @@ public class PolarisDiscoveryEndPoint {
@ReadOperation
public Map<String, Object> polarisDiscovery(@Selector String serviceId) {
Map<String, Object> polarisDisConveryInfo = new HashMap<>();
polarisDisConveryInfo.put("PolarisDiscoveryProperties", polarisDiscoveryProperties);
Map<String, Object> polarisDiscoveryInfo = new HashMap<>();
polarisDiscoveryInfo.put("PolarisDiscoveryProperties", polarisDiscoveryProperties);
List<ServiceInstances> serviceInstancesInfoList = new ArrayList<>();
if (StringUtils.isNotEmpty(serviceId)) {
ServiceInstances serviceInstances = getServiceInstances(serviceId);
serviceInstancesInfoList.add(serviceInstances);
polarisDisConveryInfo.put("ServiceInstances", serviceInstancesInfoList);
return polarisDisConveryInfo;
polarisDiscoveryInfo.put("ServiceInstances", serviceInstancesInfoList);
return polarisDiscoveryInfo;
}
for (String service : polarisDiscoveryClient.getServices()) {
@ -71,13 +71,12 @@ public class PolarisDiscoveryEndPoint {
serviceInstancesInfoList.add(serviceInstances);
}
polarisDisConveryInfo.put("ServiceInstances", serviceInstancesInfoList);
return polarisDisConveryInfo;
polarisDiscoveryInfo.put("ServiceInstances", serviceInstancesInfoList);
return polarisDiscoveryInfo;
}
private ServiceInstances getServiceInstances(String serviceId) {
InstancesResponse instancesResponse = polarisDiscoveryHandler.getHealthyInstances(serviceId);
ServiceInstances serviceInstances = instancesResponse.toServiceInstances();
return serviceInstances;
return instancesResponse.toServiceInstances();
}
}

@ -42,8 +42,8 @@ public class PolarisDiscoveryEndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnAvailableEndpoint
public PolarisDiscoveryEndPoint polarisDiscoveryEndPoint(PolarisDiscoveryProperties polarisDiscoveryProperties,
public PolarisDiscoveryEndpoint polarisDiscoveryEndPoint(PolarisDiscoveryProperties polarisDiscoveryProperties,
DiscoveryClient discoveryClient, PolarisDiscoveryHandler polarisDiscoveryHandler) {
return new PolarisDiscoveryEndPoint(polarisDiscoveryProperties, discoveryClient, polarisDiscoveryHandler);
return new PolarisDiscoveryEndpoint(polarisDiscoveryProperties, discoveryClient, polarisDiscoveryHandler);
}
}

@ -14,7 +14,6 @@
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.endpoint;
import java.util.Map;
@ -45,13 +44,13 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author shuiqingliu
*/
public class PolarisDiscoveryEndPointTest {
public class PolarisDiscoveryEndpointTest {
private static NamingServer namingServer;
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
PolarisDiscoveryEndPointTest.PolarisPropertiesConfiguration.class,
PolarisPropertiesConfiguration.class,
PolarisDiscoveryClientConfiguration.class,
PolarisDiscoveryAutoConfiguration.class,
PolarisDiscoveryEndpointAutoConfiguration.class))
@ -76,14 +75,12 @@ public class PolarisDiscoveryEndPointTest {
@Test
public void testPolarisDiscoveryEndpoint() {
this.contextRunner.run(context -> {
PolarisDiscoveryProperties polarisDiscoveryProperties = context
.getBean(PolarisDiscoveryProperties.class);
DiscoveryClient discoveryClient = context
.getBean(PolarisDiscoveryClient.class);
PolarisDiscoveryProperties polarisDiscoveryProperties = context.getBean(PolarisDiscoveryProperties.class);
DiscoveryClient discoveryClient = context.getBean(PolarisDiscoveryClient.class);
PolarisDiscoveryHandler polarisDiscoveryHandler = context.getBean(PolarisDiscoveryHandler.class);
PolarisDiscoveryEndPoint polarisDiscoveryEndPoint = new PolarisDiscoveryEndPoint(polarisDiscoveryProperties, discoveryClient, polarisDiscoveryHandler);
PolarisDiscoveryEndpoint polarisDiscoveryEndpoint = new PolarisDiscoveryEndpoint(polarisDiscoveryProperties, discoveryClient, polarisDiscoveryHandler);
Map<String, Object> mapInfo = polarisDiscoveryEndPoint.polarisDiscovery("java_provider_test");
Map<String, Object> mapInfo = polarisDiscoveryEndpoint.polarisDiscovery("java_provider_test");
assertThat(polarisDiscoveryProperties).isEqualTo(mapInfo.get("PolarisDiscoveryProperties"));
});

@ -24,19 +24,16 @@ import java.util.Map;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.cloud.polaris.ratelimit.config.PolarisRateLimitProperties;
import com.tencent.polaris.client.pb.RateLimitProto;
import com.tencent.polaris.client.pb.RoutingProto;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
/**
@ -59,20 +56,17 @@ public class PolarisRateLimitRuleEndpoint {
}
@ReadOperation
public Map<String, Object> rateLimit(
@Selector String namespace, @Selector String service, @Nullable String dstService) {
public Map<String, Object> rateLimit() {
RateLimitProto.RateLimit rateLimit = serviceRuleManager.getServiceRateLimitRule(MetadataContext.LOCAL_NAMESPACE,
MetadataContext.LOCAL_SERVICE);
Map<String, Object> result = new HashMap<>();
RateLimitProto.RateLimit rateLimit = serviceRuleManager.getServiceRateLimitRule(namespace, service);
result.put("properties", polarisRateLimitProperties);
result.put("namespace", namespace);
result.put("service", service);
result.put("rateLimits", parseRateLimitRule(rateLimit));
result.put("namespace", MetadataContext.LOCAL_NAMESPACE);
result.put("service", MetadataContext.LOCAL_SERVICE);
result.put("rateLimitRules", parseRateLimitRule(rateLimit));
if (StringUtils.isEmpty(dstService)) {
return result;
}
List<RoutingProto.Route> routes = serviceRuleManager.getServiceRouterRule(namespace, service, dstService);
result.put("routes", routes);
return result;
}

@ -97,7 +97,7 @@ public class PolarisRateLimitRuleEndpointTests {
public void testPolarisRateLimit() {
this.contextRunner.run(context -> polarisRateLimitProperties = context.getBean(PolarisRateLimitProperties.class));
PolarisRateLimitRuleEndpoint polarisRateLimitRuleEndpoint = new PolarisRateLimitRuleEndpoint(serviceRuleManager, polarisRateLimitProperties);
Map<String, Object> rateLimit = polarisRateLimitRuleEndpoint.rateLimit("namespaceTest", "TestApp2", "TestApp3");
Map<String, Object> rateLimit = polarisRateLimitRuleEndpoint.rateLimit();
assertThat(polarisRateLimitProperties).isEqualTo(rateLimit.get("properties"));
}

@ -70,6 +70,18 @@
</dependency>
<!-- spring cloud gateway dependencies end -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

@ -0,0 +1,108 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.endpoint;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.MessageOrBuilder;
import com.google.protobuf.util.JsonFormat;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.JacksonUtils;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.polaris.client.pb.RoutingProto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;
import org.springframework.util.CollectionUtils;
/**
* Router actuator endpoint.
*
* @author lepdou 2022-07-25
*/
@Endpoint(id = "polaris-router")
public class PolarisRouterEndpoint {
private static final Logger LOGGER = LoggerFactory.getLogger(PolarisRouterEndpoint.class);
private final ServiceRuleManager serviceRuleManager;
public PolarisRouterEndpoint(ServiceRuleManager serviceRuleManager) {
this.serviceRuleManager = serviceRuleManager;
}
@ReadOperation
public Map<String, Object> router(@Selector String dstService) {
List<RoutingProto.Route> routerRules = serviceRuleManager.getServiceRouterRule(MetadataContext.LOCAL_NAMESPACE,
MetadataContext.LOCAL_SERVICE, dstService);
Map<String, Object> result = new HashMap<>();
List<Object> rules = new LinkedList<>();
result.put("routerRules", rules);
if (CollectionUtils.isEmpty(routerRules)) {
return result;
}
for (RoutingProto.Route route : routerRules) {
rules.add(parseRouterRule(route));
}
return result;
}
private Object parseRouterRule(RoutingProto.Route routeRule) {
Map<String, Object> result = new HashMap<>();
List<RoutingProto.Source> sourcePbs = routeRule.getSourcesList();
List<Object> sources = new LinkedList<>();
for (RoutingProto.Source sourcePb : sourcePbs) {
sources.add(pb2Json(sourcePb));
}
result.put("sources", sources);
List<RoutingProto.Destination> destPbs = routeRule.getDestinationsList();
List<Object> destinations = new LinkedList<>();
for (RoutingProto.Destination destPb : destPbs) {
destinations.add(pb2Json(destPb));
}
result.put("destinations", destinations);
return result;
}
private Object pb2Json(MessageOrBuilder pbObject) {
String jsonStr;
try {
jsonStr = JsonFormat.printer().print(pbObject);
}
catch (InvalidProtocolBufferException e) {
String msg = "parse router rule to json error.";
LOGGER.error(msg, e);
throw new RuntimeException(msg, e);
}
return JacksonUtils.deserialize2Map(jsonStr);
}
}

@ -0,0 +1,46 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.endpoint;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* The AutoConfiguration for polaris router endpoint.
*
* @author lepdou 2022-07-25
**/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Endpoint.class)
@ConditionalOnPolarisEnabled
public class PolarisRouterEndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnAvailableEndpoint
public PolarisRouterEndpoint polarisRouterEndpoint(ServiceRuleManager serviceRuleManager) {
return new PolarisRouterEndpoint(serviceRuleManager);
}
}

@ -1,3 +1,4 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.router.config.RouterAutoConfiguration,\
com.tencent.cloud.polaris.router.config.FeignAutoConfiguration
com.tencent.cloud.polaris.router.config.FeignAutoConfiguration,\
com.tencent.cloud.polaris.router.endpoint.PolarisRouterEndpointAutoConfiguration

@ -0,0 +1,118 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.router.endpoint;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Lists;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
import com.tencent.cloud.polaris.context.ServiceRuleManager;
import com.tencent.polaris.client.pb.ModelProto;
import com.tencent.polaris.client.pb.RoutingProto;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
/**
* Test for {@link PolarisRouterEndpoint}.
*
* @author lepdou 2022-07-25
*/
@RunWith(MockitoJUnitRunner.class)
public class PolarisRouterEndpointTest {
private static final String testDestService = "dstService";
private static MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils;
@Mock
private ServiceRuleManager serviceRuleManager;
@InjectMocks
private PolarisRouterEndpoint polarisRouterEndpoint;
@BeforeClass
public static void beforeClass() {
mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class);
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
.thenReturn(testDestService);
}
@AfterClass
public static void afterClass() {
mockedApplicationContextAwareUtils.close();
}
@Test
public void testHasRouterRule() {
Map<String, ModelProto.MatchString> labels = new HashMap<>();
ModelProto.MatchString matchString = ModelProto.MatchString.getDefaultInstance();
String validKey1 = "${http.header.uid}";
String validKey2 = "${http.query.name}";
String validKey3 = "${http.method}";
String validKey4 = "${http.uri}";
String validKey5 = "${http.body.customkey}";
String invalidKey = "$http.expression.wrong}";
labels.put(validKey1, matchString);
labels.put(validKey2, matchString);
labels.put(validKey3, matchString);
labels.put(validKey4, matchString);
labels.put(validKey5, matchString);
labels.put(invalidKey, matchString);
RoutingProto.Source source1 = RoutingProto.Source.newBuilder().putAllMetadata(labels).build();
RoutingProto.Source source2 = RoutingProto.Source.newBuilder().putAllMetadata(labels).build();
RoutingProto.Source source3 = RoutingProto.Source.newBuilder().putAllMetadata(new HashMap<>()).build();
List<RoutingProto.Route> routes = new LinkedList<>();
RoutingProto.Route route = RoutingProto.Route.newBuilder()
.addAllSources(Lists.newArrayList(source1, source2, source3))
.build();
routes.add(route);
when(serviceRuleManager.getServiceRouterRule(testDestService, testDestService, testDestService)).thenReturn(routes);
Map<String, Object> actuator = polarisRouterEndpoint.router(testDestService);
Assert.assertNotNull(actuator.get("routerRules"));
Assert.assertEquals(1, ((List) actuator.get("routerRules")).size());
}
@Test
public void testHasNotRouterRule() {
List<RoutingProto.Route> routes = new LinkedList<>();
when(serviceRuleManager.getServiceRouterRule(testDestService, testDestService, testDestService)).thenReturn(routes);
Map<String, Object> actuator = polarisRouterEndpoint.router(testDestService);
Assert.assertNotNull(actuator.get("routerRules"));
Assert.assertEquals(0, ((List) actuator.get("routerRules")).size());
}
}

@ -28,11 +28,6 @@
<!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>
<build>
<plugins>

@ -14,3 +14,9 @@ spring:
enabled: true
loadbalancer:
enabled: true
management:
endpoints:
web:
exposure:
include:
- polaris-router

@ -36,7 +36,7 @@
<dependency>
<groupId>org.owasp.esapi</groupId>
<artifactId>esapi</artifactId>
<version>2.1.0.1</version>
<version>2.5.0.0</version>
</dependency>
</dependencies>
</dependencyManagement>

Loading…
Cancel
Save