feat:support TSF router. (#1368)
parent
51bafa670a
commit
337dd48d1b
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.metadata.provider;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import com.tencent.cloud.common.util.UrlUtils;
|
||||
import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils;
|
||||
import com.tencent.polaris.metadata.core.MessageMetadataContainer;
|
||||
import com.tencent.polaris.metadata.core.MetadataProvider;
|
||||
import com.tencent.polaris.metadata.core.constant.MetadataConstants;
|
||||
import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup;
|
||||
import feign.RequestTemplate;
|
||||
|
||||
/**
|
||||
* MetadataProvider used for Feign RequestTemplate.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class FeignRequestTemplateMetadataProvider implements MetadataProvider {
|
||||
|
||||
private final RequestTemplate requestTemplate;
|
||||
|
||||
public FeignRequestTemplateMetadataProvider(RequestTemplate requestTemplate) {
|
||||
this.requestTemplate = requestTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRawMetadataStringValue(String key) {
|
||||
switch (key) {
|
||||
case MessageMetadataContainer.LABEL_KEY_METHOD:
|
||||
return requestTemplate.method();
|
||||
case MessageMetadataContainer.LABEL_KEY_PATH:
|
||||
URI uri = URI.create(requestTemplate.request().url());
|
||||
return UrlUtils.decode(uri.getPath());
|
||||
case MessageMetadataContainer.LABEL_KEY_CALLER_IP:
|
||||
return CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer()
|
||||
.getRawMetadataStringValue(MetadataConstants.LOCAL_IP);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRawMetadataMapValue(String key, String mapKey) {
|
||||
Map<String, Collection<String>> headers = requestTemplate.headers();
|
||||
switch (key) {
|
||||
case MessageMetadataContainer.LABEL_MAP_KEY_HEADER:
|
||||
return UrlUtils.decode(ExpressionLabelUtils.getFirstValue(headers, mapKey));
|
||||
case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE:
|
||||
return UrlUtils.decode(ExpressionLabelUtils.getCookieFirstValue(headers, mapKey));
|
||||
case MessageMetadataContainer.LABEL_MAP_KEY_QUERY:
|
||||
return UrlUtils.decode(ExpressionLabelUtils.getFirstValue(requestTemplate.queries(), mapKey));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.metadata.provider;
|
||||
|
||||
import com.tencent.cloud.common.util.UrlUtils;
|
||||
import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils;
|
||||
import com.tencent.polaris.metadata.core.MessageMetadataContainer;
|
||||
import com.tencent.polaris.metadata.core.MetadataProvider;
|
||||
import com.tencent.polaris.metadata.core.constant.MetadataConstants;
|
||||
import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup;
|
||||
|
||||
import org.springframework.http.HttpRequest;
|
||||
|
||||
/**
|
||||
* MetadataProvider used for RestTemplate HttpRequest.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class RestTemplateMetadataProvider implements MetadataProvider {
|
||||
|
||||
private final HttpRequest request;
|
||||
|
||||
public RestTemplateMetadataProvider(HttpRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRawMetadataStringValue(String key) {
|
||||
switch (key) {
|
||||
case MessageMetadataContainer.LABEL_KEY_METHOD:
|
||||
return request.getMethod().toString();
|
||||
case MessageMetadataContainer.LABEL_KEY_PATH:
|
||||
return UrlUtils.decode(request.getURI().getPath());
|
||||
case MessageMetadataContainer.LABEL_KEY_CALLER_IP:
|
||||
return CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer()
|
||||
.getRawMetadataStringValue(MetadataConstants.LOCAL_IP);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRawMetadataMapValue(String key, String mapKey) {
|
||||
switch (key) {
|
||||
case MessageMetadataContainer.LABEL_MAP_KEY_HEADER:
|
||||
return UrlUtils.decode(SpringWebExpressionLabelUtils.getHeaderValue(request, mapKey));
|
||||
case MessageMetadataContainer.LABEL_MAP_KEY_COOKIE:
|
||||
return UrlUtils.decode(SpringWebExpressionLabelUtils.getCookieValue(request, mapKey));
|
||||
case MessageMetadataContainer.LABEL_MAP_KEY_QUERY:
|
||||
return UrlUtils.decode(SpringWebExpressionLabelUtils.getQueryValue(request, mapKey));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* 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.tsf.registry;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.tencent.cloud.common.constant.SdkVersion;
|
||||
import com.tencent.cloud.common.util.JacksonUtils;
|
||||
import com.tencent.cloud.polaris.context.tsf.config.TsfCoreProperties;
|
||||
import com.tencent.cloud.polaris.registry.PolarisRegistration;
|
||||
import com.tencent.cloud.polaris.registry.PolarisRegistrationCustomizer;
|
||||
import com.tencent.cloud.polaris.tsf.TsfDiscoveryProperties;
|
||||
import com.tencent.cloud.polaris.tsf.consts.WarmupCons;
|
||||
import com.tencent.cloud.polaris.tsf.util.RegistrationUtil;
|
||||
|
||||
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_APPLICATION_ID;
|
||||
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_GROUP_ID;
|
||||
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_INSTNACE_ID;
|
||||
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_NAMESPACE_ID;
|
||||
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_PROG_VERSION;
|
||||
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_REGION;
|
||||
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_SDK_VERSION;
|
||||
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_TAGS;
|
||||
import static com.tencent.cloud.common.tsf.TsfConstant.TSF_ZONE;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class TsfMetadataPolarisRegistrationCustomizer implements PolarisRegistrationCustomizer {
|
||||
|
||||
private final TsfCoreProperties tsfCoreProperties;
|
||||
|
||||
private final TsfDiscoveryProperties tsfDiscoveryProperties;
|
||||
|
||||
public TsfMetadataPolarisRegistrationCustomizer(TsfCoreProperties tsfCoreProperties, TsfDiscoveryProperties tsfDiscoveryProperties) {
|
||||
this.tsfCoreProperties = tsfCoreProperties;
|
||||
this.tsfDiscoveryProperties = tsfDiscoveryProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(PolarisRegistration registration) {
|
||||
Map<String, String> metadata = registration.getMetadata();
|
||||
|
||||
metadata.put(TSF_APPLICATION_ID, tsfCoreProperties.getTsfApplicationId());
|
||||
metadata.put(TSF_PROG_VERSION, tsfDiscoveryProperties.getTsfProgVersion());
|
||||
metadata.put(TSF_GROUP_ID, tsfCoreProperties.getTsfGroupId());
|
||||
metadata.put(TSF_NAMESPACE_ID, tsfCoreProperties.getTsfNamespaceId());
|
||||
metadata.put(TSF_INSTNACE_ID, tsfDiscoveryProperties.getInstanceId());
|
||||
metadata.put(TSF_REGION, tsfDiscoveryProperties.getTsfRegion());
|
||||
metadata.put(TSF_ZONE, tsfDiscoveryProperties.getTsfZone());
|
||||
// 处理预热相关的参数
|
||||
metadata.put(WarmupCons.TSF_START_TIME, String.valueOf(System.currentTimeMillis()));
|
||||
metadata.put(TSF_SDK_VERSION, SdkVersion.get());
|
||||
metadata.put(TSF_TAGS, JacksonUtils.serialize2Json(RegistrationUtil.createTags(tsfDiscoveryProperties)));
|
||||
RegistrationUtil.appendMetaIpAddress(metadata);
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils;
|
||||
import com.tencent.cloud.polaris.context.ServiceRuleManager;
|
||||
import com.tencent.polaris.specification.api.v1.model.ModelProto;
|
||||
import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Resolve label expressions from routing rules.
|
||||
* @author lepdou 2022-05-19
|
||||
*/
|
||||
public class RouterRuleLabelResolver {
|
||||
|
||||
private final ServiceRuleManager serviceRuleManager;
|
||||
|
||||
public RouterRuleLabelResolver(ServiceRuleManager serviceRuleManager) {
|
||||
this.serviceRuleManager = serviceRuleManager;
|
||||
}
|
||||
|
||||
public Set<String> getExpressionLabelKeys(String namespace, String sourceService, String dstService) {
|
||||
List<RoutingProto.Route> rules = serviceRuleManager.getServiceRouterRule(namespace, sourceService, dstService);
|
||||
|
||||
if (CollectionUtils.isEmpty(rules)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set<String> expressionLabels = new HashSet<>();
|
||||
|
||||
for (RoutingProto.Route rule : rules) {
|
||||
List<RoutingProto.Source> sources = rule.getSourcesList();
|
||||
if (CollectionUtils.isEmpty(sources)) {
|
||||
continue;
|
||||
}
|
||||
for (RoutingProto.Source source : sources) {
|
||||
Map<String, ModelProto.MatchString> labels = source.getMetadataMap();
|
||||
if (CollectionUtils.isEmpty(labels)) {
|
||||
continue;
|
||||
}
|
||||
for (String labelKey : labels.keySet()) {
|
||||
if (ExpressionLabelUtils.isExpressionLabel(labelKey)) {
|
||||
expressionLabels.add(labelKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return expressionLabels;
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 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.beanprocessor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.tencent.cloud.common.metadata.StaticMetadataManager;
|
||||
import com.tencent.cloud.common.util.BeanFactoryUtils;
|
||||
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
|
||||
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
|
||||
import com.tencent.cloud.polaris.router.scg.PolarisReactiveLoadBalancerClientFilter;
|
||||
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties;
|
||||
import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
|
||||
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
||||
|
||||
/**
|
||||
* Replaced ReactiveLoadBalancerClientFilter with PolarisReactiveLoadBalancerClientFilter during creating bean phase.
|
||||
*@author lepdou 2022-06-20
|
||||
*/
|
||||
public class ReactiveLoadBalancerClientFilterBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
|
||||
private BeanFactory factory;
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.factory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
// Support spring cloud gateway router.
|
||||
// Replaces the default ReactiveLoadBalancerClientFilter implementation
|
||||
// and returns a custom PolarisReactiveLoadBalancerClientFilter
|
||||
if (bean instanceof ReactiveLoadBalancerClientFilter) {
|
||||
LoadBalancerClientFactory loadBalancerClientFactory = this.factory.getBean(LoadBalancerClientFactory.class);
|
||||
GatewayLoadBalancerProperties gatewayLoadBalancerProperties = this.factory.getBean(GatewayLoadBalancerProperties.class);
|
||||
List<SpringWebRouterLabelResolver> routerLabelResolvers = BeanFactoryUtils.getBeans(factory, SpringWebRouterLabelResolver.class);
|
||||
StaticMetadataManager staticMetadataManager = this.factory.getBean(StaticMetadataManager.class);
|
||||
RouterRuleLabelResolver routerRuleLabelResolver = this.factory.getBean(RouterRuleLabelResolver.class);
|
||||
PolarisContextProperties polarisContextProperties = this.factory.getBean(PolarisContextProperties.class);
|
||||
|
||||
return new PolarisReactiveLoadBalancerClientFilter(
|
||||
loadBalancerClientFactory, gatewayLoadBalancerProperties,
|
||||
staticMetadataManager, routerRuleLabelResolver, routerLabelResolvers, polarisContextProperties);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
/*
|
||||
* 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.feign;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils;
|
||||
import feign.RequestTemplate;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Resolve rule expression label from feign request.
|
||||
*
|
||||
* @author lepdou 2022-05-20
|
||||
*/
|
||||
public final class FeignExpressionLabelUtils {
|
||||
|
||||
private FeignExpressionLabelUtils() {
|
||||
}
|
||||
|
||||
public static Map<String, String> resolve(RequestTemplate request, Set<String> labelKeys) {
|
||||
if (CollectionUtils.isEmpty(labelKeys)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, String> labels = new HashMap<>();
|
||||
|
||||
for (String labelKey : labelKeys) {
|
||||
if (ExpressionLabelUtils.isHeaderLabel(labelKey)) {
|
||||
String headerKey = ExpressionLabelUtils.parseHeaderKey(labelKey);
|
||||
if (StringUtils.isBlank(headerKey)) {
|
||||
continue;
|
||||
}
|
||||
labels.put(labelKey, getHeaderValue(request, headerKey));
|
||||
}
|
||||
else if (ExpressionLabelUtils.isQueryLabel(labelKey)) {
|
||||
String queryKey = ExpressionLabelUtils.parseQueryKey(labelKey);
|
||||
if (StringUtils.isBlank(queryKey)) {
|
||||
continue;
|
||||
}
|
||||
labels.put(labelKey, getQueryValue(request, queryKey));
|
||||
}
|
||||
else if (ExpressionLabelUtils.isCookieLabel(labelKey)) {
|
||||
String cookieKey = ExpressionLabelUtils.parseCookieKey(labelKey);
|
||||
if (StringUtils.isBlank(cookieKey)) {
|
||||
continue;
|
||||
}
|
||||
labels.put(labelKey, getCookieValue(request, cookieKey));
|
||||
}
|
||||
else if (ExpressionLabelUtils.isMethodLabel(labelKey)) {
|
||||
labels.put(labelKey, request.method());
|
||||
}
|
||||
else if (ExpressionLabelUtils.isUriLabel(labelKey)) {
|
||||
URI uri = URI.create(request.request().url());
|
||||
labels.put(labelKey, uri.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
public static String getHeaderValue(RequestTemplate request, String key) {
|
||||
Map<String, Collection<String>> headers = request.headers();
|
||||
return ExpressionLabelUtils.getFirstValue(headers, key);
|
||||
|
||||
}
|
||||
|
||||
public static String getQueryValue(RequestTemplate request, String key) {
|
||||
return ExpressionLabelUtils.getFirstValue(request.queries(), key);
|
||||
}
|
||||
|
||||
public static String getCookieValue(RequestTemplate request, String key) {
|
||||
Map<String, Collection<String>> headers = request.headers();
|
||||
return ExpressionLabelUtils.getCookieFirstValue(headers, key);
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* 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.resttemplate;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
|
||||
import org.springframework.http.HttpRequest;
|
||||
|
||||
/**
|
||||
* Wrapper of {@link LoadBalancerRequest}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public class PolarisLoadBalancerRequest<T> implements LoadBalancerRequest<T> {
|
||||
|
||||
private HttpRequest request;
|
||||
|
||||
private LoadBalancerRequest<T> delegate;
|
||||
|
||||
public PolarisLoadBalancerRequest(HttpRequest request, LoadBalancerRequest<T> delegate) {
|
||||
this.request = request;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T apply(ServiceInstance instance) throws Exception {
|
||||
return delegate.apply(instance);
|
||||
}
|
||||
|
||||
public HttpRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public LoadBalancerRequest<T> getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
@ -1,281 +0,0 @@
|
||||
/*
|
||||
* 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.scg;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.tencent.cloud.common.constant.RouterConstant;
|
||||
import com.tencent.cloud.common.metadata.MetadataContext;
|
||||
import com.tencent.cloud.common.metadata.MetadataContextHolder;
|
||||
import com.tencent.cloud.common.metadata.StaticMetadataManager;
|
||||
import com.tencent.cloud.common.util.JacksonUtils;
|
||||
import com.tencent.cloud.common.util.expresstion.ExpressionLabelUtils;
|
||||
import com.tencent.cloud.common.util.expresstion.SpringWebExpressionLabelUtils;
|
||||
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
|
||||
import com.tencent.cloud.polaris.router.PolarisRouterServiceInstanceListSupplier;
|
||||
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
|
||||
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.CompletionContext;
|
||||
import org.springframework.cloud.client.loadbalancer.DefaultRequest;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerLifecycle;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerLifecycleValidator;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools;
|
||||
import org.springframework.cloud.client.loadbalancer.Request;
|
||||
import org.springframework.cloud.client.loadbalancer.RequestData;
|
||||
import org.springframework.cloud.client.loadbalancer.RequestDataContext;
|
||||
import org.springframework.cloud.client.loadbalancer.Response;
|
||||
import org.springframework.cloud.client.loadbalancer.ResponseData;
|
||||
import org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
|
||||
import org.springframework.cloud.gateway.support.DelegatingServiceInstance;
|
||||
import org.springframework.cloud.gateway.support.NotFoundException;
|
||||
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
|
||||
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
|
||||
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import static com.tencent.cloud.common.constant.ContextConstant.UTF_8;
|
||||
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_LOADBALANCER_RESPONSE_ATTR;
|
||||
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
|
||||
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR;
|
||||
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;
|
||||
|
||||
/**
|
||||
* ReactiveLoadBalancerClientFilter does not have the ability to pass route labels, so it is replaced
|
||||
* with PolarisReactiveLoadBalancerClientFilter. The passed route labels are used in
|
||||
* {@link PolarisRouterServiceInstanceListSupplier}.
|
||||
*
|
||||
* @author lepdou, Hoatian Zhang
|
||||
*/
|
||||
public class PolarisReactiveLoadBalancerClientFilter extends ReactiveLoadBalancerClientFilter {
|
||||
private static final Logger log = LoggerFactory.getLogger(PolarisReactiveLoadBalancerClientFilter.class);
|
||||
|
||||
private final LoadBalancerClientFactory clientFactory;
|
||||
private final GatewayLoadBalancerProperties gatewayLoadBalancerProperties;
|
||||
private final StaticMetadataManager staticMetadataManager;
|
||||
private final RouterRuleLabelResolver routerRuleLabelResolver;
|
||||
private final List<SpringWebRouterLabelResolver> routerLabelResolvers;
|
||||
private final PolarisContextProperties polarisContextProperties;
|
||||
|
||||
public PolarisReactiveLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory,
|
||||
GatewayLoadBalancerProperties gatewayLoadBalancerProperties,
|
||||
StaticMetadataManager staticMetadataManager,
|
||||
RouterRuleLabelResolver routerRuleLabelResolver,
|
||||
List<SpringWebRouterLabelResolver> routerLabelResolvers,
|
||||
PolarisContextProperties polarisContextProperties) {
|
||||
super(clientFactory, gatewayLoadBalancerProperties);
|
||||
|
||||
this.clientFactory = clientFactory;
|
||||
this.gatewayLoadBalancerProperties = gatewayLoadBalancerProperties;
|
||||
this.staticMetadataManager = staticMetadataManager;
|
||||
this.routerRuleLabelResolver = routerRuleLabelResolver;
|
||||
this.routerLabelResolvers = routerLabelResolvers;
|
||||
this.polarisContextProperties = polarisContextProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied from ReactiveLoadBalancerClientFilter, and create new RequestData for passing router labels.
|
||||
*/
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
|
||||
String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);
|
||||
if (url == null || (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
// preserve the original url
|
||||
addOriginalRequestUrl(exchange, url);
|
||||
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url);
|
||||
}
|
||||
|
||||
URI requestUri = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
|
||||
String serviceId = requestUri.getHost();
|
||||
Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator
|
||||
.getSupportedLifecycleProcessors(clientFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
|
||||
RequestDataContext.class, ResponseData.class, ServiceInstance.class);
|
||||
|
||||
// Pass route tags through http headers
|
||||
HttpHeaders routerHttpHeaders = genRouterHttpHeaders(exchange, serviceId);
|
||||
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
RequestData requestData = new RequestData(request.getMethod(), request.getURI(), routerHttpHeaders,
|
||||
new HttpHeaders(), new HashMap<>());
|
||||
DefaultRequest<RequestDataContext> lbRequest = new DefaultRequest<>(new RequestDataContext(
|
||||
requestData, getHint(serviceId)));
|
||||
|
||||
return choose(lbRequest, serviceId, supportedLifecycleProcessors).doOnNext(response -> {
|
||||
|
||||
if (!response.hasServer()) {
|
||||
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
|
||||
.onComplete(new CompletionContext<>(CompletionContext.Status.DISCARD, lbRequest, response)));
|
||||
throw NotFoundException.create(gatewayLoadBalancerProperties.isUse404(),
|
||||
"Unable to find instance for " + url.getHost());
|
||||
}
|
||||
|
||||
ServiceInstance retrievedInstance = response.getServer();
|
||||
|
||||
URI uri = exchange.getRequest().getURI();
|
||||
|
||||
// if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default,
|
||||
// if the loadbalancer doesn't provide one.
|
||||
String overrideScheme = retrievedInstance.isSecure() ? "https" : "http";
|
||||
if (schemePrefix != null) {
|
||||
overrideScheme = url.getScheme();
|
||||
}
|
||||
|
||||
DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance(retrievedInstance,
|
||||
overrideScheme);
|
||||
|
||||
URI requestUrl = reconstructURI(serviceInstance, uri);
|
||||
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
|
||||
}
|
||||
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
|
||||
exchange.getAttributes().put(GATEWAY_LOADBALANCER_RESPONSE_ATTR, response);
|
||||
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStartRequest(lbRequest, response));
|
||||
}).then(chain.filter(exchange))
|
||||
.doOnError(throwable -> supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
|
||||
.onComplete(new CompletionContext<ResponseData, ServiceInstance, RequestDataContext>(
|
||||
CompletionContext.Status.FAILED, throwable, lbRequest,
|
||||
exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR)))))
|
||||
.doOnSuccess(aVoid -> supportedLifecycleProcessors.forEach(lifecycle -> lifecycle
|
||||
.onComplete(new CompletionContext<ResponseData, ServiceInstance, RequestDataContext>(
|
||||
CompletionContext.Status.SUCCESS, lbRequest,
|
||||
exchange.getAttribute(GATEWAY_LOADBALANCER_RESPONSE_ATTR),
|
||||
new ResponseData(exchange.getResponse(), new RequestData(exchange.getRequest()))))));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URI reconstructURI(ServiceInstance serviceInstance, URI original) {
|
||||
return LoadBalancerUriTools.reconstructURI(serviceInstance, original);
|
||||
}
|
||||
|
||||
private Mono<Response<ServiceInstance>> choose(Request<RequestDataContext> lbRequest, String serviceId,
|
||||
Set<LoadBalancerLifecycle> supportedLifecycleProcessors) {
|
||||
ReactorLoadBalancer<ServiceInstance> loadBalancer = this.clientFactory.getInstance(serviceId,
|
||||
ReactorServiceInstanceLoadBalancer.class);
|
||||
if (loadBalancer == null) {
|
||||
throw new NotFoundException("No loadbalancer available for " + serviceId);
|
||||
}
|
||||
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));
|
||||
return loadBalancer.choose(lbRequest);
|
||||
}
|
||||
|
||||
// no actual used
|
||||
private String getHint(String serviceId) {
|
||||
LoadBalancerProperties loadBalancerProperties = clientFactory.getProperties(serviceId);
|
||||
Map<String, String> hints = loadBalancerProperties.getHint();
|
||||
String defaultHint = hints.getOrDefault("default", "default");
|
||||
String hintPropertyValue = hints.get(serviceId);
|
||||
return hintPropertyValue != null ? hintPropertyValue : defaultHint;
|
||||
}
|
||||
|
||||
// In order to be consistent with feign and restTemplate,
|
||||
// the router label is passed through the http header uniformly instead of the original hint mechanism.
|
||||
HttpHeaders genRouterHttpHeaders(ServerWebExchange exchange, String peerServiceName) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add(RouterConstant.ROUTER_LABEL_HEADER, genRouterHint(exchange, peerServiceName));
|
||||
return headers;
|
||||
}
|
||||
|
||||
private String genRouterHint(ServerWebExchange exchange, String peerServiceName) {
|
||||
Map<String, String> routerLabels = genRouterLabels(exchange, peerServiceName);
|
||||
String encodedLabelsContent;
|
||||
try {
|
||||
encodedLabelsContent = URLEncoder.encode(JacksonUtils.serialize2Json(routerLabels), UTF_8);
|
||||
}
|
||||
catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException("unsupported charset exception " + UTF_8);
|
||||
}
|
||||
return encodedLabelsContent;
|
||||
}
|
||||
|
||||
private Map<String, String> genRouterLabels(ServerWebExchange exchange, String peerServiceName) {
|
||||
// local service labels
|
||||
Map<String, String> labels = new HashMap<>(staticMetadataManager.getMergedStaticMetadata());
|
||||
|
||||
// labels from rule expression
|
||||
Set<String> expressionLabelKeys = routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE,
|
||||
MetadataContext.LOCAL_SERVICE, peerServiceName);
|
||||
|
||||
Map<String, String> ruleExpressionLabels = getExpressionLabels(exchange, expressionLabelKeys);
|
||||
if (!CollectionUtils.isEmpty(ruleExpressionLabels)) {
|
||||
labels.putAll(ruleExpressionLabels);
|
||||
}
|
||||
|
||||
// labels from request
|
||||
if (!CollectionUtils.isEmpty(routerLabelResolvers)) {
|
||||
routerLabelResolvers.forEach(resolver -> {
|
||||
try {
|
||||
Map<String, String> customResolvedLabels = resolver.resolve(exchange, expressionLabelKeys);
|
||||
if (!CollectionUtils.isEmpty(customResolvedLabels)) {
|
||||
labels.putAll(customResolvedLabels);
|
||||
}
|
||||
}
|
||||
catch (Throwable t) {
|
||||
log.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// labels from downstream
|
||||
Map<String, String> transitiveLabels = MetadataContextHolder.get().getTransitiveMetadata();
|
||||
labels.putAll(transitiveLabels);
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
private Map<String, String> getExpressionLabels(ServerWebExchange exchange, Set<String> labelKeys) {
|
||||
if (CollectionUtils.isEmpty(labelKeys)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
//enrich labels from request
|
||||
Map<String, String> labels = SpringWebExpressionLabelUtils.resolve(exchange, labelKeys);
|
||||
|
||||
//enrich caller ip label
|
||||
for (String labelKey : labelKeys) {
|
||||
if (ExpressionLabelUtils.isCallerIPLabel(labelKey)) {
|
||||
labels.put(labelKey, polarisContextProperties.getLocalIpAddress());
|
||||
}
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.scg;
|
||||
|
||||
import com.tencent.cloud.common.metadata.MetadataContextHolder;
|
||||
import com.tencent.cloud.metadata.provider.ReactiveMetadataProvider;
|
||||
import com.tencent.polaris.metadata.core.MetadataType;
|
||||
import com.tencent.polaris.metadata.core.constant.MetadataConstants;
|
||||
import com.tencent.polaris.metadata.core.manager.CalleeMetadataContainerGroup;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import static org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER;
|
||||
|
||||
/**
|
||||
* Interceptor used for setting SCG ServerWebExchange metadata provider.
|
||||
*
|
||||
* @author Hoatian Zhang
|
||||
*/
|
||||
public class RouterLabelGlobalFilter implements GlobalFilter, Ordered {
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return LOAD_BALANCER_CLIENT_FILTER_ORDER - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copied from ReactiveLoadBalancerClientFilter, and create new RequestData for passing router labels.
|
||||
*/
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
MetadataContextHolder.get().getMetadataContainer(MetadataType.MESSAGE, false)
|
||||
.setMetadataProvider(new ReactiveMetadataProvider(exchange.getRequest(),
|
||||
CalleeMetadataContainerGroup.getStaticApplicationMetadataContainer()
|
||||
.getRawMetadataStringValue(MetadataConstants.LOCAL_IP)));
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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.spi;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import feign.RequestTemplate;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* Router label resolver for feign request.
|
||||
* @author lepdou 2022-07-20
|
||||
*/
|
||||
public interface FeignRouterLabelResolver extends Ordered {
|
||||
|
||||
/**
|
||||
* Resolve labels from feign request. User can customize expression parser to extract labels.
|
||||
*
|
||||
* @param requestTemplate the feign request.
|
||||
* @param expressionLabelKeys the expression labels which are configured in router rule.
|
||||
* @return resolved labels
|
||||
*/
|
||||
Map<String, String> resolve(RequestTemplate requestTemplate, Set<String> expressionLabelKeys);
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* 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.spi;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
* Router label resolver for spring web http request.
|
||||
* @author lepdou 2022-07-20
|
||||
*/
|
||||
public interface SpringWebRouterLabelResolver extends Ordered {
|
||||
|
||||
/**
|
||||
* resolve labels from rest template request. User can customize expression parser to extract labels.
|
||||
*
|
||||
* @param request the rest template request.
|
||||
* @param body the rest template request body.
|
||||
* @param expressionLabelKeys the expression labels which are configured in router rule.
|
||||
* @return resolved labels
|
||||
*/
|
||||
default Map<String, String> resolve(HttpRequest request, byte[] body, Set<String> expressionLabelKeys) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* resolve labels from server web exchange. User can customize expression parser to extract labels.
|
||||
*
|
||||
* @param exchange the server web exchange.
|
||||
* @param expressionLabelKeys the expression labels which are configured in router rule.
|
||||
* @return resolved labels
|
||||
*/
|
||||
default Map<String, String> resolve(ServerWebExchange exchange, Set<String> expressionLabelKeys) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.tencent.cloud.polaris.context.ServiceRuleManager;
|
||||
import com.tencent.polaris.specification.api.v1.model.ModelProto;
|
||||
import com.tencent.polaris.specification.api.v1.traffic.manage.RoutingProto;
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* test for {@link RouterRuleLabelResolver}.
|
||||
*@author lepdou 2022-05-26
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class RouterRuleLabelResolverTest {
|
||||
|
||||
private final String testNamespace = "testNamespace";
|
||||
private final String testSourceService = "sourceService";
|
||||
private final String testDstService = "dstService";
|
||||
@Mock
|
||||
private ServiceRuleManager serviceRuleManager;
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
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.list(source1, source2, source3))
|
||||
.build();
|
||||
routes.add(route);
|
||||
|
||||
when(serviceRuleManager.getServiceRouterRule(testNamespace, testSourceService, testDstService)).thenReturn(routes);
|
||||
|
||||
RouterRuleLabelResolver resolver = new RouterRuleLabelResolver(serviceRuleManager);
|
||||
|
||||
Set<String> resolvedExpressionLabelKeys = resolver.getExpressionLabelKeys(testNamespace, testSourceService, testDstService);
|
||||
|
||||
assertThat(resolvedExpressionLabelKeys).isNotNull();
|
||||
assertThat(resolvedExpressionLabelKeys.size()).isEqualTo(6);
|
||||
assertThat(resolvedExpressionLabelKeys).contains(validKey1);
|
||||
assertThat(resolvedExpressionLabelKeys).contains(validKey2);
|
||||
assertThat(resolvedExpressionLabelKeys).contains(validKey3);
|
||||
assertThat(resolvedExpressionLabelKeys).contains(validKey4);
|
||||
assertThat(resolvedExpressionLabelKeys).contains(validKey5);
|
||||
assertThat(resolvedExpressionLabelKeys).contains(invalidKey);
|
||||
}
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
* 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.beanprocessor;
|
||||
|
||||
import com.tencent.cloud.common.metadata.StaticMetadataManager;
|
||||
import com.tencent.cloud.common.util.BeanFactoryUtils;
|
||||
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
|
||||
import com.tencent.cloud.polaris.router.scg.PolarisReactiveLoadBalancerClientFilter;
|
||||
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties;
|
||||
import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
|
||||
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
/**
|
||||
* Test for ${@link ReactiveLoadBalancerClientFilterBeanPostProcessor}.
|
||||
*
|
||||
* @author lepdou 2022-07-04
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class ReactiveLoadBalancerClientFilterBeanPostProcessorTest {
|
||||
|
||||
@Mock
|
||||
private BeanFactory beanFactory;
|
||||
@Mock
|
||||
private LoadBalancerClientFactory loadBalancerClientFactory;
|
||||
@Mock
|
||||
private GatewayLoadBalancerProperties gatewayLoadBalancerProperties;
|
||||
@Mock
|
||||
private StaticMetadataManager staticMetadataManager;
|
||||
@Mock
|
||||
private RouterRuleLabelResolver routerRuleLabelResolver;
|
||||
|
||||
@Test
|
||||
public void testWrapReactiveLoadBalancerClientFilter() {
|
||||
when(beanFactory.getBean(LoadBalancerClientFactory.class)).thenReturn(loadBalancerClientFactory);
|
||||
when(beanFactory.getBean(GatewayLoadBalancerProperties.class)).thenReturn(gatewayLoadBalancerProperties);
|
||||
when(beanFactory.getBean(StaticMetadataManager.class)).thenReturn(staticMetadataManager);
|
||||
when(beanFactory.getBean(RouterRuleLabelResolver.class)).thenReturn(routerRuleLabelResolver);
|
||||
|
||||
try (MockedStatic<BeanFactoryUtils> mockedBeanFactoryUtils = Mockito.mockStatic(BeanFactoryUtils.class)) {
|
||||
mockedBeanFactoryUtils.when(() -> BeanFactoryUtils.getBeans(beanFactory, SpringWebRouterLabelResolver.class))
|
||||
.thenReturn(null);
|
||||
|
||||
ReactiveLoadBalancerClientFilter reactiveLoadBalancerClientFilter = new ReactiveLoadBalancerClientFilter(
|
||||
loadBalancerClientFactory, gatewayLoadBalancerProperties);
|
||||
|
||||
ReactiveLoadBalancerClientFilterBeanPostProcessor processor = new ReactiveLoadBalancerClientFilterBeanPostProcessor();
|
||||
processor.setBeanFactory(beanFactory);
|
||||
|
||||
Object bean = processor.postProcessBeforeInitialization(reactiveLoadBalancerClientFilter, "");
|
||||
assertThat(bean).isInstanceOf(PolarisReactiveLoadBalancerClientFilter.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotWrapLoadBalancerInterceptor() {
|
||||
ReactiveLoadBalancerClientFilterBeanPostProcessor processor = new ReactiveLoadBalancerClientFilterBeanPostProcessor();
|
||||
processor.setBeanFactory(beanFactory);
|
||||
|
||||
OtherBean otherBean = new OtherBean();
|
||||
Object bean = processor.postProcessBeforeInitialization(otherBean, "");
|
||||
assertThat(bean).isNotInstanceOf(PolarisReactiveLoadBalancerClientFilter.class);
|
||||
assertThat(bean).isInstanceOf(OtherBean.class);
|
||||
}
|
||||
|
||||
static class OtherBean {
|
||||
|
||||
}
|
||||
}
|
@ -1,161 +0,0 @@
|
||||
/*
|
||||
* 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.feign;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import feign.Request;
|
||||
import feign.RequestTemplate;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for {@link FeignExpressionLabelUtils}.
|
||||
*@author lepdou 2022-05-26
|
||||
*/
|
||||
public class FeignExpressionLabelUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testGetHeaderLabel() {
|
||||
String headerKey = "uid";
|
||||
String headerValue = "1000";
|
||||
String headerKey2 = "teacher.age";
|
||||
String headerValue2 = "1000";
|
||||
|
||||
RequestTemplate requestTemplate = new RequestTemplate();
|
||||
requestTemplate.header(headerKey, headerValue);
|
||||
requestTemplate.header(headerKey2, headerValue2);
|
||||
|
||||
String labelKey1 = "${http.header.uid}";
|
||||
String labelKey2 = "${http.header.name}";
|
||||
String labelKey3 = "${http.headername}";
|
||||
String labelKey4 = "${http.header.}";
|
||||
String labelKey5 = "${http.header.teacher.age}";
|
||||
Map<String, String> result = FeignExpressionLabelUtils.resolve(requestTemplate,
|
||||
Stream.of(labelKey1, labelKey2, labelKey3, labelKey4, labelKey5).collect(toSet()));
|
||||
|
||||
assertThat(result).isNotEmpty();
|
||||
assertThat(result.get(labelKey1)).isEqualTo(headerValue);
|
||||
assertThat(result.get(labelKey5)).isEqualTo(headerValue2);
|
||||
assertThat(result.get(labelKey2)).isBlank();
|
||||
assertThat(result.get(labelKey3)).isBlank();
|
||||
assertThat(result.get(labelKey4)).isBlank();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetQueryLabel() {
|
||||
String headerKey = "uid";
|
||||
String headerValue = "1000";
|
||||
String headerKey2 = "teacher.age";
|
||||
String headerValue2 = "1000";
|
||||
|
||||
RequestTemplate requestTemplate = new RequestTemplate();
|
||||
requestTemplate.query(headerKey, headerValue);
|
||||
requestTemplate.query(headerKey2, headerValue2);
|
||||
|
||||
String labelKey1 = "${http.query.uid}";
|
||||
String labelKey2 = "${http.query.name}";
|
||||
String labelKey3 = "${http.queryname}";
|
||||
String labelKey4 = "${http.query.}";
|
||||
String labelKey5 = "${http.query.teacher.age}";
|
||||
Map<String, String> result = FeignExpressionLabelUtils.resolve(requestTemplate,
|
||||
Stream.of(labelKey1, labelKey2, labelKey3, labelKey4, labelKey5).collect(toSet()));
|
||||
|
||||
assertThat(result).isNotEmpty();
|
||||
assertThat(result.get(labelKey1)).isEqualTo(headerValue);
|
||||
assertThat(result.get(labelKey5)).isEqualTo(headerValue2);
|
||||
assertThat(result.get(labelKey2)).isBlank();
|
||||
assertThat(result.get(labelKey3)).isBlank();
|
||||
assertThat(result.get(labelKey4)).isBlank();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMethod() {
|
||||
RequestTemplate requestTemplate = new RequestTemplate();
|
||||
requestTemplate.method(Request.HttpMethod.GET);
|
||||
|
||||
String labelKey1 = "${http.method}";
|
||||
Map<String, String> result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1)
|
||||
.collect(toSet()));
|
||||
|
||||
assertThat(result).isNotEmpty();
|
||||
assertThat(result.get(labelKey1)).isEqualTo("GET");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUri() {
|
||||
String uri = "/user/get";
|
||||
|
||||
RequestTemplate requestTemplate = new RequestTemplate();
|
||||
requestTemplate.uri(uri);
|
||||
requestTemplate.method(Request.HttpMethod.GET);
|
||||
requestTemplate.target("http://localhost");
|
||||
requestTemplate = requestTemplate.resolve(new HashMap<>());
|
||||
|
||||
String labelKey1 = "${http.uri}";
|
||||
Map<String, String> result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1)
|
||||
.collect(toSet()));
|
||||
|
||||
assertThat(result).isNotEmpty();
|
||||
assertThat(result.get(labelKey1)).isEqualTo(uri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUri2() {
|
||||
String uri = "/";
|
||||
|
||||
RequestTemplate requestTemplate = new RequestTemplate();
|
||||
requestTemplate.uri(uri);
|
||||
requestTemplate.method(Request.HttpMethod.GET);
|
||||
requestTemplate.target("http://localhost");
|
||||
requestTemplate = requestTemplate.resolve(new HashMap<>());
|
||||
|
||||
String labelKey1 = "${http.uri}";
|
||||
Map<String, String> result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1)
|
||||
.collect(toSet()));
|
||||
|
||||
assertThat(result).isNotEmpty();
|
||||
assertThat(result.get(labelKey1)).isEqualTo(uri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCookie() {
|
||||
String uri = "/";
|
||||
String cookieValue = "zhangsan";
|
||||
|
||||
RequestTemplate requestTemplate = new RequestTemplate();
|
||||
requestTemplate.uri(uri);
|
||||
requestTemplate.method(Request.HttpMethod.GET);
|
||||
requestTemplate.target("http://localhost");
|
||||
requestTemplate = requestTemplate.resolve(new HashMap<>());
|
||||
requestTemplate.header("cookie", Collections.singleton("uid=zhangsan; auth-token=dfhuwshfy77"));
|
||||
|
||||
String labelKey1 = "${http.cookie.uid}";
|
||||
Map<String, String> result = FeignExpressionLabelUtils.resolve(requestTemplate, Stream.of(labelKey1)
|
||||
.collect(toSet()));
|
||||
|
||||
assertThat(result).isNotEmpty();
|
||||
assertThat(result.get(labelKey1)).isEqualTo(cookieValue);
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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.resttemplate;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
|
||||
import org.springframework.http.HttpRequest;
|
||||
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
|
||||
/**
|
||||
* test for {@link PolarisLoadBalancerRequest}.
|
||||
* @author dongyinuo
|
||||
*/
|
||||
public class PolarisLoadBalancerRequestTests {
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
String calleeService = "calleeService";
|
||||
HttpRequest request = new RouterLabelRestTemplateInterceptorTest.MockedHttpRequest("http://" + calleeService + "/user/get");
|
||||
MockLoadBalancerRequest mockLoadBalancerRequest = new MockLoadBalancerRequest();
|
||||
PolarisLoadBalancerRequest<ServiceInstance> polarisLoadBalancerRequest = new PolarisLoadBalancerRequest<>(request, mockLoadBalancerRequest);
|
||||
|
||||
DefaultServiceInstance serviceInstance = new DefaultServiceInstance();
|
||||
serviceInstance.setServiceId(calleeService);
|
||||
ServiceInstance apply = polarisLoadBalancerRequest.apply(serviceInstance);
|
||||
assertThat(apply.getServiceId()).isEqualTo(calleeService);
|
||||
assertThat(polarisLoadBalancerRequest.getRequest()).isEqualTo(request);
|
||||
assertThat(polarisLoadBalancerRequest.getDelegate()).isEqualTo(mockLoadBalancerRequest);
|
||||
}
|
||||
|
||||
static class MockLoadBalancerRequest implements LoadBalancerRequest {
|
||||
|
||||
@Override
|
||||
public Object apply(ServiceInstance instance) throws Exception {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,202 +0,0 @@
|
||||
/*
|
||||
* 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.scg;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.tencent.cloud.common.constant.RouterConstant;
|
||||
import com.tencent.cloud.common.metadata.MetadataContext;
|
||||
import com.tencent.cloud.common.metadata.MetadataContextHolder;
|
||||
import com.tencent.cloud.common.metadata.StaticMetadataManager;
|
||||
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
|
||||
import com.tencent.cloud.common.util.JacksonUtils;
|
||||
import com.tencent.cloud.polaris.context.config.PolarisContextProperties;
|
||||
import com.tencent.cloud.polaris.router.RouterRuleLabelResolver;
|
||||
import com.tencent.cloud.polaris.router.spi.SpringWebRouterLabelResolver;
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.assertj.core.util.Sets;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.cloud.gateway.config.GatewayLoadBalancerProperties;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
|
||||
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
|
||||
import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer;
|
||||
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
||||
import org.springframework.cloud.loadbalancer.support.SimpleObjectProvider;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import static com.tencent.cloud.common.constant.ContextConstant.UTF_8;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
|
||||
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR;
|
||||
|
||||
/**
|
||||
* Test for ${@link PolarisReactiveLoadBalancerClientFilter}.
|
||||
*
|
||||
* @author lepdou 2022-07-04
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class PolarisReactiveLoadBalancerClientFilterTest {
|
||||
|
||||
private static final String testNamespaceAndService = "testNamespaceAndService";
|
||||
private static final String calleeService = "calleeService";
|
||||
|
||||
@Mock
|
||||
private StaticMetadataManager staticMetadataManager;
|
||||
@Mock
|
||||
private SpringWebRouterLabelResolver routerLabelResolver;
|
||||
@Mock
|
||||
private RouterRuleLabelResolver routerRuleLabelResolver;
|
||||
@Mock
|
||||
private LoadBalancerClientFactory loadBalancerClientFactory;
|
||||
@Mock
|
||||
private GatewayLoadBalancerProperties gatewayLoadBalancerProperties;
|
||||
@Mock
|
||||
private PolarisContextProperties polarisContextProperties;
|
||||
|
||||
@Test
|
||||
public void testGenRouterHttpHeaders() throws UnsupportedEncodingException {
|
||||
try (
|
||||
MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = mockStatic(ApplicationContextAwareUtils.class);
|
||||
MockedStatic<MetadataContextHolder> mockedMetadataContextHolder = mockStatic(MetadataContextHolder.class)
|
||||
) {
|
||||
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
|
||||
.thenReturn(testNamespaceAndService);
|
||||
|
||||
MetadataContext metadataContext = mock(MetadataContext.class);
|
||||
|
||||
// mock transitive metadata
|
||||
Map<String, String> transitiveLabels = new HashMap<>();
|
||||
transitiveLabels.put("t1", "v1");
|
||||
transitiveLabels.put("t2", "v2");
|
||||
when(metadataContext.getTransitiveMetadata()).thenReturn(transitiveLabels);
|
||||
mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext);
|
||||
|
||||
PolarisReactiveLoadBalancerClientFilter filter = new PolarisReactiveLoadBalancerClientFilter(loadBalancerClientFactory,
|
||||
gatewayLoadBalancerProperties, staticMetadataManager, routerRuleLabelResolver,
|
||||
Collections.singletonList(routerLabelResolver), polarisContextProperties);
|
||||
|
||||
Map<String, String> localMetadata = new HashMap<>();
|
||||
localMetadata.put("env", "blue");
|
||||
when(staticMetadataManager.getMergedStaticMetadata()).thenReturn(localMetadata);
|
||||
|
||||
Set<String> expressionLabelKeys = Sets.set("${http.header.k1}", "${http.query.userid}");
|
||||
when(routerRuleLabelResolver.getExpressionLabelKeys(anyString(), anyString(), anyString())).thenReturn(expressionLabelKeys);
|
||||
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/" + calleeService + "/users")
|
||||
.header("k1", "v1")
|
||||
.queryParam("userid", "zhangsan")
|
||||
.build();
|
||||
MockServerWebExchange webExchange = new MockServerWebExchange.Builder(request).build();
|
||||
|
||||
Map<String, String> customMetadata = new HashMap<>();
|
||||
customMetadata.put("k2", "v2");
|
||||
when(routerLabelResolver.resolve(webExchange, expressionLabelKeys)).thenReturn(customMetadata);
|
||||
|
||||
HttpHeaders headers = filter.genRouterHttpHeaders(webExchange, calleeService);
|
||||
|
||||
assertThat(headers).isNotNull();
|
||||
List<String> routerHeaders = headers.get(RouterConstant.ROUTER_LABEL_HEADER);
|
||||
assertThat(routerHeaders).isNotNull();
|
||||
|
||||
|
||||
Map<String, String> routerLabels = JacksonUtils.deserialize2Map(URLDecoder.decode(routerHeaders.get(0), UTF_8));
|
||||
assertThat(routerLabels.get("${http.header.k1}")).isEqualTo("v1");
|
||||
assertThat(routerLabels.get("${http.query.userid}")).isEqualTo("zhangsan");
|
||||
assertThat(routerLabels.get("env")).isEqualTo("blue");
|
||||
assertThat(routerLabels.get("t1")).isEqualTo("v1");
|
||||
assertThat(routerLabels.get("t2")).isEqualTo("v2");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilter01() throws Exception {
|
||||
try (
|
||||
MockedStatic<ApplicationContextAwareUtils> mockedApplicationContextAwareUtils = mockStatic(ApplicationContextAwareUtils.class);
|
||||
MockedStatic<MetadataContextHolder> mockedMetadataContextHolder = mockStatic(MetadataContextHolder.class)
|
||||
) {
|
||||
mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString()))
|
||||
.thenReturn(testNamespaceAndService);
|
||||
|
||||
MetadataContext metadataContext = mock(MetadataContext.class);
|
||||
|
||||
// mock transitive metadata
|
||||
Map<String, String> transitiveLabels = new HashMap<>();
|
||||
transitiveLabels.put("t1", "v1");
|
||||
transitiveLabels.put("t2", "v2");
|
||||
when(metadataContext.getTransitiveMetadata()).thenReturn(transitiveLabels);
|
||||
mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext);
|
||||
|
||||
PolarisReactiveLoadBalancerClientFilter filter = new PolarisReactiveLoadBalancerClientFilter(loadBalancerClientFactory,
|
||||
gatewayLoadBalancerProperties, staticMetadataManager, routerRuleLabelResolver,
|
||||
Lists.list(routerLabelResolver), polarisContextProperties);
|
||||
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/" + calleeService + "/users").build();
|
||||
MockServerWebExchange exchange = new MockServerWebExchange.Builder(request).build();
|
||||
|
||||
// mock no lb
|
||||
EmptyGatewayFilterChain chain = new EmptyGatewayFilterChain();
|
||||
Mono<Void> ret = filter.filter(exchange, chain);
|
||||
assertThat(ret).isEqualTo(Mono.empty());
|
||||
|
||||
// mock with lb
|
||||
exchange = new MockServerWebExchange.Builder(request).build();
|
||||
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, new URI("https://" + calleeService + ":8091"));
|
||||
exchange.getAttributes().put(GATEWAY_SCHEME_PREFIX_ATTR, "lb");
|
||||
|
||||
NoopServiceInstanceListSupplier serviceInstanceListSupplier = new NoopServiceInstanceListSupplier();
|
||||
RoundRobinLoadBalancer roundRobinLoadBalancer = new RoundRobinLoadBalancer(new SimpleObjectProvider<>(serviceInstanceListSupplier), calleeService);
|
||||
|
||||
when(loadBalancerClientFactory.getInstance(calleeService, ReactorServiceInstanceLoadBalancer.class)).thenReturn(roundRobinLoadBalancer);
|
||||
LoadBalancerProperties loadBalancerProperties = mock(LoadBalancerProperties.class);
|
||||
when(loadBalancerProperties.getHint()).thenReturn(new HashMap<>());
|
||||
when(loadBalancerClientFactory.getProperties(calleeService)).thenReturn(loadBalancerProperties);
|
||||
filter.filter(exchange, chain);
|
||||
}
|
||||
}
|
||||
|
||||
static class EmptyGatewayFilterChain implements GatewayFilterChain {
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange) {
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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.scg;
|
||||
|
||||
import com.tencent.cloud.common.metadata.MetadataContextHolder;
|
||||
import com.tencent.polaris.metadata.core.MessageMetadataContainer;
|
||||
import com.tencent.polaris.metadata.core.MetadataContainer;
|
||||
import com.tencent.polaris.metadata.core.MetadataType;
|
||||
import feign.Request;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER;
|
||||
|
||||
/**
|
||||
* Test for ${@link RouterLabelGlobalFilter}.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(classes = RouterLabelGlobalFilterTest.TestApplication.class,
|
||||
properties = {"spring.cloud.polaris.namespace=test", "spring.application.name=test", "spring.main.web-application-type=reactive"})
|
||||
public class RouterLabelGlobalFilterTest {
|
||||
|
||||
@Test
|
||||
public void testRouterLabel() {
|
||||
RouterLabelGlobalFilter routerLabelGlobalFilter = new RouterLabelGlobalFilter();
|
||||
|
||||
assertThat(routerLabelGlobalFilter.getOrder())
|
||||
.isEqualTo(LOAD_BALANCER_CLIENT_FILTER_ORDER - 1);
|
||||
|
||||
MockServerHttpRequest request = MockServerHttpRequest.post("/test/path")
|
||||
.header("uid", "1000")
|
||||
.cookie(new HttpCookie("k1", "v1"))
|
||||
.queryParam("q1", "a1")
|
||||
.build();
|
||||
MockServerWebExchange mockWebExchange = new MockServerWebExchange.Builder(request).build();
|
||||
|
||||
routerLabelGlobalFilter.filter(mockWebExchange, new EmptyGatewayFilterChain());
|
||||
|
||||
// get message metadata container
|
||||
MetadataContainer metadataContainer = MetadataContextHolder.get()
|
||||
.getMetadataContainer(MetadataType.MESSAGE, false);
|
||||
// method
|
||||
assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_METHOD)).isEqualTo(Request.HttpMethod.POST.toString());
|
||||
// path
|
||||
assertThat(metadataContainer.getRawMetadataStringValue(MessageMetadataContainer.LABEL_KEY_PATH)).isEqualTo("/test/path");
|
||||
// header
|
||||
assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_HEADER, "uid")).isEqualTo("1000");
|
||||
// cookie
|
||||
assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_COOKIE, "k1")).isEqualTo("v1");
|
||||
// query
|
||||
assertThat(metadataContainer.getRawMetadataMapValue(MessageMetadataContainer.LABEL_MAP_KEY_QUERY, "q1")).isEqualTo("a1");
|
||||
}
|
||||
|
||||
static class EmptyGatewayFilterChain implements GatewayFilterChain {
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange) {
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
protected static class TestApplication {
|
||||
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* 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.common.tsf;
|
||||
|
||||
/**
|
||||
* Constant for TSF.
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public final class TsfConstant {
|
||||
/**
|
||||
* tsf application id.
|
||||
*/
|
||||
public static String TSF_APPLICATION_ID = "TSF_APPLICATION_ID";
|
||||
|
||||
/**
|
||||
* tsf program version.
|
||||
*/
|
||||
public static String TSF_PROG_VERSION = "TSF_PROG_VERSION";
|
||||
|
||||
/**
|
||||
* tsf group id.
|
||||
*/
|
||||
public static String TSF_GROUP_ID = "TSF_GROUP_ID";
|
||||
|
||||
/**
|
||||
* tsf namespace id.
|
||||
*/
|
||||
public static String TSF_NAMESPACE_ID = "TSF_NAMESPACE_ID";
|
||||
|
||||
/**
|
||||
* tsf instance id.
|
||||
*/
|
||||
public static String TSF_INSTNACE_ID = "TSF_INSTNACE_ID";
|
||||
|
||||
/**
|
||||
* tsf region.
|
||||
*/
|
||||
public static String TSF_REGION = "TSF_REGION";
|
||||
|
||||
/**
|
||||
* tsf zone.
|
||||
*/
|
||||
public static String TSF_ZONE = "TSF_ZONE";
|
||||
|
||||
/**
|
||||
* tsf SDK version.
|
||||
*/
|
||||
public static String TSF_SDK_VERSION = "TSF_SDK_VERSION";
|
||||
|
||||
/**
|
||||
* tsf tags.
|
||||
*/
|
||||
public static String TSF_TAGS = "TSF_TAGS";
|
||||
|
||||
private TsfConstant() {
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
/*
|
||||
* 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.quickstart.caller.router;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.tencent.cloud.polaris.router.spi.FeignRouterLabelResolver;
|
||||
import feign.RequestTemplate;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
*
|
||||
* Customize the business tag information obtained from the request
|
||||
*
|
||||
*@author lepdou 2022-05-12
|
||||
*/
|
||||
@Component
|
||||
public class CustomRouterLabelResolver implements FeignRouterLabelResolver {
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
@Override
|
||||
public Map<String, String> resolve(RequestTemplate requestTemplate, Set<String> expressionLabelKeys) {
|
||||
Map<String, String> labels = new HashMap<>();
|
||||
|
||||
labels.put("label1", "value1");
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.context.tsf;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.tencent.cloud.common.util.inet.PolarisInetUtils;
|
||||
import com.tencent.cloud.polaris.context.tsf.config.TsfCoreProperties;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Haotian Zhang
|
||||
*/
|
||||
public final class TsfUtils {
|
||||
|
||||
/**
|
||||
* IPV4.
|
||||
*/
|
||||
public static String TSF_ADDRESS_IPV4 = "TSF_ADDRESS_IPV4";
|
||||
|
||||
/**
|
||||
* IPV6.
|
||||
*/
|
||||
public static String TSF_ADDRESS_IPV6 = "TSF_ADDRESS_IPV6";
|
||||
|
||||
private TsfUtils() {
|
||||
}
|
||||
|
||||
public static List<String> createTags(TsfCoreProperties properties) {
|
||||
List<String> tags = new LinkedList<>(properties.getTags());
|
||||
|
||||
if (StringUtils.hasText(properties.getInstanceZone())) {
|
||||
tags.add(properties.getDefaultZoneMetadataName() + "=" + properties.getInstanceZone());
|
||||
}
|
||||
if (StringUtils.hasText(properties.getInstanceGroup())) {
|
||||
tags.add("group=" + properties.getInstanceGroup());
|
||||
}
|
||||
|
||||
//store the secure flag in the tags so that clients will be able to figure out whether to use http or https automatically
|
||||
tags.add("secure=" + properties.getScheme().equalsIgnoreCase("https"));
|
||||
|
||||
return tags;
|
||||
}
|
||||
|
||||
public static Map<String, String> appendMetaIpAddress(Map<String, String> meta) {
|
||||
if (meta == null) {
|
||||
return null;
|
||||
}
|
||||
String ipv4Address = PolarisInetUtils.getIpString(false);
|
||||
if (ipv4Address != null) {
|
||||
meta.put(TSF_ADDRESS_IPV4, ipv4Address);
|
||||
}
|
||||
|
||||
String ipv6Address = PolarisInetUtils.getIpString(true);
|
||||
if (ipv6Address != null) {
|
||||
meta.put(TSF_ADDRESS_IPV6, ipv6Address);
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.context.tsf.metadata;
|
||||
|
||||
import com.tencent.cloud.common.spi.InstanceMetadataProvider;
|
||||
import com.tencent.cloud.common.tsf.ConditionalOnTsfEnabled;
|
||||
import com.tencent.cloud.polaris.context.config.PolarisContextAutoConfiguration;
|
||||
import com.tencent.cloud.polaris.context.tsf.config.TsfCoreProperties;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Auto configuration for instanceMetadataProvider for TSF.
|
||||
*
|
||||
* @author Hoatian Zhang
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@AutoConfigureAfter(PolarisContextAutoConfiguration.class)
|
||||
@ConditionalOnTsfEnabled
|
||||
public class TsfInstanceMetadataAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public InstanceMetadataProvider tsfInstanceMetadataProvider(TsfCoreProperties tsfCoreProperties) {
|
||||
return new TsfInstanceMetadataProvider(tsfCoreProperties);
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.context.tsf.metadata;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.tencent.cloud.common.constant.SdkVersion;
|
||||
import com.tencent.cloud.common.constant.WarmupCons;
|
||||
import com.tencent.cloud.common.spi.InstanceMetadataProvider;
|
||||
import com.tencent.cloud.common.util.JacksonUtils;
|
||||
import com.tencent.cloud.common.util.inet.PolarisInetUtils;
|
||||
import com.tencent.cloud.polaris.context.tsf.TsfUtils;
|
||||
import com.tencent.cloud.polaris.context.tsf.config.TsfCoreProperties;
|
||||
import com.tencent.polaris.api.utils.StringUtils;
|
||||
import com.tencent.polaris.metadata.core.constant.TsfMetadataConstants;
|
||||
|
||||
import static com.tencent.cloud.polaris.context.tsf.TsfUtils.TSF_ADDRESS_IPV4;
|
||||
import static com.tencent.cloud.polaris.context.tsf.TsfUtils.TSF_ADDRESS_IPV6;
|
||||
|
||||
|
||||
/**
|
||||
* InstanceMetadataProvider for TSF.
|
||||
*
|
||||
* @author Hoatian Zhang
|
||||
*/
|
||||
public class TsfInstanceMetadataProvider implements InstanceMetadataProvider {
|
||||
|
||||
private final TsfCoreProperties tsfCoreProperties;
|
||||
|
||||
public TsfInstanceMetadataProvider(TsfCoreProperties tsfCoreProperties) {
|
||||
this.tsfCoreProperties = tsfCoreProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getMetadata() {
|
||||
return new HashMap<>() {{
|
||||
put(TsfMetadataConstants.TSF_PROG_VERSION, tsfCoreProperties.getTsfProgVersion());
|
||||
put(TsfMetadataConstants.TSF_APPLICATION_ID, tsfCoreProperties.getTsfApplicationId());
|
||||
put(TsfMetadataConstants.TSF_GROUP_ID, tsfCoreProperties.getTsfGroupId());
|
||||
put(TsfMetadataConstants.TSF_APPLICATION_ID, tsfCoreProperties.getTsfApplicationId());
|
||||
put(TsfMetadataConstants.TSF_PROG_VERSION, tsfCoreProperties.getTsfProgVersion());
|
||||
put(TsfMetadataConstants.TSF_GROUP_ID, tsfCoreProperties.getTsfGroupId());
|
||||
put(TsfMetadataConstants.TSF_NAMESPACE_ID, tsfCoreProperties.getTsfNamespaceId());
|
||||
put(TsfMetadataConstants.TSF_INSTNACE_ID, tsfCoreProperties.getInstanceId());
|
||||
put(TsfMetadataConstants.TSF_REGION, tsfCoreProperties.getTsfRegion());
|
||||
put(TsfMetadataConstants.TSF_ZONE, tsfCoreProperties.getTsfZone());
|
||||
// 处理预热相关的参数
|
||||
put(WarmupCons.TSF_START_TIME, String.valueOf(System.currentTimeMillis()));
|
||||
put(TsfMetadataConstants.TSF_SDK_VERSION, SdkVersion.get());
|
||||
put(TsfMetadataConstants.TSF_TAGS, JacksonUtils.serialize2Json(TsfUtils.createTags(tsfCoreProperties)));
|
||||
String ipv4Address = PolarisInetUtils.getIpString(false);
|
||||
if (StringUtils.isNotBlank(ipv4Address)) {
|
||||
put(TSF_ADDRESS_IPV4, ipv4Address);
|
||||
}
|
||||
String ipv6Address = PolarisInetUtils.getIpString(true);
|
||||
if (StringUtils.isNotBlank(ipv6Address)) {
|
||||
put(TSF_ADDRESS_IPV6, ipv6Address);
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
Loading…
Reference in new issue