Skip to content

Commit

Permalink
Merge pull request sermant-io#1317 from provenceee/global-router
Browse files Browse the repository at this point in the history
增加全局路由规则
  • Loading branch information
Sherlockhan authored Sep 22, 2023
2 parents 6dd5d2e + 10bed08 commit 2ed4003
Show file tree
Hide file tree
Showing 13 changed files with 232 additions and 13 deletions.
2 changes: 2 additions & 0 deletions sermant-plugins/sermant-router/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ router.plugin:
request-tags: []
# 需要解析的请求头的tag
parse-header-tag: ''
# 区域路由默认策略,全部生效:ALL 全不生效:NONE 白名单策略:WHITE 黑名单策略:BLACK
zone-router-default-strategy: NONE
transmit.plugin:
# 是否在直接new Thread时传递标签
enabled-thread: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ private void putAttachment(Object invocation) {
private List<Object> getTargetInvokersByRules(List<Object> invokers, Object invocation,
Map<String, String> queryMap, String targetService, String serviceInterface) {
RouterConfiguration configuration = ConfigCache.getLabel(RouterConstant.DUBBO_CACHE_NAME);
if (RouterConfiguration.isInValid(configuration)) {
if (RouterConfiguration.isInValid(configuration, targetService)) {
return invokers;
}
String interfaceName = getGroup(queryMap) + "/" + serviceInterface + POINT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ public class RouterConfig implements PluginConfig {
@ConfigFieldKey("parse-header-tag")
private String parseHeaderTag;

/**
* 区域路由默认策略
*/
@ConfigFieldKey("zone-router-default-strategy")
private String zoneRouterDefaultStrategy = "NONE";

/**
* 构造方法
*/
Expand Down Expand Up @@ -195,4 +201,12 @@ public String getParseHeaderTag() {
public void setParseHeaderTag(String parseHeaderTag) {
this.parseHeaderTag = parseHeaderTag;
}

public String getZoneRouterDefaultStrategy() {
return zoneRouterDefaultStrategy;
}

public void setZoneRouterDefaultStrategy(String zoneRouterDefaultStrategy) {
this.zoneRouterDefaultStrategy = zoneRouterDefaultStrategy;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ public class RouterConstant {
*/
public static final String ZONE_KEY = "service.meta.zone";

/**
* 全局标签路由key
*/
public static final String GLOBAL_ROUTER_KEY = "servicecomb.globalRouteRule";

private RouterConstant() {
}
}
10 changes: 10 additions & 0 deletions sermant-plugins/sermant-router/router-config-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,15 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@

package com.huaweicloud.sermant.router.config.entity;

import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager;
import com.huaweicloud.sermant.router.common.config.RouterConfig;

import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CopyOnWriteArrayList;

/**
Expand All @@ -32,10 +36,24 @@ public class EnabledStrategy {
*/
private final List<String> value = new CopyOnWriteArrayList<>();

/**
* 默认策略
*/
private final Strategy defaultStrategy;

/**
* 开启策略
*/
private Strategy strategy = Strategy.NONE;
private Strategy strategy;

/**
* 构造方法
*/
public EnabledStrategy() {
RouterConfig routerConfig = PluginConfigManager.getPluginConfig(RouterConfig.class);
defaultStrategy = Strategy.valueOf(routerConfig.getZoneRouterDefaultStrategy().toUpperCase(Locale.ROOT));
strategy = defaultStrategy;
}

public Strategy getStrategy() {
return strategy;
Expand All @@ -49,7 +67,7 @@ public List<String> getValue() {
* 重置配置
*/
public void reset() {
reset(Strategy.NONE, Collections.emptyList());
reset(defaultStrategy, Collections.emptyList());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@

import com.huaweicloud.sermant.router.common.utils.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
* 路由标签
Expand All @@ -34,10 +36,32 @@ public class RouterConfiguration {
*/
private final Map<String, List<Rule>> routeRule = new ConcurrentHashMap<>();

/**
* 全局路由规则
*/
private final List<Rule> globalRules = new CopyOnWriteArrayList<>();

public Map<String, List<Rule>> getRouteRule() {
return routeRule;
}

public List<Rule> getGlobalRules() {
return globalRules;
}

/**
* 获取指定服务的路由规则
*
* @param serviceName 服务名
* @return 路由规则
*/
public List<Rule> getRules(String serviceName) {
if (CollectionUtils.isEmpty(routeRule) && CollectionUtils.isEmpty(globalRules)) {
return Collections.emptyList();
}
return routeRule.getOrDefault(serviceName, globalRules);
}

/**
* 重置路由规则
*
Expand All @@ -48,13 +72,35 @@ public void resetRouteRule(Map<String, List<Rule>> map) {
routeRule.putAll(map);
}

/**
* 重置全局路由规则
*
* @param rules 全局路由规则
*/
public void resetGlobalRules(List<Rule> rules) {
globalRules.clear();
globalRules.addAll(rules);
}

/**
* 路由规则是否无效
*
* @param configuration 路由规则
* @return 是否无效
*/
public static boolean isInValid(RouterConfiguration configuration) {
return configuration == null || CollectionUtils.isEmpty(configuration.getRouteRule());
return configuration == null || (CollectionUtils.isEmpty(configuration.getRouteRule())
&& CollectionUtils.isEmpty(configuration.getGlobalRules()));
}

/**
* 路由规则是否无效
*
* @param configuration 路由规则
* @param serviceName 服务名
* @return 是否无效
*/
public static boolean isInValid(RouterConfiguration configuration, String serviceName) {
return configuration == null || CollectionUtils.isEmpty(configuration.getRules(serviceName));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,7 @@ private RuleUtils() {
*/
public static List<Rule> getRules(RouterConfiguration configuration, String targetService, String path,
String serviceName) {
if (RouterConfiguration.isInValid(configuration)) {
return Collections.emptyList();
}
Map<String, List<Rule>> routeRule = configuration.getRouteRule();
if (CollectionUtils.isEmpty(routeRule)) {
return Collections.emptyList();
}
List<Rule> rules = routeRule.get(targetService);
List<Rule> rules = configuration.getRules(targetService);
if (CollectionUtils.isEmpty(rules)) {
return Collections.emptyList();
}
Expand Down Expand Up @@ -125,6 +118,7 @@ public static void initMatchKeys(RouterConfiguration configuration) {
for (List<Rule> rules : routeRules.values()) {
addKeys(rules, MATCH_KEYS);
}
addKeys(configuration.getGlobalRules(), MATCH_KEYS);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,15 @@

package com.huaweicloud.sermant.router.config.entity;

import com.huaweicloud.sermant.core.plugin.config.PluginConfigManager;
import com.huaweicloud.sermant.router.common.config.RouterConfig;

import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;

import java.util.Collections;

Expand All @@ -28,6 +35,26 @@
* @since 2022-10-10
*/
public class EnabledStrategyTest {
private static MockedStatic<PluginConfigManager> mockPluginConfigManager;

/**
* 初始化
*/
@BeforeClass
public static void init() {
RouterConfig config = new RouterConfig();
mockPluginConfigManager = Mockito.mockStatic(PluginConfigManager.class);
mockPluginConfigManager.when(() -> PluginConfigManager.getPluginConfig(RouterConfig.class)).thenReturn(config);
}

/**
* 清除mock
*/
@AfterClass
public static void clear() {
mockPluginConfigManager.close();
}


/**
* 测试reset方法
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (C) 2023-2023 Huawei Technologies Co., Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.huaweicloud.sermant.router.config.handler;

import com.huaweicloud.sermant.core.service.dynamicconfig.common.DynamicConfigEvent;
import com.huaweicloud.sermant.core.service.dynamicconfig.common.DynamicConfigEventType;
import com.huaweicloud.sermant.core.utils.StringUtils;
import com.huaweicloud.sermant.router.common.constants.RouterConstant;
import com.huaweicloud.sermant.router.common.utils.CollectionUtils;
import com.huaweicloud.sermant.router.config.cache.ConfigCache;
import com.huaweicloud.sermant.router.config.entity.RouterConfiguration;
import com.huaweicloud.sermant.router.config.entity.Rule;
import com.huaweicloud.sermant.router.config.utils.RuleUtils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
* 全局标签路由
*
* @author provenceee
* @since 2023-09-20
*/
public class GlobalConfigHandler extends AbstractConfigHandler {
@Override
public void handle(DynamicConfigEvent event, String cacheName) {
RouterConfiguration configuration = ConfigCache.getLabel(cacheName);
if (event.getEventType() == DynamicConfigEventType.DELETE) {
configuration.resetGlobalRules(Collections.emptyList());
RuleUtils.initMatchKeys(configuration);
return;
}
List<Rule> rules = JSONArray.parseArray(JSONObject.toJSONString(getRuleMap(event)), Rule.class);
RuleUtils.removeInvalidRules(rules);
if (CollectionUtils.isEmpty(rules)) {
configuration.resetGlobalRules(Collections.emptyList());
} else {
rules.sort((o1, o2) -> o2.getPrecedence() - o1.getPrecedence());
configuration.resetGlobalRules(rules);
}
RuleUtils.initMatchKeys(configuration);
}

@Override
public boolean shouldHandle(String key) {
return RouterConstant.GLOBAL_ROUTER_KEY.equals(key);
}

private List<Map<String, Object>> getRuleMap(DynamicConfigEvent event) {
String content = event.getContent();
if (StringUtils.isBlank(content)) {
return Collections.emptyList();
}
Map<String, List<Map<String, Object>>> ruleMap = yaml.load(content);
return ruleMap.get(RouterConstant.GLOBAL_ROUTER_KEY);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.huaweicloud.sermant.core.service.dynamicconfig.common.DynamicConfigListener;
import com.huaweicloud.sermant.router.config.handler.AbstractConfigHandler;
import com.huaweicloud.sermant.router.config.handler.EnabledStrategyHandler;
import com.huaweicloud.sermant.router.config.handler.GlobalConfigHandler;
import com.huaweicloud.sermant.router.config.handler.RouterConfigHandler;
import com.huaweicloud.sermant.router.config.handler.ServiceConfigHandler;

Expand Down Expand Up @@ -53,6 +54,7 @@ public RouterConfigListener(String cacheName) {
this.handlers.add(new RouterConfigHandler());
this.handlers.add(new ServiceConfigHandler());
this.handlers.add(new EnabledStrategyHandler());
this.handlers.add(new GlobalConfigHandler());
}

@Override
Expand Down
Loading

0 comments on commit 2ed4003

Please sign in to comment.