1、版本号修改为2.1.0

2、增加网关流水线
This commit is contained in:
raoxiaoyan 2020-12-01 18:07:50 +08:00
parent 01998df98d
commit 6212311f68
15 changed files with 249 additions and 30 deletions

View File

@ -1,7 +1,7 @@
# kongx
kongx(最新版本2.0.1)是网关kong的可视化界面管理平台(参考konga的部分界面布局方式),能够集中化管理应用不同环境的网关配置,提供同步各环境的网关配置功能,并且具备规范的权限管理、参数配置、环境管理及日志审计等特性。
kongx(最新版本2.1.0)是网关kong的可视化界面管理平台(参考konga的部分界面布局方式),能够集中化管理应用不同环境的网关配置,提供同步各环境的网关配置功能,并且具备规范的权限管理、参数配置、环境管理及日志审计等特性。
基于Spring Boot和Spring Cloud开发打包后可以直接运行不需要额外安装Tomcat等应用容器支持在线Shell。
@ -11,6 +11,8 @@ Kongx 使用指南请参考:[Wiki](https://www.kancloud.cn/raoxiaoyan/kongx/19
Docker部署(2.0.0+支持)请参见[Docker Quick Start](./docker-quick-start/readme.md)
可视化设计网关pipeline使用文档请参考[网关流水线]()
演示地址http://49.232.174.106/ (用户名: guest/123456)
系统环境默认用户admin/123456(部署登录后,请前往'个人设置'页面,及时修改密码)
@ -19,12 +21,10 @@ Docker部署(2.0.0+支持)请参见[Docker Quick Start](./docker-quick-start/rea
![](./docs/kong%20shell.png)
![](./docs/services.png)
![](./docs/service1.png)
![](./docs/service2.png)
![可视化网关流水线](./docs/pipeline.png)
![](./docs/consumers.png)
![](./docs/certificate.png)
@ -33,6 +33,7 @@ Docker部署(2.0.0+支持)请参见[Docker Quick Start](./docker-quick-start/rea
## Features
- Kong Manage:Upstream,Service,Route,Plugin,Consumer,Certificates及Ca Certificates等
- 新增网关流水线
- 同步Kong配置:不同环境间的kong配置进行同步便于多环境配置管理
- 系统管理:具有完善的权限管理系统,包括:用户管理、菜单管理、角色管理及用户组管理等功能;
- 参数管理:具有良好的扩展性,基于平台的参数管理可扩展多环境及服务管理;包括:环境管理、参数参数等
@ -48,6 +49,8 @@ Docker部署(2.0.0+支持)请参见[Docker Quick Start](./docker-quick-start/rea
- [Kong与consul自主发现服务](https://www.kancloud.cn/raoxiaoyan/kongx/1984357)
- 如何应用灰度插件(canary)及使用场景介绍
- kong插件开发实践
- [kong的健康检查及熔断](https://www.kancloud.cn/raoxiaoyan/kongx/2044771)
- kong网关流水线
- 整理中...尽情期待
@ -69,8 +72,8 @@ Docker部署(2.0.0+支持)请参见[Docker Quick Start](./docker-quick-start/rea
</thead>
<tbody>
<tr>
<td><img src="https://raw.githubusercontent.com/raoxiaoyan/kongx/master/docs/kongx_tech1.png" alt="tech-support-qq-1"></td>
<td><img src="https://raw.githubusercontent.com/raoxiaoyan/kongx/master/docs/cooperate.jpg" alt="cooperate" width="230px;"></td>
<td><img src="./docs/kongx_tech1.png" alt="tech-support-qq-1"></td>
<td><img src="./docs/cooperate.jpg" alt="cooperate" width="230px;"></td>
</tr>
</tbody>
</table>
@ -81,6 +84,7 @@ Docker部署(2.0.0+支持)请参见[Docker Quick Start](./docker-quick-start/rea
| --- | --- | --- | --- |
| 1 | 1.2.x | 1.2.x | 1.2.x测试|
| 1 | 2.0.0 | 1.2.x、1.3.x、1.4.x、1.5.x、2.0.x | 目前仅针对kong版本1.2.x、1.3.x测试通过,对1.4.x以上版本与1.3.x对比差异原则上基础功能全部可用(参考差异对比)[https://www.kancloud.cn/raoxiaoyan/kongx/1991178]|
| 1 | 2.1.0 | 1.2.x、1.3.x、1.4.x、1.5.x、2.0.x | 目前仅针对kong版本1.2.x、1.3.x测试通过,对1.4.x以上版本与1.3.x对比差异原则上基础功能全部可用(参考差异对比)[https://www.kancloud.cn/raoxiaoyan/kongx/1991178]|
## Upgrade
[更新历史](docs/upgrade.md)

BIN
docs/pipeline.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>kongx</artifactId>
<groupId>com.kongx</groupId>
<version>2.0.2</version>
<version>2.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -183,9 +183,7 @@ public class JsonHeaderWrapper<T extends Object> {
Success(0, "全部成功"), //
Success4M(200, "全部成功"),
//无线端统一使用200作为成功代码返回
PartialSuccess(202, "库存数不足"), //
Timeout(405, "接口超时返回"), //
OverFlowCtrl(406, "客户流量超量"), //
NOT_FOUND(404, "not found"),
Failed(500, "全部失败"), //
ParamError(505, "传入参数错误"), //
UnknownOther(599, "未知错误,系统错误");

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>kongx</artifactId>
<groupId>com.kongx</groupId>
<version>2.0.2</version>
<version>2.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -14,7 +14,7 @@
<dependency>
<groupId>com.kongx</groupId>
<artifactId>kongx-common</artifactId>
<version>2.0.2</version>
<version>2.1.0</version>
</dependency>
<dependency>

View File

@ -1,28 +1,175 @@
package com.kongx.serve.controller.flow;
import com.fasterxml.jackson.core.type.TypeReference;
import com.kongx.common.core.entity.UserInfo;
import com.kongx.common.jsonwrapper.JsonHeaderWrapper;
import com.kongx.common.utils.Jackson2Helper;
import com.kongx.serve.controller.system.DefaultController;
import com.kongx.serve.entity.flow.FlowNode;
import com.kongx.serve.entity.flow.NodeMeta;
import com.kongx.serve.entity.flow.ServicePipeline;
import com.kongx.serve.entity.gateway.KongEntity;
import com.kongx.serve.entity.gateway.TargetHealth;
import com.kongx.serve.entity.system.OperationLog;
import com.kongx.serve.entity.system.SystemProfile;
import com.kongx.serve.service.IBaseService;
import com.kongx.serve.service.flow.ServicePipelineService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.kongx.serve.service.gateway.TargetService;
import com.kongx.serve.service.gateway.TruncateEntityService;
import com.kongx.serve.service.system.SystemProfileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController("/ServiceFlowController")
@RequestMapping("/kong/api/pipeline")
public class ServicePipelineController extends DefaultController<ServicePipeline, Integer> {
@Resource(name = "servicePipelineService")
@Autowired
private TruncateEntityService truncateEntityService;
@Autowired
private ServicePipelineService servicePipelineService;
@Autowired
private TargetService targetService;
@Autowired
private SystemProfileService systemProfileService;
@Override
@Resource(name = "servicePipelineService")
protected void setBaseService(IBaseService<ServicePipeline, Integer> iBaseService) {
this.baseService = iBaseService;
}
@RequestMapping(value = "/list/profile", method = RequestMethod.GET)
public List<ServicePipeline> findAll(UserInfo userInfo, ServicePipeline project) {
return servicePipelineService.findAll(this.systemProfile(userInfo), project);
}
@RequestMapping(path = "/truncate/entity", method = RequestMethod.POST)
public JsonHeaderWrapper<ServicePipeline> removeEntity(UserInfo userInfo, @RequestBody FlowNode flowNode) {
JsonHeaderWrapper jsonHeaderWrapper = this.init();
try {
if (!flowNode.getMeta().isReady()) {
jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode());
jsonHeaderWrapper.setErrmsg("该实体未进行配置,请检查后再试!");
return jsonHeaderWrapper;
}
this.truncateEntityService.remove(this.systemProfile(userInfo), this.wrapUri(flowNode));
} catch (Exception e) {
String content = e.getMessage();
if (content.contains("Not found")) {
jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.NOT_FOUND.getCode());
} else {
jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode());
}
jsonHeaderWrapper.setErrmsg(content);
}
return jsonHeaderWrapper;
}
@RequestMapping(path = "/{id}", method = RequestMethod.GET)
@Override
public JsonHeaderWrapper findById(UserInfo userInfo, @PathVariable Integer id) {
JsonHeaderWrapper jsonHeaderWrapper = init();
try {
ServicePipeline servicePipeline = this.servicePipelineService.findById(id);
SystemProfile systemProfile = this.systemProfileService.findByProfile(servicePipeline.getProfile());
List<FlowNode> flowNodeList = Jackson2Helper.jsonToList(Jackson2Helper.toJsonString(servicePipeline.getNodeList()), FlowNode.class);
KongEntity<TargetHealth> kongEntity = null;
for (FlowNode flowNode : flowNodeList) {
if (flowNode.getMeta().isReady()) {
this.wrapFlowNode(systemProfile, flowNode, kongEntity);
}
}
servicePipeline.setNodeList(flowNodeList);
jsonHeaderWrapper.setData(servicePipeline);
} catch (Exception e) {
jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode());
jsonHeaderWrapper.setErrmsg(e.getMessage());
}
return jsonHeaderWrapper;
}
private FlowNode wrapFlowNode(SystemProfile systemProfile, FlowNode flowNode, KongEntity<TargetHealth> kongEntity) {
try {
if (flowNode.getMeta().getProp().equals("targets")) {
if (kongEntity == null) {
kongEntity = Jackson2Helper.parsonObject(
Jackson2Helper.toJsonString(this.targetService.findAllHealth(systemProfile, flowNode.getMeta().getParent().getId())),
new TypeReference<KongEntity<TargetHealth>>() {
});
}
for (TargetHealth datum : kongEntity.getData()) {
if (datum.getId().equals(flowNode.getMeta().getId())) {
flowNode.getMeta().setEntity(Jackson2Helper.parsonObject(Jackson2Helper.toJsonString(datum), new TypeReference<Map>() {
}));
return flowNode;
}
}
flowNode.getMeta().setReady(false);
Map parent = new HashMap();
parent.put("id", flowNode.getMeta().getParent().getId());
flowNode.getMeta().setEntity(parent);
} else {
String uri = this.wrapUri(flowNode);
flowNode.getMeta().setEntity(this.truncateEntityService.findById(systemProfile, uri));
}
} catch (Exception e) {
flowNode.getMeta().setReady(false);
if (flowNode.getMeta().getParent() != null) {
Map parent = new HashMap();
parent.put("id", flowNode.getMeta().getParent().getId());
flowNode.getMeta().setEntity(parent);
}
}
return flowNode;
}
private String wrapUri(FlowNode flowNode) {
String url = flowNode.getMeta().getProp();
String id = flowNode.getMeta().getId();
if ("targets".equals(url)) {
NodeMeta parent = flowNode.getMeta().getParent();
url = "/" + parent.getProp() + "/%s/" + url + "/%s";
url = String.format(url, parent.getId(), id);
} else {
url = "/" + url + "/%s";
url = String.format(url, id);
}
return url;
}
@RequestMapping(path = "/query/entity", method = RequestMethod.POST)
public JsonHeaderWrapper<Map> findEntityById(UserInfo userInfo, @RequestBody FlowNode flowNode) {
JsonHeaderWrapper jsonHeaderWrapper = this.init();
try {
if (!flowNode.getMeta().isReady()) {
jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode());
jsonHeaderWrapper.setErrmsg("该实体未进行配置,请检查后再试!");
return jsonHeaderWrapper;
}
jsonHeaderWrapper.setData(this.truncateEntityService.findById(this.systemProfile(userInfo), this.wrapUri(flowNode)));
} catch (Exception e) {
String content = e.getMessage();
if (content.contains("Not found")) {
jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.NOT_FOUND.getCode());
jsonHeaderWrapper.setErrmsg("该实体可能已被移除,请检查后再试!");
} else {
jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode());
jsonHeaderWrapper.setErrmsg(content);
}
}
return jsonHeaderWrapper;
}
@Override
protected OperationLog.OperationTarget operationTarget() {
return OperationLog.OperationTarget.SERVICE_PIPELINE;

View File

@ -62,7 +62,6 @@ public class TargetController extends BaseController {
try {
jsonHeaderWrapper.setData(this.targetFeignService.add(systemProfile(userInfo), id, target));
} catch (Exception e) {
e.printStackTrace();
jsonHeaderWrapper.setStatus(JsonHeaderWrapper.StatusEnum.Failed.getCode());
jsonHeaderWrapper.setErrmsg(e.getMessage());
}
@ -77,7 +76,7 @@ public class TargetController extends BaseController {
* @throws URISyntaxException
*/
@RequestMapping(value = TARGET_URI_ID_PATH, method = RequestMethod.DELETE)
@KongLog(target = OperationLog.OperationTarget.TARGETS, content = "#id 从属于上游服务 #upstreamId")
@KongLog(target = OperationLog.OperationTarget.TARGETS, content = "#id")
public JsonHeaderWrapper remove(UserInfo userInfo, @PathVariable String upstreamId, @PathVariable String id) {
JsonHeaderWrapper jsonHeaderWrapper = init();
try {

View File

@ -67,7 +67,7 @@ public abstract class DefaultController<T, PK> extends BaseController {
}
@RequestMapping(path = "/{id}", method = RequestMethod.GET)
public JsonHeaderWrapper findById(@PathVariable Integer id) {
public JsonHeaderWrapper findById(UserInfo userInfo, @PathVariable Integer id) {
JsonHeaderWrapper jsonHeaderWrapper = init();
try {
jsonHeaderWrapper.setData(this.baseService.findById(id));

View File

@ -8,6 +8,8 @@ import java.util.Map;
public class NodeMeta {
private Map entity;
private String id;
private NodeMeta parent;
private String name;
private String prop;
private boolean ready;
}

View File

@ -14,4 +14,5 @@ public class ServicePipeline extends BaseEntity {
private List linkList = new ArrayList<Map>();
private List nodeList = new ArrayList<FlowNode>();
private List origin = new ArrayList<Integer>();
private String profile;
}

View File

@ -0,0 +1,17 @@
package com.kongx.serve.feign;
import feign.RequestLine;
import org.springframework.cloud.openfeign.FeignClient;
import java.net.URI;
import java.util.Map;
@FeignClient(name = "truncateEntityFeignService")
public interface TruncateEntityFeignService {
@RequestLine("GET")
Map findById(URI uri);
@RequestLine("DELETE")
void remove(URI uri);
}

View File

@ -2,13 +2,14 @@ package com.kongx.serve.mapper;
import com.kongx.common.handler.JSONHandler;
import com.kongx.serve.entity.flow.ServicePipeline;
import com.kongx.serve.entity.system.SystemProfile;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
public interface ServicePipelineMapper {
@Select({"<script>", "SELECT * FROM kongx_service_pipeline where 1=1 ",
@Select({"<script>", "SELECT * FROM kongx_service_pipeline where 1=1 and profile=#{profile.profile}",
"<when test='job.name!=null'>",
" and (name like CONCAT('%',#{job.name},'%'))",
"</when>",
@ -16,15 +17,16 @@ public interface ServicePipelineMapper {
@Results({
@Result(property = "linkList", column = "link_list", typeHandler = JSONHandler.class),
@Result(property = "nodeList", column = "node_list", typeHandler = JSONHandler.class),
@Result(property = "origin", column = "origin", typeHandler = JSONHandler.class),
})
List<ServicePipeline> findAll(@Param("job") ServicePipeline project);
List<ServicePipeline> findAll(@Param("profile") SystemProfile systemProfile, @Param("job") ServicePipeline project);
@Insert({"insert into kongx_service_pipeline(name,link_list,node_list,origin,remark,creator,create_at) values (",
@Insert({"insert into kongx_service_pipeline(name,link_list,node_list,origin,remark,creator,create_at,profile) values (",
"#{name},#{linkList,typeHandler=com.kongx.common.handler.JSONHandler},",
"#{nodeList,typeHandler=com.kongx.common.handler.JSONHandler},",
"#{origin,typeHandler=com.kongx.common.handler.JSONHandler},",
"#{remark},",
"#{creator}, #{create_at, jdbcType=TIMESTAMP}",
"#{creator}, #{create_at, jdbcType=TIMESTAMP},#{profile}",
")"})
int insert(ServicePipeline project);
@ -41,6 +43,7 @@ public interface ServicePipelineMapper {
@Results({
@Result(property = "linkList", column = "link_list", typeHandler = JSONHandler.class),
@Result(property = "nodeList", column = "node_list", typeHandler = JSONHandler.class),
@Result(property = "origin", column = "origin", typeHandler = JSONHandler.class),
})
ServicePipeline findById(int id);

View File

@ -2,8 +2,10 @@ package com.kongx.serve.service.flow;
import com.kongx.common.core.entity.UserInfo;
import com.kongx.serve.entity.flow.ServicePipeline;
import com.kongx.serve.entity.system.SystemProfile;
import com.kongx.serve.mapper.ServicePipelineMapper;
import com.kongx.serve.service.IBaseService;
import com.kongx.serve.service.system.SystemProfileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -15,17 +17,18 @@ public class ServicePipelineService implements IBaseService<ServicePipeline, Int
@Autowired
private ServicePipelineMapper servicePipelineMapper;
@Autowired
private SystemProfileService systemProfileService;
@Override
public List<ServicePipeline> findAll(ServicePipeline entity) {
return this.servicePipelineMapper.findAll(entity);
public List<ServicePipeline> findAll(SystemProfile systemProfile, ServicePipeline entity) {
return this.servicePipelineMapper.findAll(systemProfile, entity);
}
@Override
public void add(ServicePipeline entity, UserInfo userInfo) {
entity.setCreator(userInfo.getName());
entity.setCreate_at(new Date());
entity.setProfile(systemProfileService.getClientByName(userInfo.getUserId()).getProfile());
this.servicePipelineMapper.insert(entity);
}
@ -38,11 +41,19 @@ public class ServicePipelineService implements IBaseService<ServicePipeline, Int
@Override
public void remove(int pk) {
this.servicePipelineMapper.deleteById(pk);
ServicePipeline servicePipeline = this.servicePipelineMapper.findById(pk);
if (servicePipeline.getNodeList().isEmpty()) {
this.servicePipelineMapper.deleteById(pk);
} else {
throw new RuntimeException("请删除相关配置后再执行本操作");
}
}
@Override
public ServicePipeline findById(Integer id) {
return this.servicePipelineMapper.findById(id);
ServicePipeline servicePipeline = this.servicePipelineMapper.findById(id);
return servicePipeline;
}
}

View File

@ -0,0 +1,37 @@
package com.kongx.serve.service.gateway;
import com.kongx.serve.entity.system.SystemProfile;
import com.kongx.serve.feign.TruncateEntityFeignService;
import com.kongx.serve.service.AbstractCacheService;
import feign.Feign;
import feign.Target;
import feign.codec.Decoder;
import feign.codec.Encoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
import java.net.URISyntaxException;
import java.util.Map;
@Slf4j
@Component("truncateEntityService")
@Import(FeignClientsConfiguration.class)
public class TruncateEntityService extends AbstractCacheService {
private TruncateEntityFeignService truncateEntityFeignService;
@Autowired
public TruncateEntityService(Decoder decoder, Encoder encoder) {
truncateEntityFeignService = Feign.builder().encoder(encoder).decoder(decoder).target(Target.EmptyTarget.create(TruncateEntityFeignService.class));
}
public void remove(SystemProfile systemProfile, String uri) throws URISyntaxException {
this.truncateEntityFeignService.remove(uri(systemProfile, uri));
}
public Map findById(SystemProfile systemProfile, String uri) throws URISyntaxException {
return this.truncateEntityFeignService.findById(uri(systemProfile, uri));
}
}

View File

@ -13,7 +13,7 @@
<groupId>com.kongx</groupId>
<artifactId>kongx</artifactId>
<packaging>pom</packaging>
<version>2.0.2</version>
<version>2.1.0</version>
<modules>
<module>kongx-serve</module>
<module>kongx-common</module>