feat:support TSF router. (#1403)
Co-authored-by: Haotian Zhang <skyebefreeman@qq.com>pull/1404/head
parent
775b66cecb
commit
4487317354
@ -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,76 +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,55 +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.polaris.router.resttemplate.PolarisLoadBalancerInterceptor;
|
|
||||||
|
|
||||||
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.client.loadbalancer.LoadBalancerClient;
|
|
||||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
|
|
||||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replace LoadBalancerInterceptor with PolarisLoadBalancerInterceptor.
|
|
||||||
* PolarisLoadBalancerInterceptor can pass routing context information.
|
|
||||||
*
|
|
||||||
*@author lepdou 2022-05-18
|
|
||||||
*/
|
|
||||||
public class LoadBalancerInterceptorBeanPostProcessor 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 {
|
|
||||||
if (bean instanceof LoadBalancerInterceptor) {
|
|
||||||
LoadBalancerRequestFactory requestFactory = this.factory.getBean(LoadBalancerRequestFactory.class);
|
|
||||||
LoadBalancerClient loadBalancerClient = this.factory.getBean(LoadBalancerClient.class);
|
|
||||||
|
|
||||||
return new PolarisLoadBalancerInterceptor(loadBalancerClient, requestFactory);
|
|
||||||
}
|
|
||||||
return bean;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,72 +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.client.loadbalancer.LoadBalancerProperties;
|
|
||||||
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);
|
|
||||||
LoadBalancerProperties loadBalancerProperties = this.factory.getBean(LoadBalancerProperties.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, loadBalancerProperties,
|
|
||||||
staticMetadataManager, routerRuleLabelResolver, routerLabelResolvers, polarisContextProperties);
|
|
||||||
}
|
|
||||||
return bean;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,98 +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,60 +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 java.io.IOException;
|
|
||||||
import java.net.URI;
|
|
||||||
|
|
||||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
|
||||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
|
|
||||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory;
|
|
||||||
import org.springframework.http.HttpRequest;
|
|
||||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
|
||||||
import org.springframework.http.client.ClientHttpResponse;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor capabilities.
|
|
||||||
* Parses the label from the request and puts it into the RouterContext for routing.
|
|
||||||
*
|
|
||||||
* @author lepdou, cheese8
|
|
||||||
*/
|
|
||||||
public class PolarisLoadBalancerInterceptor extends LoadBalancerInterceptor {
|
|
||||||
|
|
||||||
private final LoadBalancerClient loadBalancer;
|
|
||||||
private final LoadBalancerRequestFactory requestFactory;
|
|
||||||
|
|
||||||
public PolarisLoadBalancerInterceptor(LoadBalancerClient loadBalancer,
|
|
||||||
LoadBalancerRequestFactory requestFactory) {
|
|
||||||
super(loadBalancer, requestFactory);
|
|
||||||
this.loadBalancer = loadBalancer;
|
|
||||||
this.requestFactory = requestFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
|
|
||||||
final URI originalUri = request.getURI();
|
|
||||||
String peerServiceName = originalUri.getHost();
|
|
||||||
Assert.state(peerServiceName != null,
|
|
||||||
"Request URI does not contain a valid hostname: " + originalUri);
|
|
||||||
|
|
||||||
return this.loadBalancer.execute(peerServiceName,
|
|
||||||
new PolarisLoadBalancerRequest<>(request, this.requestFactory.createRequest(request, body, execution)));
|
|
||||||
}
|
|
||||||
}
|
|
@ -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,282 +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 LoadBalancerProperties loadBalancerProperties;
|
|
||||||
private final StaticMetadataManager staticMetadataManager;
|
|
||||||
private final RouterRuleLabelResolver routerRuleLabelResolver;
|
|
||||||
private final List<SpringWebRouterLabelResolver> routerLabelResolvers;
|
|
||||||
private final PolarisContextProperties polarisContextProperties;
|
|
||||||
|
|
||||||
public PolarisReactiveLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory,
|
|
||||||
GatewayLoadBalancerProperties gatewayLoadBalancerProperties,
|
|
||||||
LoadBalancerProperties loadBalancerProperties,
|
|
||||||
StaticMetadataManager staticMetadataManager,
|
|
||||||
RouterRuleLabelResolver routerRuleLabelResolver,
|
|
||||||
List<SpringWebRouterLabelResolver> routerLabelResolvers,
|
|
||||||
PolarisContextProperties polarisContextProperties) {
|
|
||||||
super(clientFactory, gatewayLoadBalancerProperties, loadBalancerProperties);
|
|
||||||
|
|
||||||
this.clientFactory = clientFactory;
|
|
||||||
this.gatewayLoadBalancerProperties = gatewayLoadBalancerProperties;
|
|
||||||
this.loadBalancerProperties = loadBalancerProperties;
|
|
||||||
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, loadBalancerProperties.getHint())));
|
|
||||||
|
|
||||||
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, Map<String, String> hints) {
|
|
||||||
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,95 +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,86 +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.util.BeanFactoryUtils;
|
|
||||||
import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerInterceptor;
|
|
||||||
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.client.loadbalancer.LoadBalancerClient;
|
|
||||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor;
|
|
||||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test for ${@link LoadBalancerInterceptorBeanPostProcessor}.
|
|
||||||
*
|
|
||||||
* @author lepdou 2022-05-26
|
|
||||||
*/
|
|
||||||
@ExtendWith(MockitoExtension.class)
|
|
||||||
public class LoadBalancerInterceptorBeanPostProcessorTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private LoadBalancerClient loadBalancerClient;
|
|
||||||
@Mock
|
|
||||||
private LoadBalancerRequestFactory loadBalancerRequestFactory;
|
|
||||||
@Mock
|
|
||||||
private BeanFactory beanFactory;
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWrapperLoadBalancerInterceptor() {
|
|
||||||
when(beanFactory.getBean(LoadBalancerRequestFactory.class)).thenReturn(loadBalancerRequestFactory);
|
|
||||||
when(beanFactory.getBean(LoadBalancerClient.class)).thenReturn(loadBalancerClient);
|
|
||||||
|
|
||||||
try (MockedStatic<BeanFactoryUtils> mockedBeanFactoryUtils = Mockito.mockStatic(BeanFactoryUtils.class)) {
|
|
||||||
mockedBeanFactoryUtils.when(() -> BeanFactoryUtils.getBeans(beanFactory, SpringWebRouterLabelResolver.class))
|
|
||||||
.thenReturn(null);
|
|
||||||
LoadBalancerInterceptor loadBalancerInterceptor = new LoadBalancerInterceptor(loadBalancerClient, loadBalancerRequestFactory);
|
|
||||||
|
|
||||||
LoadBalancerInterceptorBeanPostProcessor processor = new LoadBalancerInterceptorBeanPostProcessor();
|
|
||||||
processor.setBeanFactory(beanFactory);
|
|
||||||
|
|
||||||
Object bean = processor.postProcessBeforeInitialization(loadBalancerInterceptor, "");
|
|
||||||
|
|
||||||
assertThat(bean).isInstanceOf(PolarisLoadBalancerInterceptor.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNotWrapperLoadBalancerInterceptor() {
|
|
||||||
LoadBalancerInterceptorBeanPostProcessor processor = new LoadBalancerInterceptorBeanPostProcessor();
|
|
||||||
processor.setBeanFactory(beanFactory);
|
|
||||||
|
|
||||||
OtherBean otherBean = new OtherBean();
|
|
||||||
Object bean = processor.postProcessBeforeInitialization(otherBean, "");
|
|
||||||
assertThat(bean).isNotInstanceOf(PolarisLoadBalancerInterceptor.class);
|
|
||||||
assertThat(bean).isInstanceOf(OtherBean.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
static class OtherBean {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,100 +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.client.loadbalancer.LoadBalancerProperties;
|
|
||||||
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 LoadBalancerProperties loadBalancerProperties;
|
|
||||||
@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(LoadBalancerProperties.class)).thenReturn(loadBalancerProperties);
|
|
||||||
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, loadBalancerProperties);
|
|
||||||
|
|
||||||
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,162 +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,201 +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 LoadBalancerProperties loadBalancerProperties;
|
|
||||||
@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, loadBalancerProperties, 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.newLinkedHashSet("${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, loadBalancerProperties, 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);
|
|
||||||
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<String, String>() {{
|
||||||
|
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