mirror of
https://github.com/alibaba/canal.git
synced 2026-11-04 00:30:15 +08:00
canal-admin完善 (#2121)
* admin端口调整完成 * server端适配调整 * 调整部分功能 * 单机/集群admin调试完成 * 重新发布前端页面
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
package com.alibaba.otter.canal.admin.common;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
public class DaemonThreadFactory implements ThreadFactory {
|
||||
|
||||
public static final ThreadFactory daemonThreadFactory = new DaemonThreadFactory();
|
||||
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = Executors.defaultThreadFactory().newThread(r);
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ import com.google.protobuf.ByteString;
|
||||
|
||||
/**
|
||||
* 基于netty实现的admin控制
|
||||
*
|
||||
*
|
||||
* @author agapple 2019年8月26日 上午10:23:44
|
||||
* @since 1.1.4
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.alibaba.otter.canal.admin.controller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.otter.canal.admin.model.BaseModel;
|
||||
import com.alibaba.otter.canal.admin.model.CanalCluster;
|
||||
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||
import com.alibaba.otter.canal.admin.service.CanalClusterServic;
|
||||
import com.alibaba.otter.canal.admin.service.NodeServerService;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/{env}/canal")
|
||||
public class CanalClusterController {
|
||||
|
||||
@Autowired
|
||||
CanalClusterServic canalClusterServic;
|
||||
|
||||
@Autowired
|
||||
NodeServerService nodeServerService;
|
||||
|
||||
@GetMapping(value = "/clusters")
|
||||
public BaseModel<List<CanalCluster>> clusters(CanalCluster canalCluster, @PathVariable String env) {
|
||||
return BaseModel.getInstance(canalClusterServic.findList(canalCluster));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/cluster")
|
||||
public BaseModel<String> save(@RequestBody CanalCluster canalCluster, @PathVariable String env) {
|
||||
canalClusterServic.save(canalCluster);
|
||||
return BaseModel.getInstance("success");
|
||||
}
|
||||
|
||||
@GetMapping(value = "/cluster/{id}")
|
||||
public BaseModel<CanalCluster> detail(@PathVariable Long id, @PathVariable String env) {
|
||||
return BaseModel.getInstance(canalClusterServic.detail(id));
|
||||
}
|
||||
|
||||
@PutMapping(value = "/cluster")
|
||||
public BaseModel<String> update(@RequestBody CanalCluster canalCluster, @PathVariable String env) {
|
||||
canalClusterServic.update(canalCluster);
|
||||
return BaseModel.getInstance("success");
|
||||
}
|
||||
|
||||
@DeleteMapping(value = "/cluster/{id}")
|
||||
public BaseModel<String> delete(@PathVariable Long id, @PathVariable String env) {
|
||||
canalClusterServic.delete(id);
|
||||
return BaseModel.getInstance("success");
|
||||
}
|
||||
|
||||
@GetMapping(value = "/clustersAndServers")
|
||||
public BaseModel<List<?>> clustersAndServers(@PathVariable String env) {
|
||||
List<CanalCluster> clusters = canalClusterServic.findList(new CanalCluster());
|
||||
JSONObject group = new JSONObject();
|
||||
group.put("label", "集群");
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
clusters.forEach(cluster -> {
|
||||
JSONObject item = new JSONObject();
|
||||
item.put("label", cluster.getName());
|
||||
item.put("value", "cluster:" + cluster.getId());
|
||||
jsonArray.add(item);
|
||||
});
|
||||
group.put("options", jsonArray);
|
||||
|
||||
NodeServer param = new NodeServer();
|
||||
param.setClusterId(-1L);
|
||||
List<NodeServer> servers = nodeServerService.findAll(param); // 取所有standalone的节点
|
||||
JSONObject group2 = new JSONObject();
|
||||
group2.put("label", "单机主机");
|
||||
JSONArray jsonArray2 = new JSONArray();
|
||||
servers.forEach(server -> {
|
||||
JSONObject item = new JSONObject();
|
||||
item.put("label", server.getName());
|
||||
item.put("value", "server:" + server.getId());
|
||||
jsonArray2.add(item);
|
||||
});
|
||||
group2.put("options", jsonArray2);
|
||||
|
||||
List<JSONObject> result = new ArrayList<>();
|
||||
result.add(group);
|
||||
result.add(group2);
|
||||
return BaseModel.getInstance(result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,9 +31,10 @@ public class CanalConfigController {
|
||||
* @param env 环境变量
|
||||
* @return 配置信息
|
||||
*/
|
||||
@GetMapping(value = "/config")
|
||||
public BaseModel<CanalConfig> canalConfig(@PathVariable String env) {
|
||||
return BaseModel.getInstance(canalConfigService.getCanalConfig());
|
||||
@GetMapping(value = "/config/{clusterId}/{serverId}")
|
||||
public BaseModel<CanalConfig> canalConfig(@PathVariable Long clusterId, @PathVariable Long serverId,
|
||||
@PathVariable String env) {
|
||||
return BaseModel.getInstance(canalConfigService.getCanalConfig(clusterId, serverId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,15 +3,9 @@ package com.alibaba.otter.canal.admin.controller;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.otter.canal.admin.model.Pager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import com.alibaba.otter.canal.admin.model.BaseModel;
|
||||
import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
||||
@@ -38,8 +32,9 @@ public class CanalInstanceController {
|
||||
* @return 实例列表
|
||||
*/
|
||||
@GetMapping(value = "/instances")
|
||||
public BaseModel<List<CanalInstanceConfig>> list(CanalInstanceConfig canalInstanceConfig, @PathVariable String env) {
|
||||
return BaseModel.getInstance(canalInstanceConfigService.findList(canalInstanceConfig));
|
||||
public BaseModel<Pager<CanalInstanceConfig>> list(CanalInstanceConfig canalInstanceConfig,
|
||||
Pager<CanalInstanceConfig> pager, @PathVariable String env) {
|
||||
return BaseModel.getInstance(canalInstanceConfigService.findList(canalInstanceConfig, pager));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,6 +125,20 @@ public class CanalInstanceController {
|
||||
return BaseModel.getInstance(canalInstanceConfigService.remoteOperation(id, nodeId, "stop"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过操作instance状态启动/停止远程instance
|
||||
*
|
||||
* @param id 实例配置id
|
||||
* @param option 操作类型: start/stop
|
||||
* @param env 环境变量
|
||||
* @return 是否成功
|
||||
*/
|
||||
@PutMapping(value = "/instance/status/{id}")
|
||||
public BaseModel<Boolean> instanceStart(@PathVariable Long id, @RequestParam String option,
|
||||
@PathVariable String env) {
|
||||
return BaseModel.getInstance(canalInstanceConfigService.instanceOperation(id, option));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取远程实例运行日志
|
||||
*
|
||||
@@ -143,4 +152,16 @@ public class CanalInstanceController {
|
||||
@PathVariable String env) {
|
||||
return BaseModel.getInstance(canalInstanceConfigService.remoteInstanceLog(id, nodeId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过Server id获取所有活动的Instance
|
||||
*
|
||||
* @param serverId 节点id
|
||||
* @param env 环境变量
|
||||
* @return 实例列表
|
||||
*/
|
||||
@GetMapping(value = "/active/instances/{serverId}")
|
||||
public BaseModel<List<CanalInstanceConfig>> activeInstances(@PathVariable Long serverId, @PathVariable String env) {
|
||||
return BaseModel.getInstance(canalInstanceConfigService.findActiveInstaceByServerId(serverId));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import com.alibaba.otter.canal.admin.model.BaseModel;
|
||||
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||
import com.alibaba.otter.canal.admin.model.Pager;
|
||||
import com.alibaba.otter.canal.admin.service.NodeServerService;
|
||||
|
||||
/**
|
||||
@@ -30,8 +31,9 @@ public class NodeServerController {
|
||||
* @return 节点信息列表
|
||||
*/
|
||||
@GetMapping(value = "/nodeServers")
|
||||
public BaseModel<List<NodeServer>> nodeServers(NodeServer nodeServer, @PathVariable String env) {
|
||||
return BaseModel.getInstance(nodeServerService.findList(nodeServer));
|
||||
public BaseModel<Pager<NodeServer>> nodeServers(NodeServer nodeServer, Pager<NodeServer> pager,
|
||||
@PathVariable String env) {
|
||||
return BaseModel.getInstance(nodeServerService.findList(nodeServer, pager));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,26 +1,17 @@
|
||||
package com.alibaba.otter.canal.admin.controller;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import com.alibaba.otter.canal.admin.model.BaseModel;
|
||||
import com.alibaba.otter.canal.admin.model.CanalConfig;
|
||||
import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
||||
import com.alibaba.otter.canal.admin.service.CanalConfigService;
|
||||
import com.alibaba.otter.canal.admin.service.CanalInstanceService;
|
||||
import com.alibaba.otter.canal.admin.service.PollingConfigServer;
|
||||
import com.alibaba.otter.canal.protocol.SecurityUtil;
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
/**
|
||||
* Canal Instance配置管理控制层
|
||||
@@ -34,43 +25,28 @@ public class PollingConfigController {
|
||||
|
||||
private static final byte[] seeds = "canal is best!".getBytes();
|
||||
|
||||
@Autowired
|
||||
CanalInstanceService canalInstanceConfigService;
|
||||
|
||||
@Autowired
|
||||
CanalConfigService canalConfigService;
|
||||
|
||||
@Value(value = "${canal.adminUser}")
|
||||
String user;
|
||||
|
||||
@Value(value = "${canal.adminPasswd}")
|
||||
String passwd;
|
||||
|
||||
@Autowired
|
||||
PollingConfigServer pollingConfigServer;
|
||||
|
||||
/**
|
||||
* 获取server全局配置
|
||||
*/
|
||||
@GetMapping(value = "/server_polling")
|
||||
public BaseModel<CanalConfig> canalConfigPoll(@RequestHeader String user, @RequestHeader String passwd,
|
||||
@PathVariable String env, @RequestParam String md5) {
|
||||
@RequestParam String ip, @RequestParam Integer port,
|
||||
@RequestParam String md5, @PathVariable String env) {
|
||||
if (!auth(user, passwd)) {
|
||||
throw new RuntimeException("auth :" + user + " is failed");
|
||||
}
|
||||
|
||||
CanalConfig config = canalConfigService.getCanalConfig();
|
||||
if (StringUtils.isEmpty(md5)) {
|
||||
return BaseModel.getInstance(config);
|
||||
} else {
|
||||
|
||||
try {
|
||||
String newMd5 = SecurityUtil.md5String(config.getContent());
|
||||
if (StringUtils.equals(md5, newMd5)) {
|
||||
config.setContent(null);
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
}
|
||||
|
||||
return BaseModel.getInstance(config);
|
||||
}
|
||||
CanalConfig canalConfig = pollingConfigServer.getChangedConfig(ip, port, md5);
|
||||
return BaseModel.getInstance(canalConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,26 +54,14 @@ public class PollingConfigController {
|
||||
*/
|
||||
@GetMapping(value = "/instance_polling/{destination}")
|
||||
public BaseModel<CanalInstanceConfig> instanceConfigPoll(@RequestHeader String user, @RequestHeader String passwd,
|
||||
@PathVariable String env,
|
||||
@PathVariable String destination, @RequestParam String md5) {
|
||||
@PathVariable String env, @PathVariable String destination,
|
||||
@RequestParam String md5) {
|
||||
if (!auth(user, passwd)) {
|
||||
throw new RuntimeException("auth :" + user + " is failed");
|
||||
}
|
||||
|
||||
CanalInstanceConfig config = canalInstanceConfigService.findOne(destination);
|
||||
if (StringUtils.isEmpty(md5)) {
|
||||
return BaseModel.getInstance(config);
|
||||
} else {
|
||||
try {
|
||||
String newMd5 = SecurityUtil.md5String(config.getContent());
|
||||
if (StringUtils.equals(md5, newMd5)) {
|
||||
config.setContent(null);
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
}
|
||||
|
||||
return BaseModel.getInstance(config);
|
||||
}
|
||||
CanalInstanceConfig canalInstanceConfig = pollingConfigServer.getInstanceConfig(destination, md5);
|
||||
return BaseModel.getInstance(canalInstanceConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,30 +69,14 @@ public class PollingConfigController {
|
||||
*/
|
||||
@GetMapping(value = "/instances_polling")
|
||||
public BaseModel<CanalInstanceConfig> instancesPoll(@RequestHeader String user, @RequestHeader String passwd,
|
||||
@PathVariable String env, @RequestParam String ip,
|
||||
@RequestParam String port, @RequestParam String md5) {
|
||||
@RequestParam String ip, @RequestParam Integer port,
|
||||
@RequestParam String md5, @PathVariable String env) {
|
||||
if (!auth(user, passwd)) {
|
||||
throw new RuntimeException("auth :" + user + " is failed");
|
||||
}
|
||||
|
||||
CanalInstanceConfig canalInstanceConfig = new CanalInstanceConfig();
|
||||
List<CanalInstanceConfig> configs = canalInstanceConfigService.findList(canalInstanceConfig);
|
||||
List<String> instances = configs.stream().map(CanalInstanceConfig::getName).collect(Collectors.toList());
|
||||
String data = Joiner.on(',').join(instances);
|
||||
canalInstanceConfig.setContent(data);
|
||||
if (StringUtils.isEmpty(md5)) {
|
||||
return BaseModel.getInstance(canalInstanceConfig);
|
||||
} else {
|
||||
try {
|
||||
String newMd5 = SecurityUtil.md5String(canalInstanceConfig.getContent());
|
||||
if (StringUtils.equals(md5, newMd5)) {
|
||||
canalInstanceConfig.setContent(null);
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
}
|
||||
|
||||
return BaseModel.getInstance(canalInstanceConfig);
|
||||
}
|
||||
CanalInstanceConfig canalInstanceConfig = pollingConfigServer.getInstancesConfig(ip, port, md5);
|
||||
return BaseModel.getInstance(canalInstanceConfig);
|
||||
}
|
||||
|
||||
private boolean auth(String user, String passwd) {
|
||||
|
||||
@@ -27,7 +27,7 @@ public class UserController {
|
||||
|
||||
public static final LoadingCache<String, User> loginUsers = Caffeine.newBuilder()
|
||||
.maximumSize(10_000)
|
||||
.expireAfterAccess(10, TimeUnit.MINUTES)
|
||||
.expireAfterAccess(30, TimeUnit.MINUTES)
|
||||
.build(key -> null); // 用户登录信息缓存
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.alibaba.otter.canal.admin.model;
|
||||
|
||||
import io.ebean.Finder;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Canal集群信息实体类
|
||||
*
|
||||
* @author rewerma 2019-07-13 下午05:12:16
|
||||
* @version 1.0.0
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "canal_cluster")
|
||||
public class CanalCluster extends Model {
|
||||
|
||||
public static final CanalClusterFinder find = new CanalClusterFinder();
|
||||
|
||||
public static class CanalClusterFinder extends Finder<Long, CanalCluster> {
|
||||
|
||||
/**
|
||||
* Construct using the default EbeanServer.
|
||||
*/
|
||||
public CanalClusterFinder(){
|
||||
super(CanalCluster.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
private String name;
|
||||
private String zkHosts;
|
||||
private Date modifiedTime;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getZkHosts() {
|
||||
return zkHosts;
|
||||
}
|
||||
|
||||
public void setZkHosts(String zkHosts) {
|
||||
this.zkHosts = zkHosts;
|
||||
}
|
||||
|
||||
public Date getModifiedTime() {
|
||||
return modifiedTime;
|
||||
}
|
||||
|
||||
public void setModifiedTime(Date modifiedTime) {
|
||||
this.modifiedTime = modifiedTime;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* Canal住配置实体类
|
||||
* Canal主配置实体类
|
||||
*
|
||||
* @author rewerma 2019-07-13 下午05:12:16
|
||||
* @version 1.0.0
|
||||
@@ -31,8 +31,11 @@ public class CanalConfig extends Model {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
private Long clusterId;
|
||||
private Long serverId;
|
||||
private String name;
|
||||
private String content;
|
||||
private String contentMd5;
|
||||
private String status;
|
||||
private Date modifiedTime;
|
||||
|
||||
@@ -44,6 +47,22 @@ public class CanalConfig extends Model {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
|
||||
public void setClusterId(Long clusterId) {
|
||||
this.clusterId = clusterId;
|
||||
}
|
||||
|
||||
public Long getServerId() {
|
||||
return serverId;
|
||||
}
|
||||
|
||||
public void setServerId(Long serverId) {
|
||||
this.serverId = serverId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -60,6 +79,14 @@ public class CanalConfig extends Model {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getContentMd5() {
|
||||
return contentMd5;
|
||||
}
|
||||
|
||||
public void setContentMd5(String contentMd5) {
|
||||
this.contentMd5 = contentMd5;
|
||||
}
|
||||
|
||||
public Date getModifiedTime() {
|
||||
return modifiedTime;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package com.alibaba.otter.canal.admin.model;
|
||||
|
||||
import io.ebean.Finder;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Transient;
|
||||
import javax.persistence.*;
|
||||
|
||||
import io.ebean.Finder;
|
||||
|
||||
/**
|
||||
* Canal实例配置信息实体类
|
||||
@@ -31,16 +29,31 @@ public class CanalInstanceConfig extends Model {
|
||||
}
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
private String name;
|
||||
private String content;
|
||||
private String status;
|
||||
private Date modifiedTime;
|
||||
private Long id;
|
||||
@Column(name = "cluster_id")
|
||||
private Long clusterId;
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "cluster_id", updatable = false, insertable = false)
|
||||
private CanalCluster canalCluster;
|
||||
@Column(name = "server_id")
|
||||
private Long serverId;
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "server_id", updatable = false, insertable = false)
|
||||
private NodeServer nodeServer;
|
||||
private String name;
|
||||
private String content;
|
||||
private String contentMd5;
|
||||
private String status; // 1: 正常 0: 停止
|
||||
private Date modifiedTime;
|
||||
|
||||
@Transient
|
||||
private Long nodeId;
|
||||
private String clusterServerId;
|
||||
@Transient
|
||||
private String nodeIp;
|
||||
private String runningStatus = "0"; // 1: 运行中 0: 停止
|
||||
|
||||
public void init() {
|
||||
status = "1";
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
@@ -50,6 +63,38 @@ public class CanalInstanceConfig extends Model {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
|
||||
public void setClusterId(Long clusterId) {
|
||||
this.clusterId = clusterId;
|
||||
}
|
||||
|
||||
public CanalCluster getCanalCluster() {
|
||||
return canalCluster;
|
||||
}
|
||||
|
||||
public void setCanalCluster(CanalCluster canalCluster) {
|
||||
this.canalCluster = canalCluster;
|
||||
}
|
||||
|
||||
public Long getServerId() {
|
||||
return serverId;
|
||||
}
|
||||
|
||||
public void setServerId(Long serverId) {
|
||||
this.serverId = serverId;
|
||||
}
|
||||
|
||||
public NodeServer getNodeServer() {
|
||||
return nodeServer;
|
||||
}
|
||||
|
||||
public void setNodeServer(NodeServer nodeServer) {
|
||||
this.nodeServer = nodeServer;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
@@ -66,6 +111,14 @@ public class CanalInstanceConfig extends Model {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getContentMd5() {
|
||||
return contentMd5;
|
||||
}
|
||||
|
||||
public void setContentMd5(String contentMd5) {
|
||||
this.contentMd5 = contentMd5;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
@@ -82,19 +135,19 @@ public class CanalInstanceConfig extends Model {
|
||||
this.modifiedTime = modifiedTime;
|
||||
}
|
||||
|
||||
public Long getNodeId() {
|
||||
return nodeId;
|
||||
public String getClusterServerId() {
|
||||
return clusterServerId;
|
||||
}
|
||||
|
||||
public void setNodeId(Long nodeId) {
|
||||
this.nodeId = nodeId;
|
||||
public void setClusterServerId(String clusterServerId) {
|
||||
this.clusterServerId = clusterServerId;
|
||||
}
|
||||
|
||||
public String getNodeIp() {
|
||||
return nodeIp;
|
||||
public String getRunningStatus() {
|
||||
return runningStatus;
|
||||
}
|
||||
|
||||
public void setNodeIp(String nodeIp) {
|
||||
this.nodeIp = nodeIp;
|
||||
public void setRunningStatus(String runningStatus) {
|
||||
this.runningStatus = runningStatus;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@ import io.ebean.Finder;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.*;
|
||||
|
||||
/**
|
||||
* 节点信息实体类
|
||||
@@ -32,14 +30,19 @@ public class NodeServer extends Model {
|
||||
}
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
private String name;
|
||||
private String ip;
|
||||
private Integer adminPort;
|
||||
private Integer metricPort;
|
||||
private Integer tcpPort;
|
||||
private String status;
|
||||
private Date modifiedTime;
|
||||
private Long id;
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "cluster_id", updatable = false, insertable = false)
|
||||
private CanalCluster canalCluster;
|
||||
@Column(name = "cluster_id")
|
||||
private Long clusterId;
|
||||
private String name;
|
||||
private String ip;
|
||||
private Integer adminPort;
|
||||
private Integer metricPort;
|
||||
private Integer tcpPort;
|
||||
private String status;
|
||||
private Date modifiedTime;
|
||||
|
||||
public void init() {
|
||||
status = "-1";
|
||||
@@ -53,6 +56,22 @@ public class NodeServer extends Model {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public CanalCluster getCanalCluster() {
|
||||
return canalCluster;
|
||||
}
|
||||
|
||||
public void setCanalCluster(CanalCluster canalCluster) {
|
||||
this.canalCluster = canalCluster;
|
||||
}
|
||||
|
||||
public Long getClusterId() {
|
||||
return clusterId;
|
||||
}
|
||||
|
||||
public void setClusterId(Long clusterId) {
|
||||
this.clusterId = clusterId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.alibaba.otter.canal.admin.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Pager<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -986577815091763517L;
|
||||
|
||||
private Long count = 0L;
|
||||
private List<T> items = new ArrayList<T>();
|
||||
private Integer page = 1;
|
||||
private Integer size = 20;
|
||||
private Long offset = 0L;
|
||||
|
||||
public Pager(){
|
||||
|
||||
}
|
||||
|
||||
public Pager(Integer page, Integer size){
|
||||
this.page = page;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public Pager(Long count, List<T> items){
|
||||
this.count = count;
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "PageResult[count=" + this.count + ", items=" + this.items + "]";
|
||||
}
|
||||
|
||||
public Long getCount() {
|
||||
return this.count;
|
||||
}
|
||||
|
||||
public void setCount(Long count) {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public List<T> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public void setItems(List<T> items) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
public Integer getPage() {
|
||||
if (page == null) {
|
||||
page = 1;
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
public void setPage(Integer page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
public Integer getSize() {
|
||||
if (size == null) {
|
||||
size = 20;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(Integer size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public Long getOffset() {
|
||||
offset = (long) (getPage() - 1) * (long) getSize();
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void setOffset(Long offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.alibaba.otter.canal.admin.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.otter.canal.admin.model.CanalCluster;
|
||||
|
||||
public interface CanalClusterServic {
|
||||
|
||||
void save(CanalCluster canalCluster);
|
||||
|
||||
CanalCluster detail(Long id);
|
||||
|
||||
void update(CanalCluster canalCluster);
|
||||
|
||||
void delete(Long id);
|
||||
|
||||
List<CanalCluster> findList(CanalCluster canalCluster);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import com.alibaba.otter.canal.admin.model.CanalConfig;
|
||||
|
||||
public interface CanalConfigService {
|
||||
|
||||
CanalConfig getCanalConfig();
|
||||
CanalConfig getCanalConfig(Long clusterId, Long serverId);
|
||||
|
||||
CanalConfig getCanalConfigSummary();
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
||||
import com.alibaba.otter.canal.admin.model.Pager;
|
||||
|
||||
/**
|
||||
* Canal实例配置信息业务层接口
|
||||
@@ -13,7 +14,7 @@ import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
||||
*/
|
||||
public interface CanalInstanceService {
|
||||
|
||||
List<CanalInstanceConfig> findList(CanalInstanceConfig canalInstanceConfig);
|
||||
Pager<CanalInstanceConfig> findList(CanalInstanceConfig canalInstanceConfig, Pager<CanalInstanceConfig> pager);
|
||||
|
||||
void save(CanalInstanceConfig canalInstanceConfig);
|
||||
|
||||
@@ -28,4 +29,8 @@ public interface CanalInstanceService {
|
||||
Map<String, String> remoteInstanceLog(Long id, Long nodeId);
|
||||
|
||||
boolean remoteOperation(Long id, Long nodeId, String option);
|
||||
|
||||
boolean instanceOperation(Long id, String option);
|
||||
|
||||
List<CanalInstanceConfig> findActiveInstaceByServerId(Long serverId);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.alibaba.otter.canal.admin.service;
|
||||
|
||||
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||
import com.alibaba.otter.canal.admin.model.Pager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -14,7 +15,9 @@ public interface NodeServerService {
|
||||
|
||||
void delete(Long id);
|
||||
|
||||
List<NodeServer> findList(NodeServer nodeServer);
|
||||
List<NodeServer> findAll(NodeServer nodeServer);
|
||||
|
||||
Pager<NodeServer> findList(NodeServer nodeServer, Pager<NodeServer> pager);
|
||||
|
||||
int remoteNodeStatus(String ip, Integer port);
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.alibaba.otter.canal.admin.service;
|
||||
|
||||
import com.alibaba.otter.canal.admin.model.CanalConfig;
|
||||
import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
||||
|
||||
public interface PollingConfigServer {
|
||||
|
||||
CanalConfig getChangedConfig(String ip, Integer port, String md5);
|
||||
|
||||
CanalInstanceConfig getInstancesConfig(String ip, Integer port, String md5);
|
||||
|
||||
CanalInstanceConfig getInstanceConfig(String destination, String md5);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.alibaba.otter.canal.admin.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.otter.canal.admin.common.exception.ServiceException;
|
||||
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.alibaba.otter.canal.admin.model.CanalCluster;
|
||||
import com.alibaba.otter.canal.admin.service.CanalClusterServic;
|
||||
|
||||
import io.ebean.Query;
|
||||
|
||||
@Service
|
||||
public class CanalClusterServiceImpl implements CanalClusterServic {
|
||||
|
||||
public void save(CanalCluster canalCluster) {
|
||||
canalCluster.save();
|
||||
}
|
||||
|
||||
public CanalCluster detail(Long id) {
|
||||
return CanalCluster.find.byId(id);
|
||||
}
|
||||
|
||||
public void update(CanalCluster canalCluster) {
|
||||
canalCluster.update("name", "zkHosts");
|
||||
}
|
||||
|
||||
public void delete(Long id) {
|
||||
// 判断集群下是否存在server信息
|
||||
int serverCnt = NodeServer.find.query().where().eq("clusterId", id).findCount();
|
||||
if (serverCnt > 0) {
|
||||
throw new ServiceException("Servers exist, delete failed");
|
||||
}
|
||||
|
||||
CanalCluster canalCluster = CanalCluster.find.byId(id);
|
||||
if (canalCluster != null) {
|
||||
canalCluster.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public List<CanalCluster> findList(CanalCluster canalCluster) {
|
||||
Query<CanalCluster> query = CanalCluster.find.query();
|
||||
query.order().asc("id");
|
||||
return query.findList();
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,14 @@ package com.alibaba.otter.canal.admin.service.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Date;
|
||||
|
||||
import com.alibaba.otter.canal.admin.common.exception.ServiceException;
|
||||
import com.alibaba.otter.canal.admin.model.CanalCluster;
|
||||
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||
import com.alibaba.otter.canal.protocol.SecurityUtil;
|
||||
import io.ebean.Query;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
@@ -27,20 +33,27 @@ public class CanalConfigServiceImpl implements CanalConfigService {
|
||||
private static final String CANAL_GLOBAL_CONFIG = "canal.properties";
|
||||
private static final String CANAL_ADAPTER_CONFIG = "application.yml";
|
||||
|
||||
public CanalConfig getCanalConfig() {
|
||||
long id = 1L;
|
||||
CanalConfig config = CanalConfig.find.byId(id);
|
||||
if (config == null) {
|
||||
String context = loadDefaultConf(CANAL_GLOBAL_CONFIG);
|
||||
if (context == null) {
|
||||
return null;
|
||||
public CanalConfig getCanalConfig(Long clusterId, Long serverId) {
|
||||
CanalConfig config = null;
|
||||
if (clusterId != null && clusterId != 0) {
|
||||
config = CanalConfig.find.query().where().eq("clusterId", clusterId).findOne();
|
||||
} else if (serverId != null && serverId != 0) {
|
||||
config = CanalConfig.find.query().where().eq("serverId", serverId).findOne();
|
||||
if (config == null) {
|
||||
NodeServer nodeServer = NodeServer.find.byId(serverId);
|
||||
if (nodeServer != null) {
|
||||
Long cid = nodeServer.getClusterId();
|
||||
if (cid != null) {
|
||||
config = CanalConfig.find.query().where().eq("clusterId", cid).findOne();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new ServiceException("clusterId and serverId are all empty");
|
||||
}
|
||||
if (config == null) {
|
||||
config = new CanalConfig();
|
||||
config.setId(id);
|
||||
config.setName(CANAL_GLOBAL_CONFIG);
|
||||
config.setModifiedTime(new Date());
|
||||
config.setContent(context);
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -78,9 +91,19 @@ public class CanalConfigServiceImpl implements CanalConfigService {
|
||||
|
||||
public void updateContent(CanalConfig canalConfig) {
|
||||
try {
|
||||
canalConfig.insert();
|
||||
} catch (Throwable e) {
|
||||
canalConfig.update();
|
||||
String contentMd5 = SecurityUtil.md5String(canalConfig.getContent());
|
||||
canalConfig.setContentMd5(contentMd5);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// ignore
|
||||
}
|
||||
if (canalConfig.getId() != null) {
|
||||
CanalConfig canalConfigTmp = CanalConfig.find.byId(canalConfig.getId());
|
||||
if (canalConfigTmp != null && canalConfigTmp.getClusterId() != null) {
|
||||
canalConfig.setServerId(null);
|
||||
}
|
||||
canalConfig.update("serverId", "content", "contentMd5");
|
||||
} else {
|
||||
canalConfig.save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
package com.alibaba.otter.canal.admin.service.impl;
|
||||
|
||||
import io.ebean.Query;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import com.alibaba.otter.canal.admin.model.Pager;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.alibaba.otter.canal.admin.common.DaemonThreadFactory;
|
||||
import com.alibaba.otter.canal.admin.common.exception.ServiceException;
|
||||
import com.alibaba.otter.canal.admin.connector.AdminConnector;
|
||||
import com.alibaba.otter.canal.admin.connector.SimpleAdminConnectors;
|
||||
import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
||||
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||
import com.alibaba.otter.canal.admin.service.CanalInstanceService;
|
||||
import com.alibaba.otter.canal.protocol.SecurityUtil;
|
||||
|
||||
import io.ebean.Query;
|
||||
|
||||
/**
|
||||
* Canal实例配置信息业务层
|
||||
@@ -24,52 +28,196 @@ import com.alibaba.otter.canal.admin.service.CanalInstanceService;
|
||||
@Service
|
||||
public class CanalInstanceServiceImpl implements CanalInstanceService {
|
||||
|
||||
public List<CanalInstanceConfig> findList(CanalInstanceConfig canalInstanceConfig) {
|
||||
public Pager<CanalInstanceConfig> findList(CanalInstanceConfig canalInstanceConfig,
|
||||
Pager<CanalInstanceConfig> pager) {
|
||||
Query<CanalInstanceConfig> query = CanalInstanceConfig.find.query()
|
||||
.setDisableLazyLoading(true)
|
||||
.select("name, modifiedTime");
|
||||
.select("clusterId, serverId, name, modifiedTime")
|
||||
.fetch("canalCluster", "name")
|
||||
.fetch("nodeServer", "name,ip,adminPort");
|
||||
if (canalInstanceConfig != null) {
|
||||
if (StringUtils.isNotEmpty(canalInstanceConfig.getName())) {
|
||||
query.where().like("name", "%" + canalInstanceConfig.getName() + "%");
|
||||
}
|
||||
}
|
||||
query.order().asc("id");
|
||||
List<CanalInstanceConfig> canalInstanceConfigs = query.findList();
|
||||
|
||||
// check all canal instances running status
|
||||
List<NodeServer> nodeServers = NodeServer.find.query().findList();
|
||||
for (NodeServer nodeServer : nodeServers) {
|
||||
String runningInstances = SimpleAdminConnectors.execute(nodeServer.getIp(),
|
||||
nodeServer.getAdminPort(),
|
||||
AdminConnector::getRunningInstances);
|
||||
if (runningInstances == null) {
|
||||
continue;
|
||||
}
|
||||
String[] instances = runningInstances.split(",");
|
||||
for (String instance : instances) {
|
||||
for (CanalInstanceConfig cig : canalInstanceConfigs) {
|
||||
if (instance.equals(cig.getName())) {
|
||||
cig.setNodeId(nodeServer.getId());
|
||||
cig.setNodeIp(nodeServer.getIp());
|
||||
break;
|
||||
}
|
||||
if (StringUtils.isNotEmpty(canalInstanceConfig.getClusterServerId())) {
|
||||
if (canalInstanceConfig.getClusterServerId().startsWith("cluster:")) {
|
||||
query.where()
|
||||
.eq("clusterId", Long.parseLong(canalInstanceConfig.getClusterServerId().substring(8)));
|
||||
} else if (canalInstanceConfig.getClusterServerId().startsWith("server:")) {
|
||||
query.where().eq("serverId", Long.parseLong(canalInstanceConfig.getClusterServerId().substring(7)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return canalInstanceConfigs;
|
||||
Query<CanalInstanceConfig> queryCnt = query.copy();
|
||||
int count = queryCnt.findCount();
|
||||
pager.setCount((long) count);
|
||||
|
||||
query.setFirstRow(pager.getOffset().intValue()).setMaxRows(pager.getSize()).order().asc("id");
|
||||
List<CanalInstanceConfig> canalInstanceConfigs = query.findList();
|
||||
pager.setItems(canalInstanceConfigs);
|
||||
|
||||
if (canalInstanceConfigs.isEmpty()) {
|
||||
return pager;
|
||||
}
|
||||
|
||||
// check all canal instances running status
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(canalInstanceConfigs.size(),
|
||||
DaemonThreadFactory.daemonThreadFactory);
|
||||
List<Future<Void>> futures = new ArrayList<>(canalInstanceConfigs.size());
|
||||
|
||||
for (CanalInstanceConfig canalInstanceConfig1 : canalInstanceConfigs) {
|
||||
futures.add(executorService.submit(() -> {
|
||||
List<NodeServer> nodeServers;
|
||||
if (canalInstanceConfig1.getClusterId() != null) { // 集群模式
|
||||
nodeServers = NodeServer.find.query()
|
||||
.where()
|
||||
.eq("clusterId", canalInstanceConfig1.getClusterId())
|
||||
.findList();
|
||||
} else if (canalInstanceConfig1.getServerId() != null) { // 单机模式
|
||||
nodeServers = Collections.singletonList(canalInstanceConfig1.getNodeServer());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (NodeServer nodeServer : nodeServers) {
|
||||
String runningInstances = SimpleAdminConnectors
|
||||
.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::getRunningInstances);
|
||||
if (runningInstances == null) {
|
||||
continue;
|
||||
}
|
||||
String[] instances = runningInstances.split(",");
|
||||
for (String instance : instances) {
|
||||
if (instance.equals(canalInstanceConfig1.getName())) {
|
||||
if (canalInstanceConfig1.getNodeServer() == null) { // 集群模式下 server 对象为空
|
||||
canalInstanceConfig1.setNodeServer(nodeServer);
|
||||
}
|
||||
canalInstanceConfig1.setRunningStatus("1");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}));
|
||||
}
|
||||
|
||||
futures.forEach(f -> {
|
||||
try {
|
||||
f.get(3, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException | InterruptedException | ExecutionException e) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
executorService.shutdownNow();
|
||||
|
||||
return pager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过Server id获取当前Server下所有运行的Instance
|
||||
*
|
||||
* @param serverId server id
|
||||
*/
|
||||
public List<CanalInstanceConfig> findActiveInstaceByServerId(Long serverId) {
|
||||
NodeServer nodeServer = NodeServer.find.byId(serverId);
|
||||
if (nodeServer == null) {
|
||||
return null;
|
||||
}
|
||||
String runningInstances = SimpleAdminConnectors
|
||||
.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::getRunningInstances);
|
||||
if (runningInstances == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] instances = runningInstances.split(",");
|
||||
|
||||
// 单机模式和集群模式区分处理
|
||||
if (nodeServer.getClusterId() != null) { // 集群模式
|
||||
List<CanalInstanceConfig> list = CanalInstanceConfig.find.query()
|
||||
.setDisableLazyLoading(true)
|
||||
.select("clusterId, serverId, name, modifiedTime")
|
||||
.where()
|
||||
// 暂停的实例也显示 .eq("status", "1")
|
||||
.in("name", instances)
|
||||
.findList();
|
||||
list.forEach(config -> config.setRunningStatus("1"));
|
||||
return list; // 集群模式直接返回当前运行的Instances
|
||||
} else { // 单机模式
|
||||
// 当前Server所配置的所有Instance
|
||||
List<CanalInstanceConfig> list = CanalInstanceConfig.find.query()
|
||||
.setDisableLazyLoading(true)
|
||||
.select("clusterId, serverId, name, modifiedTime")
|
||||
.where()
|
||||
// 暂停的实例也显示 .eq("status", "1")
|
||||
.eq("serverId", serverId)
|
||||
.findList();
|
||||
List<String> instanceList = Arrays.asList(instances);
|
||||
list.forEach(config -> {
|
||||
if (instanceList.contains(config.getName())) {
|
||||
config.setRunningStatus("1");
|
||||
}
|
||||
});
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public void save(CanalInstanceConfig canalInstanceConfig) {
|
||||
if (StringUtils.isEmpty(canalInstanceConfig.getClusterServerId())) {
|
||||
throw new ServiceException("empty cluster or server id");
|
||||
}
|
||||
if (canalInstanceConfig.getClusterServerId().startsWith("cluster:")) {
|
||||
Long clusterId = Long.parseLong(canalInstanceConfig.getClusterServerId().substring(8));
|
||||
canalInstanceConfig.setClusterId(clusterId);
|
||||
} else if (canalInstanceConfig.getClusterServerId().startsWith("server:")) {
|
||||
Long serverId = Long.parseLong(canalInstanceConfig.getClusterServerId().substring(7));
|
||||
canalInstanceConfig.setServerId(serverId);
|
||||
}
|
||||
|
||||
try {
|
||||
String contentMd5 = SecurityUtil.md5String(canalInstanceConfig.getContent());
|
||||
canalInstanceConfig.setContentMd5(contentMd5);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
canalInstanceConfig.insert();
|
||||
}
|
||||
|
||||
public CanalInstanceConfig detail(Long id) {
|
||||
return CanalInstanceConfig.find.byId(id);
|
||||
CanalInstanceConfig canalInstanceConfig = CanalInstanceConfig.find.byId(id);
|
||||
if (canalInstanceConfig != null) {
|
||||
if (canalInstanceConfig.getClusterId() != null) {
|
||||
canalInstanceConfig.setClusterServerId("cluster:" + canalInstanceConfig.getClusterId());
|
||||
} else if (canalInstanceConfig.getServerId() != null) {
|
||||
canalInstanceConfig.setClusterServerId("server:" + canalInstanceConfig.getServerId());
|
||||
}
|
||||
}
|
||||
return canalInstanceConfig;
|
||||
}
|
||||
|
||||
public void updateContent(CanalInstanceConfig canalInstanceConfig) {
|
||||
canalInstanceConfig.update("content");
|
||||
if (StringUtils.isEmpty(canalInstanceConfig.getClusterServerId())) {
|
||||
throw new ServiceException("empty cluster or server id");
|
||||
}
|
||||
if (canalInstanceConfig.getClusterServerId().startsWith("cluster:")) {
|
||||
Long clusterId = Long.parseLong(canalInstanceConfig.getClusterServerId().substring(8));
|
||||
canalInstanceConfig.setClusterId(clusterId);
|
||||
canalInstanceConfig.setServerId(null);
|
||||
} else if (canalInstanceConfig.getClusterServerId().startsWith("server:")) {
|
||||
Long serverId = Long.parseLong(canalInstanceConfig.getClusterServerId().substring(7));
|
||||
canalInstanceConfig.setServerId(serverId);
|
||||
canalInstanceConfig.setClusterId(null);
|
||||
}
|
||||
|
||||
try {
|
||||
String contentMd5 = SecurityUtil.md5String(canalInstanceConfig.getContent());
|
||||
canalInstanceConfig.setContentMd5(contentMd5);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
canalInstanceConfig.update("content", "contentMd5", "clusterId", "serverId");
|
||||
}
|
||||
|
||||
public void delete(Long id) {
|
||||
@@ -133,13 +281,34 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
|
||||
}
|
||||
Boolean resutl = null;
|
||||
if ("start".equals(option)) {
|
||||
resutl = SimpleAdminConnectors.execute(nodeServer.getIp(),
|
||||
nodeServer.getAdminPort(),
|
||||
adminConnector -> adminConnector.startInstance(canalInstanceConfig.getName()));
|
||||
if (nodeServer.getClusterId() == null) { // 非集群模式
|
||||
return instanceOperation(id, "start");
|
||||
// resutl = SimpleAdminConnectors.execute(nodeServer.getIp(),
|
||||
// nodeServer.getAdminPort(),
|
||||
// adminConnector ->
|
||||
// adminConnector.startInstance(canalInstanceConfig.getName()));
|
||||
}
|
||||
} else if ("stop".equals(option)) {
|
||||
resutl = SimpleAdminConnectors.execute(nodeServer.getIp(),
|
||||
nodeServer.getAdminPort(),
|
||||
adminConnector -> adminConnector.stopInstance(canalInstanceConfig.getName()));
|
||||
if (nodeServer.getClusterId() != null) {
|
||||
resutl = SimpleAdminConnectors.execute(nodeServer.getIp(),
|
||||
nodeServer.getAdminPort(),
|
||||
adminConnector -> adminConnector.stopInstance(canalInstanceConfig.getName()));
|
||||
|
||||
NodeServer nodeServerTmp = nodeServer;
|
||||
// 集群模式下停止实例后过五秒钟再次启动进行启动抢占
|
||||
Thread thread = new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
SimpleAdminConnectors.execute(nodeServerTmp.getIp(),
|
||||
nodeServerTmp.getAdminPort(),
|
||||
adminConnector -> adminConnector.startInstance(canalInstanceConfig.getName()));
|
||||
} catch (Throwable e) {
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
} else { // 非集群模式下直接将状态置为0
|
||||
return instanceOperation(id, "stop");
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -150,4 +319,20 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
|
||||
return resutl;
|
||||
}
|
||||
|
||||
public boolean instanceOperation(Long id, String option) {
|
||||
CanalInstanceConfig canalInstanceConfig = CanalInstanceConfig.find.byId(id);
|
||||
if (canalInstanceConfig == null) {
|
||||
return false;
|
||||
}
|
||||
if ("stop".equals(option)) {
|
||||
canalInstanceConfig.setStatus("0");
|
||||
canalInstanceConfig.update("status");
|
||||
} else if ("start".equals(option)) {
|
||||
canalInstanceConfig.setStatus("1");
|
||||
canalInstanceConfig.update("status");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package com.alibaba.otter.canal.admin.service.impl;
|
||||
|
||||
import com.alibaba.otter.canal.admin.common.DaemonThreadFactory;
|
||||
import com.alibaba.otter.canal.admin.model.*;
|
||||
import io.ebean.Query;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -15,7 +14,6 @@ import org.springframework.stereotype.Service;
|
||||
import com.alibaba.otter.canal.admin.common.exception.ServiceException;
|
||||
import com.alibaba.otter.canal.admin.connector.AdminConnector;
|
||||
import com.alibaba.otter.canal.admin.connector.SimpleAdminConnectors;
|
||||
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||
import com.alibaba.otter.canal.admin.service.NodeServerService;
|
||||
|
||||
/**
|
||||
@@ -31,7 +29,7 @@ public class NodeServerServiceImpl implements NodeServerService {
|
||||
int cnt = NodeServer.find.query()
|
||||
.where()
|
||||
.eq("ip", nodeServer.getIp())
|
||||
.eq("admin_port", nodeServer.getAdminPort())
|
||||
.eq("adminPort", nodeServer.getAdminPort())
|
||||
.findCount();
|
||||
if (cnt > 0) {
|
||||
throw new ServiceException("节点信息已存在");
|
||||
@@ -48,25 +46,39 @@ public class NodeServerServiceImpl implements NodeServerService {
|
||||
int cnt = NodeServer.find.query()
|
||||
.where()
|
||||
.eq("ip", nodeServer.getIp())
|
||||
.eq("admin_port", nodeServer.getAdminPort())
|
||||
.eq("adminPort", nodeServer.getAdminPort())
|
||||
.ne("id", nodeServer.getId())
|
||||
.findCount();
|
||||
if (cnt > 0) {
|
||||
throw new ServiceException("节点信息已存在");
|
||||
}
|
||||
|
||||
nodeServer.update("name", "ip", "admin_port", "tcp_port", "metric_port");
|
||||
nodeServer.update("name", "ip", "adminPort", "tcpPort", "metricPort", "clusterId");
|
||||
}
|
||||
|
||||
public void delete(Long id) {
|
||||
NodeServer nodeServer = NodeServer.find.byId(id);
|
||||
if (nodeServer != null) {
|
||||
// 判断是否存在实例
|
||||
int cnt = CanalInstanceConfig.find.query().where().eq("serverId", nodeServer.getId()).findCount();
|
||||
if (cnt > 0) {
|
||||
throw new ServiceException("当前Server下存在Instance配置, 无法删除");
|
||||
}
|
||||
|
||||
// 同时删除配置
|
||||
CanalConfig canalConfig = CanalConfig.find.query().where().eq("serverId", id).findOne();
|
||||
if (canalConfig != null) {
|
||||
canalConfig.delete();
|
||||
}
|
||||
|
||||
nodeServer.delete();
|
||||
}
|
||||
}
|
||||
|
||||
public List<NodeServer> findList(NodeServer nodeServer) {
|
||||
private Query<NodeServer> getBaseQuery(NodeServer nodeServer) {
|
||||
Query<NodeServer> query = NodeServer.find.query();
|
||||
query.fetch("canalCluster", "name").setDisableLazyLoading(true);
|
||||
|
||||
if (nodeServer != null) {
|
||||
if (StringUtils.isNotEmpty(nodeServer.getName())) {
|
||||
query.where().like("name", "%" + nodeServer.getName() + "%");
|
||||
@@ -74,14 +86,45 @@ public class NodeServerServiceImpl implements NodeServerService {
|
||||
if (StringUtils.isNotEmpty(nodeServer.getIp())) {
|
||||
query.where().eq("ip", nodeServer.getIp());
|
||||
}
|
||||
}
|
||||
query.order().asc("id");
|
||||
List<NodeServer> nodeServers = query.findList();
|
||||
if (nodeServers.isEmpty()) {
|
||||
return nodeServers;
|
||||
if (nodeServer.getClusterId() != null) {
|
||||
if (nodeServer.getClusterId() == -1) {
|
||||
query.where().isNull("clusterId");
|
||||
} else {
|
||||
query.where().eq("clusterId", nodeServer.getClusterId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(nodeServers.size());
|
||||
return query;
|
||||
}
|
||||
|
||||
public List<NodeServer> findAll(NodeServer nodeServer) {
|
||||
Query<NodeServer> query = getBaseQuery(nodeServer);
|
||||
query.order().asc("id");
|
||||
return query.findList();
|
||||
}
|
||||
|
||||
public Pager<NodeServer> findList(NodeServer nodeServer, Pager<NodeServer> pager) {
|
||||
|
||||
Query<NodeServer> query = getBaseQuery(nodeServer);
|
||||
Query<NodeServer> queryCnt = query.copy();
|
||||
|
||||
int count = queryCnt.findCount();
|
||||
pager.setCount((long) count);
|
||||
|
||||
List<NodeServer> nodeServers = query.order()
|
||||
.asc("id")
|
||||
.setFirstRow(pager.getOffset().intValue())
|
||||
.setMaxRows(pager.getSize())
|
||||
.findList();
|
||||
pager.setItems(nodeServers);
|
||||
|
||||
if (nodeServers.isEmpty()) {
|
||||
return pager;
|
||||
}
|
||||
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(nodeServers.size(),
|
||||
DaemonThreadFactory.daemonThreadFactory);
|
||||
List<Future<Boolean>> futures = new ArrayList<>(nodeServers.size());
|
||||
// get all nodes status
|
||||
for (NodeServer ns : nodeServers) {
|
||||
@@ -93,15 +136,15 @@ public class NodeServerServiceImpl implements NodeServerService {
|
||||
}
|
||||
futures.forEach(f -> {
|
||||
try {
|
||||
f.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
f.get(3, TimeUnit.SECONDS);
|
||||
} catch (TimeoutException | InterruptedException | ExecutionException e) {
|
||||
// ignore
|
||||
}
|
||||
});
|
||||
|
||||
executorService.shutdownNow();
|
||||
|
||||
return nodeServers;
|
||||
return pager;
|
||||
}
|
||||
|
||||
public int remoteNodeStatus(String ip, Integer port) {
|
||||
@@ -114,9 +157,8 @@ public class NodeServerServiceImpl implements NodeServerService {
|
||||
if (nodeServer == null) {
|
||||
return "";
|
||||
}
|
||||
return SimpleAdminConnectors.execute(nodeServer.getIp(),
|
||||
nodeServer.getAdminPort(),
|
||||
adminConnector -> adminConnector.canalLog(100));
|
||||
return SimpleAdminConnectors
|
||||
.execute(nodeServer.getIp(), nodeServer.getAdminPort(), adminConnector -> adminConnector.canalLog(100));
|
||||
}
|
||||
|
||||
public boolean remoteOperation(Long id, String option) {
|
||||
@@ -126,7 +168,8 @@ public class NodeServerServiceImpl implements NodeServerService {
|
||||
}
|
||||
Boolean result = null;
|
||||
if ("start".equals(option)) {
|
||||
result = SimpleAdminConnectors.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::start);
|
||||
result = SimpleAdminConnectors
|
||||
.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::start);
|
||||
} else if ("stop".equals(option)) {
|
||||
result = SimpleAdminConnectors.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::stop);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.alibaba.otter.canal.admin.service.impl;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.alibaba.otter.canal.admin.model.CanalConfig;
|
||||
import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
|
||||
import com.alibaba.otter.canal.admin.model.NodeServer;
|
||||
import com.alibaba.otter.canal.admin.service.PollingConfigServer;
|
||||
import com.alibaba.otter.canal.protocol.SecurityUtil;
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
@Service
|
||||
public class PollingConfigServiceImpl implements PollingConfigServer {
|
||||
|
||||
public CanalConfig getChangedConfig(String ip, Integer port, String md5) {
|
||||
NodeServer server = NodeServer.find.query().where().eq("ip", ip).eq("adminPort", port).findOne();
|
||||
if (server == null) {
|
||||
return null;
|
||||
}
|
||||
CanalConfig canalConfig;
|
||||
if (server.getClusterId() != null) { // 集群模式
|
||||
canalConfig = CanalConfig.find.query().where().eq("clusterId", server.getClusterId()).findOne();
|
||||
} else { // 单机模式
|
||||
canalConfig = CanalConfig.find.query().where().eq("serverId", server.getId()).findOne();
|
||||
}
|
||||
if (canalConfig != null && !canalConfig.getContentMd5().equals(md5)) { // 内容发生变化
|
||||
return canalConfig;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public CanalInstanceConfig getInstancesConfig(String ip, Integer port, String md5) {
|
||||
NodeServer server = NodeServer.find.query().where().eq("ip", ip).eq("adminPort", port).findOne();
|
||||
if (server == null) {
|
||||
return null;
|
||||
}
|
||||
List<CanalInstanceConfig> canalInstanceConfigs;
|
||||
if (server.getClusterId() != null) { // 集群模式
|
||||
canalInstanceConfigs = CanalInstanceConfig.find.query()
|
||||
.where()
|
||||
.eq("status", "1")
|
||||
.eq("clusterId", server.getClusterId())
|
||||
.findList(); // 取属于该集群的所有instance config
|
||||
} else { // 单机模式
|
||||
canalInstanceConfigs = CanalInstanceConfig.find.query()
|
||||
.where()
|
||||
.eq("status", "1")
|
||||
.eq("serverId", server.getId())
|
||||
.findList();
|
||||
}
|
||||
|
||||
CanalInstanceConfig canalInstanceConfig = new CanalInstanceConfig();
|
||||
List<String> instances = canalInstanceConfigs.stream()
|
||||
.map(CanalInstanceConfig::getName)
|
||||
.collect(Collectors.toList());
|
||||
String data = Joiner.on(',').join(instances);
|
||||
canalInstanceConfig.setContent(data);
|
||||
if (!StringUtils.isEmpty(md5)) {
|
||||
try {
|
||||
String newMd5 = SecurityUtil.md5String(canalInstanceConfig.getContent());
|
||||
if (StringUtils.equals(md5, newMd5)) {
|
||||
canalInstanceConfig.setContent(null);
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return canalInstanceConfig;
|
||||
}
|
||||
|
||||
public CanalInstanceConfig getInstanceConfig(String destination, String md5) {
|
||||
CanalInstanceConfig instanceConfig = CanalInstanceConfig.find.query().where().eq("name", destination).findOne();
|
||||
if (instanceConfig == null) {
|
||||
return null;
|
||||
}
|
||||
if (StringUtils.isEmpty(md5)) {
|
||||
return instanceConfig;
|
||||
} else {
|
||||
try {
|
||||
String newMd5 = SecurityUtil.md5String(instanceConfig.getContent());
|
||||
if (StringUtils.equals(md5, newMd5)) {
|
||||
instanceConfig.setContent(null);
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return instanceConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,14 @@ spring:
|
||||
time-zone: GMT+8
|
||||
|
||||
spring.datasource:
|
||||
url: jdbc:mysql://127.0.0.1:3306/canal_manager?useUnicode=true&characterEncoding=UTF-8&useSSL=false
|
||||
username: root
|
||||
password: 121212
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
hikari:
|
||||
maximum-pool-size: 10
|
||||
minimum-idle: 1
|
||||
url: jdbc:mysql://127.0.0.1:3306/canal_manager?useUnicode=true&characterEncoding=UTF-8&useSSL=false
|
||||
username: root
|
||||
password: 121212
|
||||
driver-class-name: com.mysql.jdbc.Driver
|
||||
hikari:
|
||||
maximum-pool-size: 10
|
||||
minimum-idle: 1
|
||||
|
||||
canal:
|
||||
adminUser: admin
|
||||
adminPasswd: admin
|
||||
adminUser: admin
|
||||
adminPasswd: admin
|
||||
|
||||
@@ -17,7 +17,19 @@ CREATE TABLE `canal_adapter_config` (
|
||||
`content` text NOT NULL,
|
||||
`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for canal_cluster
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `canal_cluster`;
|
||||
CREATE TABLE `canal_cluster` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(63) NOT NULL,
|
||||
`zk_hosts` varchar(255) NOT NULL,
|
||||
`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for canal_config
|
||||
@@ -25,13 +37,16 @@ CREATE TABLE `canal_adapter_config` (
|
||||
DROP TABLE IF EXISTS `canal_config`;
|
||||
CREATE TABLE `canal_config` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`cluster_id` bigint(20) DEFAULT NULL,
|
||||
`server_id` bigint(20) DEFAULT NULL,
|
||||
`name` varchar(45) NOT NULL,
|
||||
`status` varchar(45) DEFAULT NULL,
|
||||
`content` text NOT NULL,
|
||||
`content_md5` varchar(128) NOT NULL,
|
||||
`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `name_UNIQUE` (`name`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
|
||||
UNIQUE KEY `sid_UNIQUE` (`server_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for canal_instance_config
|
||||
@@ -39,13 +54,16 @@ CREATE TABLE `canal_config` (
|
||||
DROP TABLE IF EXISTS `canal_instance_config`;
|
||||
CREATE TABLE `canal_instance_config` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`cluster_id` bigint(20) DEFAULT NULL,
|
||||
`server_id` bigint(20) DEFAULT NULL,
|
||||
`name` varchar(45) NOT NULL,
|
||||
`status` varchar(45) DEFAULT NULL,
|
||||
`content` text NOT NULL,
|
||||
`content_md5` varchar(128) DEFAULT NULL,
|
||||
`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `name_UNIQUE` (`name`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for canal_node_server
|
||||
@@ -53,6 +71,7 @@ CREATE TABLE `canal_instance_config` (
|
||||
DROP TABLE IF EXISTS `canal_node_server`;
|
||||
CREATE TABLE `canal_node_server` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`cluster_id` bigint(20) DEFAULT NULL,
|
||||
`name` varchar(63) NOT NULL,
|
||||
`ip` varchar(63) NOT NULL,
|
||||
`admin_port` int(11) DEFAULT NULL,
|
||||
@@ -61,7 +80,7 @@ CREATE TABLE `canal_node_server` (
|
||||
`status` varchar(45) DEFAULT NULL,
|
||||
`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for canal_user
|
||||
@@ -77,7 +96,9 @@ CREATE TABLE `canal_user` (
|
||||
`avatar` varchar(255) DEFAULT NULL,
|
||||
`creation_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of canal_user
|
||||
|
||||
@@ -38,4 +38,10 @@
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="CANAL-ROOT" />
|
||||
</root>
|
||||
|
||||
<logger name="io.ebean.SQL" additivity="false">
|
||||
<level value="INFO" />
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="CANAL-ROOT" />
|
||||
</logger>
|
||||
</configuration>
|
||||
|
||||
@@ -1 +1 @@
|
||||
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=/favicon.ico><title>Canal Admin</title><link href=/static/css/chunk-elementUI.18b11d0e.css rel=stylesheet><link href=/static/css/chunk-libs.5cf311f0.css rel=stylesheet><link href=/static/css/app.bb951cb3.css rel=stylesheet></head><body><noscript><strong>We're sorry but Canal Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/static/js/chunk-elementUI.667f4c87.js></script><script src=/static/js/chunk-libs.c04beefc.js></script><script>(function(e){function n(n){for(var r,c,o=n[0],a=n[1],i=n[2],h=0,l=[];h<o.length;h++)c=o[h],u[c]&&l.push(u[c][0]),u[c]=0;for(r in a)Object.prototype.hasOwnProperty.call(a,r)&&(e[r]=a[r]);d&&d(n);while(l.length)l.shift()();return f.push.apply(f,i||[]),t()}function t(){for(var e,n=0;n<f.length;n++){for(var t=f[n],r=!0,c=1;c<t.length;c++){var o=t[c];0!==u[o]&&(r=!1)}r&&(f.splice(n--,1),e=a(a.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},f=[];function o(e){return a.p+"static/js/"+({}[e]||e)+"."+{"chunk-101fc062":"bc898027","chunk-137eaf06":"4b6e5771","chunk-238a81e9":"273bda76","chunk-37c49cbf":"64d26540","chunk-3fcdf643":"4b7133b8","chunk-1ef583f0":"9f611126","chunk-5560c396":"55ba7544","chunk-6f6d6145":"8b7e1719","chunk-4f09fed2":"ff28d88d","chunk-69386cf0":"76d77f5c","chunk-7ec889b7":"6ba68ef0","chunk-e1a839e4":"4357a0af"}[e]+".js"}function a(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var n=[],t={"chunk-101fc062":1,"chunk-238a81e9":1,"chunk-37c49cbf":1,"chunk-1ef583f0":1,"chunk-5560c396":1,"chunk-6f6d6145":1,"chunk-4f09fed2":1,"chunk-69386cf0":1,"chunk-7ec889b7":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise(function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-101fc062":"fad9926f","chunk-137eaf06":"31d6cfe0","chunk-238a81e9":"e8e2beee","chunk-37c49cbf":"efc21a9c","chunk-3fcdf643":"31d6cfe0","chunk-1ef583f0":"ec3a43f5","chunk-5560c396":"b660603c","chunk-6f6d6145":"bf63041a","chunk-4f09fed2":"70ec0b86","chunk-69386cf0":"741ff14e","chunk-7ec889b7":"c0585512","chunk-e1a839e4":"31d6cfe0"}[e]+".css",u=a.p+r,f=document.getElementsByTagName("link"),o=0;o<f.length;o++){var i=f[o],h=i.getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(h===r||h===u))return n()}var l=document.getElementsByTagName("style");for(o=0;o<l.length;o++){i=l[o],h=i.getAttribute("data-href");if(h===r||h===u)return n()}var d=document.createElement("link");d.rel="stylesheet",d.type="text/css",d.onload=n,d.onerror=function(n){var r=n&&n.target&&n.target.src||u,f=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");f.code="CSS_CHUNK_LOAD_FAILED",f.request=r,delete c[e],d.parentNode.removeChild(d),t(f)},d.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(d)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var f=new Promise(function(n,t){r=u[e]=[n,t]});n.push(r[2]=f);var i,h=document.createElement("script");h.charset="utf-8",h.timeout=120,a.nc&&h.setAttribute("nonce",a.nc),h.src=o(e),i=function(n){h.onerror=h.onload=null,clearTimeout(l);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,f=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");f.type=r,f.request=c,t[1](f)}u[e]=void 0}};var l=setTimeout(function(){i({type:"timeout",target:h})},12e4);h.onerror=h.onload=i,document.head.appendChild(h)}return Promise.all(n)},a.m=e,a.c=r,a.d=function(e,n,t){a.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},a.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,n){if(1&n&&(e=a(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)a.d(t,r,function(n){return e[n]}.bind(null,r));return t},a.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return a.d(n,"a",n),n},a.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},a.p="/",a.oe=function(e){throw console.error(e),e};var i=window["webpackJsonp"]=window["webpackJsonp"]||[],h=i.push.bind(i);i.push=n,i=i.slice();for(var l=0;l<i.length;l++)n(i[l]);var d=h;t()})([]);</script><script src=/static/js/app.a89b2d02.js></script></body></html>
|
||||
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=/favicon.ico><title>Canal Admin</title><link href=/static/css/chunk-elementUI.18b11d0e.css rel=stylesheet><link href=/static/css/chunk-libs.5cf311f0.css rel=stylesheet><link href=/static/css/app.bb951cb3.css rel=stylesheet></head><body><noscript><strong>We're sorry but Canal Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/static/js/chunk-elementUI.667f4c87.js></script><script src=/static/js/chunk-libs.c04beefc.js></script><script>(function(e){function n(n){for(var r,c,f=n[0],a=n[1],i=n[2],d=0,h=[];d<f.length;d++)c=f[d],u[c]&&h.push(u[c][0]),u[c]=0;for(r in a)Object.prototype.hasOwnProperty.call(a,r)&&(e[r]=a[r]);l&&l(n);while(h.length)h.shift()();return o.push.apply(o,i||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],r=!0,c=1;c<t.length;c++){var f=t[c];0!==u[f]&&(r=!1)}r&&(o.splice(n--,1),e=a(a.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function f(e){return a.p+"static/js/"+({}[e]||e)+"."+{"chunk-0dca2f22":"a2bc28b8","chunk-2301924a":"b0e97fa6","chunk-98f505d0":"aade2e3b","chunk-bd1d44ee":"c2f6b1a9","chunk-101fc062":"bc898027","chunk-14b5f7a4":"d0531bb5","chunk-22553be3":"21abed4f","chunk-37c49cbf":"64d26540","chunk-49959c8b":"6d226f70","chunk-4f09fed2":"ff28d88d","chunk-55380ff2":"681c71c9","chunk-69386cf0":"76d77f5c","chunk-7ec889b7":"295b8aad"}[e]+".js"}function a(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,a),t.l=!0,t.exports}a.e=function(e){var n=[],t={"chunk-2301924a":1,"chunk-98f505d0":1,"chunk-bd1d44ee":1,"chunk-101fc062":1,"chunk-14b5f7a4":1,"chunk-22553be3":1,"chunk-37c49cbf":1,"chunk-49959c8b":1,"chunk-4f09fed2":1,"chunk-69386cf0":1,"chunk-7ec889b7":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise(function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-0dca2f22":"31d6cfe0","chunk-2301924a":"160e7b4a","chunk-98f505d0":"5280f88f","chunk-bd1d44ee":"1528199a","chunk-101fc062":"fad9926f","chunk-14b5f7a4":"f3e06673","chunk-22553be3":"f3e06673","chunk-37c49cbf":"efc21a9c","chunk-49959c8b":"e8e2beee","chunk-4f09fed2":"70ec0b86","chunk-55380ff2":"31d6cfe0","chunk-69386cf0":"741ff14e","chunk-7ec889b7":"c0585512"}[e]+".css",u=a.p+r,o=document.getElementsByTagName("link"),f=0;f<o.length;f++){var i=o[f],d=i.getAttribute("data-href")||i.getAttribute("href");if("stylesheet"===i.rel&&(d===r||d===u))return n()}var h=document.getElementsByTagName("style");for(f=0;f<h.length;f++){i=h[f],d=i.getAttribute("data-href");if(d===r||d===u)return n()}var l=document.createElement("link");l.rel="stylesheet",l.type="text/css",l.onload=n,l.onerror=function(n){var r=n&&n.target&&n.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=r,delete c[e],l.parentNode.removeChild(l),t(o)},l.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(l)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var o=new Promise(function(n,t){r=u[e]=[n,t]});n.push(r[2]=o);var i,d=document.createElement("script");d.charset="utf-8",d.timeout=120,a.nc&&d.setAttribute("nonce",a.nc),d.src=f(e),i=function(n){d.onerror=d.onload=null,clearTimeout(h);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");o.type=r,o.request=c,t[1](o)}u[e]=void 0}};var h=setTimeout(function(){i({type:"timeout",target:d})},12e4);d.onerror=d.onload=i,document.head.appendChild(d)}return Promise.all(n)},a.m=e,a.c=r,a.d=function(e,n,t){a.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},a.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,n){if(1&n&&(e=a(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(a.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)a.d(t,r,function(n){return e[n]}.bind(null,r));return t},a.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return a.d(n,"a",n),n},a.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},a.p="/",a.oe=function(e){throw console.error(e),e};var i=window["webpackJsonp"]=window["webpackJsonp"]||[],d=i.push.bind(i);i.push=n,i=i.slice();for(var h=0;h<i.length;h++)n(i[h]);var l=d;t()})([]);</script><script src=/static/js/app.cae6e777.js></script></body></html>
|
||||
@@ -0,0 +1 @@
|
||||
.pagination-container[data-v-cebf2f0c]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-cebf2f0c]{display:none}
|
||||
@@ -0,0 +1 @@
|
||||
.pagination-container[data-v-cebf2f0c]{background:#fff;padding:32px 16px}.pagination-container.hidden[data-v-cebf2f0c]{display:none}
|
||||
@@ -0,0 +1 @@
|
||||
.line[data-v-28f0cd0f]{text-align:center}
|
||||
@@ -0,0 +1 @@
|
||||
.wscn-http404-container[data-v-c095f994]{-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);position:absolute;top:40%;left:50%}.wscn-http404[data-v-c095f994]{position:relative;width:1200px;padding:0 50px;overflow:hidden}.wscn-http404 .pic-404[data-v-c095f994]{position:relative;float:left;width:600px;overflow:hidden}.wscn-http404 .pic-404__parent[data-v-c095f994]{width:100%}.wscn-http404 .pic-404__child[data-v-c095f994]{position:absolute}.wscn-http404 .pic-404__child.left[data-v-c095f994]{width:80px;top:17px;left:220px;opacity:0;-webkit-animation-name:cloudLeft-data-v-c095f994;animation-name:cloudLeft-data-v-c095f994;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}.wscn-http404 .pic-404__child.mid[data-v-c095f994]{width:46px;top:10px;left:420px;opacity:0;-webkit-animation-name:cloudMid-data-v-c095f994;animation-name:cloudMid-data-v-c095f994;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1.2s;animation-delay:1.2s}.wscn-http404 .pic-404__child.right[data-v-c095f994]{width:62px;top:100px;left:500px;opacity:0;-webkit-animation-name:cloudRight-data-v-c095f994;animation-name:cloudRight-data-v-c095f994;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-timing-function:linear;animation-timing-function:linear;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-delay:1s;animation-delay:1s}@-webkit-keyframes cloudLeft-data-v-c095f994{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@keyframes cloudLeft-data-v-c095f994{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@-webkit-keyframes cloudMid-data-v-c095f994{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@keyframes cloudMid-data-v-c095f994{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@-webkit-keyframes cloudRight-data-v-c095f994{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}@keyframes cloudRight-data-v-c095f994{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}.wscn-http404 .bullshit[data-v-c095f994]{position:relative;float:left;width:300px;padding:30px 0;overflow:hidden}.wscn-http404 .bullshit__oops[data-v-c095f994]{font-size:32px;line-height:40px;color:#1482f0;margin-bottom:20px;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__headline[data-v-c095f994],.wscn-http404 .bullshit__oops[data-v-c095f994]{font-weight:700;opacity:0;-webkit-animation-name:slideUp-data-v-c095f994;animation-name:slideUp-data-v-c095f994;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__headline[data-v-c095f994]{font-size:20px;line-height:24px;color:#222;margin-bottom:10px;-webkit-animation-delay:.1s;animation-delay:.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-c095f994]{font-size:13px;line-height:21px;color:grey;margin-bottom:30px;-webkit-animation-delay:.2s;animation-delay:.2s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-c095f994],.wscn-http404 .bullshit__return-home[data-v-c095f994]{opacity:0;-webkit-animation-name:slideUp-data-v-c095f994;animation-name:slideUp-data-v-c095f994;-webkit-animation-duration:.5s;animation-duration:.5s}.wscn-http404 .bullshit__return-home[data-v-c095f994]{display:block;float:left;width:110px;height:36px;background:#1482f0;border-radius:100px;text-align:center;color:#fff;font-size:14px;line-height:36px;cursor:pointer;-webkit-animation-delay:.3s;animation-delay:.3s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards}@-webkit-keyframes slideUp-data-v-c095f994{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}@keyframes slideUp-data-v-c095f994{0%{-webkit-transform:translateY(60px);transform:translateY(60px);opacity:0}to{-webkit-transform:translateY(0);transform:translateY(0);opacity:1}}
|
||||
@@ -0,0 +1 @@
|
||||
.line[data-v-35af5ff9]{text-align:center}
|
||||
@@ -0,0 +1 @@
|
||||
.line[data-v-5c332416]{text-align:center}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2301924a"],{"10df":function(t,e,n){},1248:function(t,e,n){"use strict";n.r(e);var r=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",[n("el-form",{ref:"form",attrs:{model:t.form}},[n("div",{staticClass:"filter-container",staticStyle:{"padding-left":"10px","padding-top":"20px"}},[n("el-input",{staticClass:"filter-item",staticStyle:{width:"200px"},attrs:{placeholder:"Instance名称"},model:{value:t.form.name,callback:function(e){t.$set(t.form,"name",e)},expression:"form.name"}}),t._v(" "),n("el-select",{staticClass:"filter-item",attrs:{placeholder:"所属集群/主机"},model:{value:t.form.clusterServerId,callback:function(e){t.$set(t.form,"clusterServerId",e)},expression:"form.clusterServerId"}},t._l(t.options,function(e){return n("el-option-group",{key:e.label,attrs:{label:e.label}},t._l(e.options,function(t){return n("el-option",{key:t.value,attrs:{label:t.label,value:t.value}})}),1)}),1),t._v(" "),n("el-button",{staticClass:"filter-item",attrs:{type:"primary"},on:{click:t.onSubmit}},[t._v("保存")]),t._v(" "),n("el-button",{staticClass:"filter-item",attrs:{type:"info"},on:{click:t.onBack}},[t._v("返回")])],1),t._v(" "),n("editor",{attrs:{lang:"properties",theme:"chrome",width:"100%",height:800},on:{init:t.editorInit},model:{value:t.form.content,callback:function(e){t.$set(t.form,"content",e)},expression:"form.content"}})],1)],1)},a=[],c=(n("7f7f"),n("f546")),o=n("d631"),u={components:{editor:n("7c9e")},data:function(){return{options:[],form:{name:"",content:"",clusterServerId:""}}},created:function(){var t=this;Object(o["d"])().then(function(e){t.options=e.data})},methods:{editorInit:function(){n("2099"),n("be9d"),n("2968"),n("e0e5"),n("bb36"),n("0329"),n("95b8"),n("6a21")},onSubmit:function(){var t=this;""!==this.form.name?""!==this.form.clusterServerId?null!==this.form.content&&""!==this.form.content?this.$confirm("确定新建","确定新建",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then(function(){Object(c["a"])(t.form).then(function(e){"success"===e.data?(t.$message({message:"新建成功",type:"success"}),t.$router.push("/canalServer/canalInstances")):t.$message({message:"新建失败",type:"error"})})}):this.$message({message:"请输入配置内容",type:"error"}):this.$message({message:"请选择所属集群/主机",type:"error"}):this.$message({message:"请输入Instance名称",type:"error"})},onBack:function(){history.go(-1)}}},i=u,s=(n("2eb8"),n("2877")),l=Object(s["a"])(i,r,a,!1,null,"28f0cd0f",null);e["default"]=l.exports},"2eb8":function(t,e,n){"use strict";var r=n("10df"),a=n.n(r);a.a},d631:function(t,e,n){"use strict";n.d(e,"c",function(){return a}),n.d(e,"a",function(){return c}),n.d(e,"e",function(){return o}),n.d(e,"b",function(){return u}),n.d(e,"d",function(){return i});var r=n("b775");function a(t){return Object(r["a"])({url:"/canal/clusters",method:"get",params:t})}function c(t){return Object(r["a"])({url:"/canal/cluster",method:"post",data:t})}function o(t){return Object(r["a"])({url:"/canal/cluster",method:"put",data:t})}function u(t){return Object(r["a"])({url:"/canal/cluster/"+t,method:"delete"})}function i(){return Object(r["a"])({url:"/canal/clustersAndServers",method:"get"})}},f546:function(t,e,n){"use strict";n.d(e,"e",function(){return a}),n.d(e,"b",function(){return c}),n.d(e,"j",function(){return o}),n.d(e,"a",function(){return u}),n.d(e,"c",function(){return i}),n.d(e,"h",function(){return s}),n.d(e,"i",function(){return l}),n.d(e,"f",function(){return f}),n.d(e,"g",function(){return d}),n.d(e,"d",function(){return m});var r=n("b775");function a(t){return Object(r["a"])({url:"/canal/instances",method:"get",params:t})}function c(t){return Object(r["a"])({url:"/canal/instance/"+t,method:"get"})}function o(t){return Object(r["a"])({url:"/canal/instance",method:"put",data:t})}function u(t){return Object(r["a"])({url:"/canal/instance",method:"post",data:t})}function i(t){return Object(r["a"])({url:"/canal/instance/"+t,method:"delete"})}function s(t,e){return Object(r["a"])({url:"/canal/instance/start/"+t+"/"+e,method:"put"})}function l(t,e){return Object(r["a"])({url:"/canal/instance/stop/"+t+"/"+e,method:"put"})}function f(t,e){return Object(r["a"])({url:"/canal/instance/log/"+t+"/"+e,method:"get"})}function d(t,e){return Object(r["a"])({url:"/canal/instance/status/"+t+"?option="+e,method:"put"})}function m(t){return Object(r["a"])({url:"/canal/active/instances/"+t,method:"get"})}}}]);
|
||||
@@ -0,0 +1 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-49959c8b"],{"26fc":function(t,s,a){t.exports=a.p+"static/img/404_cloud.0f4bc32b.png"},"8cdb":function(t,s,a){"use strict";a.r(s);var e=function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"wscn-http404-container"},[a("div",{staticClass:"wscn-http404"},[t._m(0),t._v(" "),a("div",{staticClass:"bullshit"},[a("div",{staticClass:"bullshit__oops"},[t._v("OOPS!")]),t._v(" "),t._m(1),t._v(" "),a("div",{staticClass:"bullshit__headline"},[t._v(t._s(t.message))]),t._v(" "),a("div",{staticClass:"bullshit__info"},[t._v("Please check that the URL you entered is correct, or click the button below to return to the homepage.")]),t._v(" "),a("a",{staticClass:"bullshit__return-home",attrs:{href:""}},[t._v("Back to home")])])])])},c=[function(){var t=this,s=t.$createElement,e=t._self._c||s;return e("div",{staticClass:"pic-404"},[e("img",{staticClass:"pic-404__parent",attrs:{src:a("a36b"),alt:"404"}}),t._v(" "),e("img",{staticClass:"pic-404__child left",attrs:{src:a("26fc"),alt:"404"}}),t._v(" "),e("img",{staticClass:"pic-404__child mid",attrs:{src:a("26fc"),alt:"404"}}),t._v(" "),e("img",{staticClass:"pic-404__child right",attrs:{src:a("26fc"),alt:"404"}})])},function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("div",{staticClass:"bullshit__info"},[t._v("All rights reserved\n "),a("a",{staticStyle:{color:"#20a0ff"},attrs:{href:"https://wallstreetcn.com",target:"_blank"}},[t._v("wallstreetcn")])])}],i={name:"Page404",computed:{message:function(){return"The webmaster said that you can not enter this page..."}}},l=i,n=(a("97ef"),a("2877")),r=Object(n["a"])(l,e,c,!1,null,"c095f994",null);s["default"]=r.exports},"97ef":function(t,s,a){"use strict";var e=a("b51e"),c=a.n(e);c.a},a36b:function(t,s,a){t.exports=a.p+"static/img/404.a57b6f31.png"},b51e:function(t,s,a){}}]);
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-7ec889b7"],{"11ec":function(t,n,e){},"7f19":function(t,n,e){"use strict";var c=e("11ec"),r=e.n(c);r.a},"7f84":function(t,n,e){"use strict";e.r(n);var c=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e("div",[e("el-form",{ref:"form",attrs:{model:t.form}},[e("div",{staticStyle:{"padding-left":"10px","padding-right":"10px","padding-top":"20px"}},[e("el-form-item",[t._v("\n "+t._s(t.form.instance)+" \n "),e("el-button",{attrs:{type:"primary"},on:{click:t.onRefresh}},[t._v("刷新")]),t._v(" "),e("el-button",{attrs:{type:"info"},on:{click:t.onBack}},[t._v("返回")])],1),t._v(" "),e("el-input",{attrs:{rows:35,readonly:"readonly",type:"textarea"},model:{value:t.form.desc,callback:function(n){t.$set(t.form,"desc",n)},expression:"form.desc"}})],1)])],1)},r=[],a=e("f546"),o={data:function(){return{form:{instance:"",desc:""}}},created:function(){this.fetchData()},methods:{fetchData:function(){var t=this;Object(a["f"])(this.$route.query.id,this.$route.query.nodeId).then(function(n){t.form.instance=n.data.instance+".log",t.form.desc=n.data.log})},onRefresh:function(){this.fetchData()},onBack:function(){history.go(-1)}}},u=o,i=(e("7f19"),e("2877")),f=Object(i["a"])(u,c,r,!1,null,"0b80198c",null);n["default"]=f.exports},f546:function(t,n,e){"use strict";e.d(n,"e",function(){return r}),e.d(n,"b",function(){return a}),e.d(n,"j",function(){return o}),e.d(n,"a",function(){return u}),e.d(n,"c",function(){return i}),e.d(n,"h",function(){return f}),e.d(n,"i",function(){return s}),e.d(n,"f",function(){return d}),e.d(n,"g",function(){return l}),e.d(n,"d",function(){return h});var c=e("b775");function r(t){return Object(c["a"])({url:"/canal/instances",method:"get",params:t})}function a(t){return Object(c["a"])({url:"/canal/instance/"+t,method:"get"})}function o(t){return Object(c["a"])({url:"/canal/instance",method:"put",data:t})}function u(t){return Object(c["a"])({url:"/canal/instance",method:"post",data:t})}function i(t){return Object(c["a"])({url:"/canal/instance/"+t,method:"delete"})}function f(t,n){return Object(c["a"])({url:"/canal/instance/start/"+t+"/"+n,method:"put"})}function s(t,n){return Object(c["a"])({url:"/canal/instance/stop/"+t+"/"+n,method:"put"})}function d(t,n){return Object(c["a"])({url:"/canal/instance/log/"+t+"/"+n,method:"get"})}function l(t,n){return Object(c["a"])({url:"/canal/instance/status/"+t+"?option="+n,method:"put"})}function h(t){return Object(c["a"])({url:"/canal/active/instances/"+t,method:"get"})}}}]);
|
||||
@@ -0,0 +1 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-98f505d0"],{"4e8a":function(t,e,n){"use strict";var o=n("727e"),r=n.n(o);r.a},"727e":function(t,e,n){},aa99:function(t,e,n){"use strict";n.r(e);var o=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",[n("el-form",{ref:"form",attrs:{model:t.form}},[n("div",{staticStyle:{"padding-left":"10px","padding-top":"20px"}},[n("el-form-item",[t._v("\n "+t._s(t.form.name)+" \n "),n("el-button",{attrs:{type:"primary"},on:{click:t.onSubmit}},[t._v("保存")]),t._v(" "),n("el-button",{attrs:{type:"warning"},on:{click:t.onCancel}},[t._v("重置")]),t._v(" "),n("el-button",{attrs:{type:"info"},on:{click:t.onBack}},[t._v("返回")])],1)],1),t._v(" "),n("editor",{attrs:{lang:"properties",theme:"chrome",width:"100%",height:800},on:{init:t.editorInit},model:{value:t.form.content,callback:function(e){t.$set(t.form,"content",e)},expression:"form.content"}})],1)],1)},r=[],a=(n("7f7f"),n("b775"));function i(t,e){return Object(a["a"])({url:"/canal/config/"+t+"/"+e,method:"get"})}function c(t){return Object(a["a"])({url:"/canal/config",method:"put",data:t})}var s={components:{editor:n("7c9e")},data:function(){return{form:{id:null,name:"",content:"",serverId:null,clusterId:null}}},created:function(){this.loadCanalConfig()},methods:{editorInit:function(){n("2099"),n("be9d"),n("2968"),n("e0e5"),n("bb36"),n("0329"),n("95b8"),n("6a21")},loadCanalConfig:function(){var t=this,e=0,n=0;this.$route.query.clusterId?e=this.$route.query.clusterId:this.$route.query.serverId&&(n=this.$route.query.serverId),i(e,n).then(function(e){var n=e.data;t.form.id=n.id,t.form.name=n.name,t.form.content=n.content,t.form.serverId=t.$route.query.serverId,t.form.clusterId=t.$route.query.clusterId})},onSubmit:function(){var t=this;null!==this.form.content&&""!==this.form.content?this.$confirm("修改主配置可能会导致Server重启,是否继续?","确定修改",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then(function(){c(t.form).then(function(e){"success"===e.data?(t.$message({message:"保存成功",type:"success"}),t.loadCanalConfig()):t.$message({message:"保存失败",type:"error"})})}):this.$message({message:"配置内容不能为空",type:"error"})},onCancel:function(){this.loadCanalConfig()},onBack:function(){history.go(-1)}}},u=s,f=(n("4e8a"),n("2877")),l=Object(f["a"])(u,o,r,!1,null,"35af5ff9",null);e["default"]=l.exports}}]);
|
||||
@@ -0,0 +1 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-bd1d44ee"],{"878d":function(t,n,e){},b0a2:function(t,n,e){"use strict";e.r(n);var r=function(){var t=this,n=t.$createElement,e=t._self._c||n;return e("div",[e("el-form",{ref:"form",attrs:{model:t.form}},[e("div",{staticStyle:{"padding-left":"10px","padding-top":"20px"}},[e("el-form-item",[t._v("\n "+t._s(t.form.name)+" \n "),e("el-select",{staticClass:"filter-item",attrs:{placeholder:"所属集群/主机"},model:{value:t.form.clusterServerId,callback:function(n){t.$set(t.form,"clusterServerId",n)},expression:"form.clusterServerId"}},t._l(t.options,function(n){return e("el-option-group",{key:n.label,attrs:{label:n.label}},t._l(n.options,function(t){return e("el-option",{key:t.value,attrs:{label:t.label,value:t.value}})}),1)}),1),t._v(" "),e("el-button",{attrs:{type:"primary"},on:{click:t.onSubmit}},[t._v("修改")]),t._v(" "),e("el-button",{attrs:{type:"warning"},on:{click:t.onCancel}},[t._v("重置")]),t._v(" "),e("el-button",{attrs:{type:"info"},on:{click:t.onBack}},[t._v("返回")])],1)],1),t._v(" "),e("editor",{attrs:{lang:"properties",theme:"chrome",width:"100%",height:800},on:{init:t.editorInit},model:{value:t.form.content,callback:function(n){t.$set(t.form,"content",n)},expression:"form.content"}})],1)],1)},o=[],c=(e("7f7f"),e("f546")),a=e("d631"),u={components:{editor:e("7c9e")},data:function(){return{options:[],form:{id:null,name:"",content:"",clusterServerId:""}}},created:function(){var t=this;this.loadCanalConfig(),Object(a["d"])().then(function(n){t.options=n.data})},methods:{editorInit:function(){e("2099"),e("be9d"),e("2968"),e("e0e5"),e("bb36"),e("0329"),e("95b8"),e("6a21")},loadCanalConfig:function(){var t=this;Object(c["b"])(this.$route.query.id).then(function(n){var e=n.data;t.form.id=e.id,t.form.name=e.name+"/instance.propertios",t.form.content=e.content,t.form.clusterServerId=e.clusterServerId})},onSubmit:function(){var t=this;this.$confirm("修改Instance配置可能会导致重启,是否继续?","确定修改",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then(function(){Object(c["j"])(t.form).then(function(n){"success"===n.data?(t.$message({message:"修改成功",type:"success"}),t.loadCanalConfig()):t.$message({message:"修改失败",type:"error"})})})},onCancel:function(){this.loadCanalConfig()},onBack:function(){history.go(-1)}}},i=u,l=(e("de9c"),e("2877")),s=Object(l["a"])(i,r,o,!1,null,"5c332416",null);n["default"]=s.exports},d631:function(t,n,e){"use strict";e.d(n,"c",function(){return o}),e.d(n,"a",function(){return c}),e.d(n,"e",function(){return a}),e.d(n,"b",function(){return u}),e.d(n,"d",function(){return i});var r=e("b775");function o(t){return Object(r["a"])({url:"/canal/clusters",method:"get",params:t})}function c(t){return Object(r["a"])({url:"/canal/cluster",method:"post",data:t})}function a(t){return Object(r["a"])({url:"/canal/cluster",method:"put",data:t})}function u(t){return Object(r["a"])({url:"/canal/cluster/"+t,method:"delete"})}function i(){return Object(r["a"])({url:"/canal/clustersAndServers",method:"get"})}},de9c:function(t,n,e){"use strict";var r=e("878d"),o=e.n(r);o.a},f546:function(t,n,e){"use strict";e.d(n,"e",function(){return o}),e.d(n,"b",function(){return c}),e.d(n,"j",function(){return a}),e.d(n,"a",function(){return u}),e.d(n,"c",function(){return i}),e.d(n,"h",function(){return l}),e.d(n,"i",function(){return s}),e.d(n,"f",function(){return d}),e.d(n,"g",function(){return f}),e.d(n,"d",function(){return m});var r=e("b775");function o(t){return Object(r["a"])({url:"/canal/instances",method:"get",params:t})}function c(t){return Object(r["a"])({url:"/canal/instance/"+t,method:"get"})}function a(t){return Object(r["a"])({url:"/canal/instance",method:"put",data:t})}function u(t){return Object(r["a"])({url:"/canal/instance",method:"post",data:t})}function i(t){return Object(r["a"])({url:"/canal/instance/"+t,method:"delete"})}function l(t,n){return Object(r["a"])({url:"/canal/instance/start/"+t+"/"+n,method:"put"})}function s(t,n){return Object(r["a"])({url:"/canal/instance/stop/"+t+"/"+n,method:"put"})}function d(t,n){return Object(r["a"])({url:"/canal/instance/log/"+t+"/"+n,method:"get"})}function f(t,n){return Object(r["a"])({url:"/canal/instance/status/"+t+"?option="+n,method:"put"})}function m(t){return Object(r["a"])({url:"/canal/active/instances/"+t,method:"get"})}}}]);
|
||||
Reference in New Issue
Block a user