Skip to content

Commit

Permalink
Merge pull request #13 from hango-io/release-v1.2
Browse files Browse the repository at this point in the history
support dubbo bridge
  • Loading branch information
ethanhanjiahao authored Jan 5, 2023
2 parents cee315f + 84e03df commit c1a2211
Show file tree
Hide file tree
Showing 45 changed files with 2,083 additions and 792 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ public class GlobalConfig {
@Value("${telnet.connect.timeout:3000}")
private Integer telnetConnectTimeout;

@Value("${customDefaultRespCode:500}")
private int customDefaultRespCode;

public String getResourceNamespace() {
return resourceNamespace;
}
Expand All @@ -40,4 +43,8 @@ public String getApiPlaneVersion() {
public Integer getTelnetConnectTimeout() {
return telnetConnectTimeout;
}

public int getCustomDefaultRespCode() {
return customDefaultRespCode;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.hango.cloud.core.gateway;

import org.apache.commons.lang3.math.NumberUtils;
import org.hango.cloud.core.GlobalConfig;
import org.hango.cloud.core.IstioModelEngine;
import org.hango.cloud.core.editor.EditorContext;
import org.hango.cloud.core.gateway.handler.*;
import org.hango.cloud.core.gateway.processor.DefaultModelProcessor;
import org.hango.cloud.core.gateway.processor.NeverReturnNullModelProcessor;
import org.hango.cloud.core.gateway.processor.RenderTwiceModelProcessor;
Expand All @@ -21,16 +23,8 @@
import org.hango.cloud.service.PluginService;
import org.hango.cloud.util.Const;
import org.hango.cloud.util.constant.LogConstant;
import org.hango.cloud.util.constant.PluginConstant;
import io.fabric8.kubernetes.api.model.HasMetadata;
import istio.networking.v1alpha3.VirtualServiceOuterClass;
import org.hango.cloud.core.gateway.handler.GatewayPluginConfigMapDataHandler;
import org.hango.cloud.core.gateway.handler.GatewayPluginDataHandler;
import org.hango.cloud.core.gateway.handler.PluginOrderDataHandler;
import org.hango.cloud.core.gateway.handler.PortalDestinationRuleServiceDataHandler;
import org.hango.cloud.core.gateway.handler.PortalGatewayDataHandler;
import org.hango.cloud.core.gateway.handler.PortalServiceEntryServiceDataHandler;
import org.hango.cloud.core.gateway.handler.PortalVirtualServiceAPIDataHandler;
import org.hango.cloud.meta.API;
import org.hango.cloud.meta.GatewayPlugin;
import org.hango.cloud.meta.IstioGateway;
Expand All @@ -46,11 +40,9 @@
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Component
public class GatewayIstioModelEngine extends IstioModelEngine {
Expand Down Expand Up @@ -102,6 +94,9 @@ public GatewayIstioModelEngine(IntegratedResourceOperator operator, TemplateTran
private static final String pluginManager = "gateway/pluginManager";
private static final String serviceServiceEntry = "gateway/service/serviceEntry";
private static final String gatewayPlugin = "gateway/gatewayPlugin";
private static final String smartLimiter = "gateway/smartLimiter";
private static final String envoyFilter = "gateway/envoyFilter";
private static final String grpcConfigPatch = "gateway/grpcConfigPatch";
private static final String VIRTUAL_SERVICE = "VirtualService";

public List<K8sResourcePack> translate(API api) {
Expand All @@ -126,6 +121,9 @@ public List<K8sResourcePack> translate(API api, boolean simple) {
.map(FragmentHolder::getVirtualServiceFragment)
.collect(Collectors.toList());
}
if (NumberUtils.INTEGER_ZERO.equals(api.getCustomDefaultRespCode())){
api.setCustomDefaultRespCode(globalConfig.getCustomDefaultRespCode());
}
List<String> rawVirtualServices = renderTwiceModelProcessor
.process(apiVirtualService, api,
new PortalVirtualServiceAPIDataHandler(
Expand Down Expand Up @@ -170,34 +168,39 @@ public List<K8sResourcePack> translate(GatewayPlugin plugin) {
*/
private List<K8sResourcePack> generateAndAddK8sResource(RawResourceContainer rawResourceContainer,
GatewayPlugin plugin) {
// 插件渲染GatewayPlugin资源
logger.info("{}{} start render raw GatewayPlugin CRDs",
// 插件渲染网关插件CR资源
logger.info("{}{} start render raw Plugin CRs",
LogConstant.TRANSLATE_LOG_NOTE, LogConstant.PLUGIN_LOG_NOTE);
List<K8sResourcePack> resourcePacks = configureGatewayPlugin(rawResourceContainer, plugin);

// 路由级别的限流插件要渲染ConfigMap资源
if (isNeedToRenderConfigMap(plugin)) {
logger.info("{}{} start render raw ConfigMap CRDs",
LogConstant.TRANSLATE_LOG_NOTE, LogConstant.PLUGIN_LOG_NOTE);
configureRateLimitConfigMap(rawResourceContainer, resourcePacks, plugin);
}
// 渲染EnvoyPlugin和SmartPlugin资源
List<K8sResourcePack> envoyPlugins = configureEnvoyPlugin(rawResourceContainer, plugin);
List<K8sResourcePack> smartLimiters = configureSmartLimiter(rawResourceContainer, plugin);

return resourcePacks;
// 聚合插件CR资源
return Stream.of(envoyPlugins, smartLimiters)
.flatMap(Collection::stream)
.collect(Collectors.toList());
}

/**
* 插件流程只有两个场景需要渲染ConfigMap资源
* 1.路由级别的限流插件
* 2.没有传插件类型,即批量操作的场景,此时可能会有限流插件,因此需要无差别渲染(匹配路由启用、禁用、下线场景)
* 注:限流插件只有路由级别,因此路由插件是先决条件
* 插件转换为SmartLimiter CRD资源
*
* @param plugin 网关插件实例(内含插件配置)
* @return 是否需要渲染ConfigMap资源
* @param rawResourceContainer 存放资源的容器对象
* @param plugin 插件对象
* @return k8s资源集合
*/
private boolean isNeedToRenderConfigMap(GatewayPlugin plugin) {
return plugin.isRoutePlugin() &&
(StringUtils.isEmpty(plugin.getPluginType()) || plugin.getPluginType().equals(
PluginConstant.RATE_LIMIT_PLUGIN_TYPE));
private List<K8sResourcePack> configureSmartLimiter(RawResourceContainer rawResourceContainer,
GatewayPlugin plugin) {
List<K8sResourcePack> resourcePacks = new ArrayList<>();
// 将插件配置转换为SmartLimiters
List<String> rawSmartLimiters = defaultModelProcessor.process(smartLimiter, plugin,
new SmartLimiterDataHandler(rawResourceContainer.getSmartLimiters(), globalConfig.getResourceNamespace()));

resourcePacks.addAll(generateK8sPack(rawSmartLimiters));
logger.info("{}{} raw SmartLimiter CRs added ok",
LogConstant.TRANSLATE_LOG_NOTE, LogConstant.PLUGIN_LOG_NOTE);

return resourcePacks;
}

/**
Expand All @@ -207,8 +210,8 @@ private boolean isNeedToRenderConfigMap(GatewayPlugin plugin) {
* @param plugin 插件对象
* @return k8s资源集合
*/
private List<K8sResourcePack> configureGatewayPlugin(RawResourceContainer rawResourceContainer,
GatewayPlugin plugin) {
private List<K8sResourcePack> configureEnvoyPlugin(RawResourceContainer rawResourceContainer,
GatewayPlugin plugin) {
List<K8sResourcePack> resourcePacks = new ArrayList<>();
// 插件配置放在GatewayPlugin的CRD上
List<String> rawGatewayPlugins = renderTwiceModelProcessor.process(gatewayPlugin, plugin,
Expand All @@ -229,28 +232,6 @@ private List<K8sResourcePack> configureGatewayPlugin(RawResourceContainer rawRes
return resourcePacks;
}

/**
* 限流插件转换为ConfigMap CRD资源
*
* @param rawResourceContainer 存放资源的容器对象
* @param resourcePacks k8s资源集合
* @param plugin 插件对象
*/
private void configureRateLimitConfigMap(RawResourceContainer rawResourceContainer,
List<K8sResourcePack> resourcePacks,
GatewayPlugin plugin) {
// 限流插件需要额外的configMap配置
List<String> rawConfigMaps = neverNullRenderTwiceProcessor.process(rateLimitConfigMap, plugin,
new GatewayPluginConfigMapDataHandler(
rawResourceContainer.getSharedConfigs(), rateLimitConfigMapName, rateLimitNamespace));
// 加入限流插件configMap配置
resourcePacks.addAll(generateK8sPack(rawConfigMaps,
new GatewayRateLimitConfigMapMerger(),
new GatewayRateLimitConfigMapSubtracter(plugin.getGateway(), plugin.getRouteId()),
new EmptyResourceGenerator(new EmptyConfigMap(rateLimitConfigMapName, rateLimitNamespace))));
logger.info("{}{} raw ConfigMap CRDs added ok", LogConstant.TRANSLATE_LOG_NOTE, LogConstant.PLUGIN_LOG_NOTE);
}

public List<K8sResourcePack> translate(Service service) {
List<K8sResourcePack> resources = new ArrayList<>();
List<String> destinations = defaultModelProcessor.process(serviceDestinationRule, service, new PortalDestinationRuleServiceDataHandler());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class RawResourceContainer {
List<FragmentWrapper> virtualServices = new ArrayList<>();
List<FragmentWrapper> sharedConfigs = new ArrayList<>();
List<FragmentWrapper> gatewayPlugins = new ArrayList<>();
List<FragmentWrapper> smartLimiters = new ArrayList<>();

public void add(FragmentHolder holder) {

Expand All @@ -26,6 +27,10 @@ public void add(FragmentHolder holder) {
if (holder.getGatewayPluginsFragment() != null) {
gatewayPlugins.add(holder.getGatewayPluginsFragment());
}

if (holder.getSmartLimiterFragment() != null) {
smartLimiters.addAll(holder.getSmartLimiterFragment());
}
}

public void add(List<FragmentHolder> holders) {
Expand All @@ -44,4 +49,8 @@ public List<FragmentWrapper> getSharedConfigs() {
public List<FragmentWrapper> getGatewayPlugins() {
return gatewayPlugins;
}

public List<FragmentWrapper> getSmartLimiters() {
return smartLimiters;
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
package org.hango.cloud.core.gateway.handler;

import com.fasterxml.jackson.core.JsonProcessingException;
import me.snowdrop.istio.api.networking.v1alpha3.VirtualService;
import org.apache.commons.lang3.StringEscapeUtils;
import org.hango.cloud.core.gateway.handler.meta.UriMatchMeta;
import org.hango.cloud.core.template.TemplateParams;
import org.hango.cloud.meta.API;
import org.hango.cloud.meta.CRDMetaEnum;
import org.hango.cloud.meta.PairMatch;
import org.hango.cloud.meta.UriMatch;
import org.hango.cloud.meta.dto.DubboInfoDto;
import org.hango.cloud.util.CommonUtil;
import org.hango.cloud.util.PriorityUtil;
import org.apache.commons.lang3.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static org.hango.cloud.core.template.TemplateConst.*;

public abstract class APIDataHandler implements DataHandler<API> {

private static final Logger logger = LoggerFactory.getLogger(APIDataHandler.class);

@Override
public List<TemplateParams> handle(API api) {
TemplateParams tp = handleApi(api);
Expand Down Expand Up @@ -75,11 +85,83 @@ public TemplateParams handleApi(API api) {
.put(VIRTUAL_SERVICE_REQUEST_HEADERS, api.getRequestOperation())
.put(VIRTUAL_SERVICE_VIRTUAL_CLUSTER_NAME, api.getVirtualClusterName())
.put(VIRTUAL_SERVICE_VIRTUAL_CLUSTER_HEADERS, getVirtualClusterHeaders(api))
.put(VIRTUAL_SERVICE_STATS, api.getStatsMeta());
.put(VIRTUAL_SERVICE_RESP_EXCEPTION_CODE, api.getCustomDefaultRespCode())
;

return handleApiMetaMap(api,tp);
}

/**
* 处理VirtualService metadata 数据
*
* @param api 上层输入的API数据
* @param tp 模板参数
* @return TemplateParams
*/
private TemplateParams handleApiMetaMap(API api, TemplateParams tp) {
if (CollectionUtils.isEmpty(api.getMetaMap())) {
return tp;
}
Iterator<Map.Entry<String, String>> iterator = api.getMetaMap().entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> next = iterator.next();
handleApiMeta(next.getKey(), next.getValue(), tp);
}
return tp;
}

/**
* 处理VirtualService metadata 数据
*
* @param name 上层输入的metadata类型
* @param value 上层输入的metadata数据
* @param tp 模板参数
* @return TemplateParams
*/
private TemplateParams handleApiMeta(String name, String value, TemplateParams tp) {
CRDMetaEnum metaEnum = CRDMetaEnum.get(VirtualService.class, name);
if (metaEnum == null) {
logger.warn("find null meta enum ,please check input content , target class is {} , name is {} ", VirtualService.class, name);
return tp;
}
try {
switch (metaEnum) {
case VIRTUAL_SERVICE_STATS_META:
tp.put(metaEnum.getTemplateName(), metaEnum.getTransData(value));
break;
case VIRTUAL_SERVICE_DUBBO_META:
handleDubboMeta(tp, metaEnum.getTransData(value));
break;
default:
break;
}
} catch (JsonProcessingException e) {
logger.warn("meta content parse failed , errMsg is {}", e.getMessage());
}
return tp;
}

/**
* 将Dubbo meta 元数据信息加入模板参数中
*
* @param tp 模板参数
* @param info dubbo meta信息
* @return TemplateParams
*/
private TemplateParams handleDubboMeta(TemplateParams tp, DubboInfoDto info) {
tp.put(VIRTUAL_SERVICE_DUBBO_META_SERVICE, info.getInterfaceName())
.put(VIRTUAL_SERVICE_DUBBO_META_VERSION, info.getVersion())
.put(VIRTUAL_SERVICE_DUBBO_META_METHOD, info.getMethod())
.put(VIRTUAL_SERVICE_DUBBO_META_GROUP, info.getGroup())
.put(VIRTUAL_SERVICE_DUBBO_META_SOURCE, info.getParamSource())
.put(VIRTUAL_SERVICE_DUBBO_META_PARAMS, info.getParams())
.put(VIRTUAL_SERVICE_DUBBO_META_ATTACHMENTS, info.getDubboAttachment())
;
return tp;
}



protected String getOrDefault(String value, String defaultValue) {
return StringUtils.isEmpty(value) ? defaultValue : value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,55 +41,27 @@ public List<TemplateParams> handle(GatewayPlugin plugin) {
Map<String, List<String>> gatewayPluginMap = HandlerUtil.getGatewayPlugins(fragments);
TemplateParams gatewayPluginParams = TemplateParams.instance()
.put(TemplateConst.GATEWAY_PLUGIN_GATEWAYS, getGatewayName(plugin))
.put(TemplateConst.GATEWAY_PLUGIN_NAME, getGatewayPluginName(plugin))
.put(TemplateConst.GATEWAY_PLUGIN_NAME, HandlerUtil.getGatewayPluginName(plugin))
.put(TemplateConst.GATEWAY_PLUGIN_PLUGINS, gatewayPluginMap);

// 路由和全局插件模板渲染数据区分填充
if (plugin.isRoutePlugin()) {
gatewayPluginParams
.put(TemplateConst.GATEWAY_PLUGIN_ROUTES, getRouteList(plugin))
.put(TemplateConst.RESOURCE_IDENTITY, getIdentity(plugin))
.put(TemplateConst.GATEWAY_PLUGIN_ROUTES, HandlerUtil.getRouteList(plugin))
.put(TemplateConst.RESOURCE_IDENTITY, HandlerUtil.getIdentity(plugin))
.put(TemplateConst.SERVICE_INFO_API_SERVICE, PluginConstant.DEFAULT_SERVICE_NAME)
.put(TemplateConst.SERVICE_INFO_API_GATEWAY, plugin.getGateway())
.put(TemplateConst.SERVICE_INFO_API_NAME, plugin.getRouteId());
} else if (plugin.isGlobalPlugin()) {
if (!CollectionUtils.isEmpty(plugin.getHosts())){
Integer port = plugin.getPort();
List<String> hosts = plugin.getHosts().stream().map(host -> host + ":" + port).collect(Collectors.toList());
plugin.setHosts(hosts);
}
gatewayPluginParams.put(TemplateConst.GATEWAY_PLUGIN_HOSTS, plugin.getHosts());
gatewayPluginParams.put(TemplateConst.GATEWAY_PLUGIN_HOSTS, HandlerUtil.completeHosts(plugin));
}

params.addAll(Arrays.asList((gatewayPluginParams)));

return params;
}

private String getIdentity(GatewayPlugin plugin) {
return String.format("%s-%s", plugin.getRouteId(), plugin.getGateway());
}

private List<String> getRouteList(GatewayPlugin plugin) {
final String routeId = plugin.getRouteId();
Integer port = plugin.getPort();
return plugin.getHosts().stream()
.map(host -> host + ":"+ port + "/" + routeId)
.collect(Collectors.toList());
}

private List<String> getGatewayName(GatewayPlugin plugin) {
return Collections.singletonList(String.format("%s/%s", gatewayNamespace, plugin.getGateway()));
}

private String getGatewayPluginName(GatewayPlugin plugin) {
String pluginName = PluginConstant.DEFAULT_PLUGIN_NAME;

if (plugin.isRoutePlugin()) {
pluginName = plugin.getRouteId() + "-" + plugin.getGateway();
} else if (plugin.isGlobalPlugin()) {
pluginName = plugin.getCode().toLowerCase();
}
return pluginName;
}
}
Loading

0 comments on commit c1a2211

Please sign in to comment.