diff --git a/canal-admin/canal-admin-server/pom.xml b/canal-admin/canal-admin-server/pom.xml
index aa9c4c4c..9fcb1c86 100644
--- a/canal-admin/canal-admin-server/pom.xml
+++ b/canal-admin/canal-admin-server/pom.xml
@@ -8,9 +8,7 @@
1.1.4-SNAPSHOT
4.0.0
-
canal-admin-server
-
com.alibaba.otter
@@ -199,6 +197,39 @@
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.0.2
+
+
+ application.yml
+ canal_manager.sql
+
+
+
+
+ maven-assembly-plugin
+ 2.2.1
+
+
+ assemble
+
+ single
+
+ package
+
+
+
+ false
+ false
+
+ ${basedir}/src/main/assembly/release.xml
+
+ canal-admin-${project.version}
+ ${project.basedir}/../../target
+
+
diff --git a/canal-admin/canal-admin-server/src/main/assembly/release.xml b/canal-admin/canal-admin-server/src/main/assembly/release.xml
new file mode 100644
index 00000000..f7b66376
--- /dev/null
+++ b/canal-admin/canal-admin-server/src/main/assembly/release.xml
@@ -0,0 +1,41 @@
+
+ dist
+
+ tar.gz
+
+ false
+
+
+ .
+ /
+
+ README*
+
+
+
+ ./src/main/bin
+ bin
+
+ **/*
+
+ 0755
+
+
+ ./src/main/resources
+ /conf
+
+ application.yml
+ canal_manager.sql
+
+
+
+ ./target
+ /lib
+
+ canal-admin-*.jar
+
+
+
+
\ No newline at end of file
diff --git a/canal-admin/canal-admin-server/src/main/bin/restart.sh b/canal-admin/canal-admin-server/src/main/bin/restart.sh
new file mode 100644
index 00000000..63749ce5
--- /dev/null
+++ b/canal-admin/canal-admin-server/src/main/bin/restart.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+sh stop.sh
+
+sh startup.sh
diff --git a/canal-admin/canal-admin-server/src/main/bin/startup.bat b/canal-admin/canal-admin-server/src/main/bin/startup.bat
new file mode 100755
index 00000000..840f0c03
--- /dev/null
+++ b/canal-admin/canal-admin-server/src/main/bin/startup.bat
@@ -0,0 +1,22 @@
+@echo off
+@if not "%ECHO%" == "" echo %ECHO%
+@if "%OS%" == "Windows_NT" setlocal
+
+set ENV_PATH=.\
+if "%OS%" == "Windows_NT" set ENV_PATH=%~dp0%
+
+set conf_dir=%ENV_PATH%\..\conf
+
+set CLASSPATH=%conf_dir%
+set CLASSPATH=%conf_dir%\..\lib\*;%CLASSPATH%
+
+set JAVA_MEM_OPTS= -Xms128m -Xmx512m
+set JAVA_OPTS_EXT= -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Dapplication.codeset=UTF-8 -Dfile.encoding=UTF-8
+set ADAPTER_OPTS= -DappName=canal-admin
+
+set JAVA_OPTS= %JAVA_MEM_OPTS% %JAVA_OPTS_EXT% %ADAPTER_OPTS%
+
+set CMD_STR= java %JAVA_OPTS% -classpath "%CLASSPATH%" com.alibaba.otter.canal.admin.CanalAdminApplication
+echo start cmd : %CMD_STR%
+
+java %JAVA_OPTS% -classpath "%CLASSPATH%" com.alibaba.otter.canal.admin.CanalAdminApplication
\ No newline at end of file
diff --git a/canal-admin/canal-admin-server/src/main/bin/startup.sh b/canal-admin/canal-admin-server/src/main/bin/startup.sh
new file mode 100644
index 00000000..ec18c408
--- /dev/null
+++ b/canal-admin/canal-admin-server/src/main/bin/startup.sh
@@ -0,0 +1,84 @@
+#!/bin/bash
+
+current_path=`pwd`
+case "`uname`" in
+ Linux)
+ bin_abs_path=$(readlink -f $(dirname $0))
+ ;;
+ *)
+ bin_abs_path=`cd $(dirname $0); pwd`
+ ;;
+esac
+base=${bin_abs_path}/..
+export LANG=en_US.UTF-8
+export BASE=$base
+
+if [ -f $base/bin/adapter.pid ] ; then
+ echo "found adapter.pid , Please run stop.sh first ,then startup.sh" 2>&2
+ exit 1
+fi
+
+if [ ! -d $base/logs ] ; then
+ mkdir -p $base/logs
+fi
+
+## set java path
+if [ -z "$JAVA" ] ; then
+ JAVA=$(which java)
+fi
+
+ALIBABA_JAVA="/usr/alibaba/java/bin/java"
+TAOBAO_JAVA="/opt/taobao/java/bin/java"
+if [ -z "$JAVA" ]; then
+ if [ -f $ALIBABA_JAVA ] ; then
+ JAVA=$ALIBABA_JAVA
+ elif [ -f $TAOBAO_JAVA ] ; then
+ JAVA=$TAOBAO_JAVA
+ else
+ echo "Cannot find a Java JDK. Please set either set JAVA or put java (>=1.5) in your PATH." 2>&2
+ exit 1
+ fi
+fi
+
+case "$#"
+in
+0 )
+ ;;
+2 )
+ if [ "$1" = "debug" ]; then
+ DEBUG_PORT=$2
+ DEBUG_SUSPEND="n"
+ JAVA_DEBUG_OPT="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=$DEBUG_PORT,server=y,suspend=$DEBUG_SUSPEND"
+ fi
+ ;;
+* )
+ echo "THE PARAMETERS MUST BE TWO OR LESS.PLEASE CHECK AGAIN."
+ exit;;
+esac
+
+str=`file -L $JAVA | grep 64-bit`
+if [ -n "$str" ]; then
+ JAVA_OPTS="-server -Xms2048m -Xmx3072m"
+else
+ JAVA_OPTS="-server -Xms1024m -Xmx1024m"
+fi
+
+JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=250 -XX:+UseGCOverheadLimit -XX:+ExplicitGCInvokesConcurrent -XX:+PrintAdaptiveSizePolicy -XX:+PrintTenuringDistribution"
+JAVA_OPTS=" $JAVA_OPTS -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8"
+CANAL_OPTS="-DappName=canal-admin"
+
+for i in $base/lib/*;
+ do CLASSPATH=$i:"$CLASSPATH";
+done
+
+CLASSPATH="$base/conf:$CLASSPATH";
+
+echo "cd to $bin_abs_path for workaround relative path"
+cd $bin_abs_path
+
+echo CLASSPATH :$CLASSPATH
+$JAVA $JAVA_OPTS $JAVA_DEBUG_OPT $CANAL_OPTS -classpath .:$CLASSPATH com.alibaba.otter.canal.admin.CanalAdminApplication 1>>/dev/null 2>&1 &
+echo $! > $base/bin/admin.pid
+
+echo "cd to $current_path for continue"
+cd $current_path
\ No newline at end of file
diff --git a/canal-admin/canal-admin-server/src/main/bin/stop.sh b/canal-admin/canal-admin-server/src/main/bin/stop.sh
new file mode 100644
index 00000000..05415ad9
--- /dev/null
+++ b/canal-admin/canal-admin-server/src/main/bin/stop.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+cygwin=false;
+linux=false;
+case "`uname`" in
+ CYGWIN*)
+ cygwin=true
+ ;;
+ Linux*)
+ linux=true
+ ;;
+esac
+
+get_pid() {
+ STR=$1
+ PID=$2
+ if $cygwin; then
+ JAVA_CMD="$JAVA_HOME\bin\java"
+ JAVA_CMD=`cygpath --path --unix $JAVA_CMD`
+ JAVA_PID=`ps |grep $JAVA_CMD |awk '{print $1}'`
+ else
+ if $linux; then
+ if [ ! -z "$PID" ]; then
+ JAVA_PID=`ps -C java -f --width 1000|grep "$STR"|grep "$PID"|grep -v grep|awk '{print $2}'`
+ else
+ JAVA_PID=`ps -C java -f --width 1000|grep "$STR"|grep -v grep|awk '{print $2}'`
+ fi
+ else
+ if [ ! -z "$PID" ]; then
+ JAVA_PID=`ps aux |grep "$STR"|grep "$PID"|grep -v grep|awk '{print $2}'`
+ else
+ JAVA_PID=`ps aux |grep "$STR"|grep -v grep|awk '{print $2}'`
+ fi
+ fi
+ fi
+ echo $JAVA_PID;
+}
+
+base=`dirname $0`/..
+pidfile=$base/bin/admin.pid
+if [ ! -f "$pidfile" ];then
+ echo "canal-admin is not running. exists"
+ exit
+fi
+
+pid=`cat $pidfile`
+if [ "$pid" == "" ] ; then
+ pid=`get_pid "appName=canal-admin"`
+fi
+
+echo -e "`hostname`: stopping canal $pid ... "
+kill $pid
+
+LOOPS=0
+while (true);
+do
+ gpid=`get_pid "appName=canal-admin" "$pid"`
+ if [ "$gpid" == "" ] ; then
+ echo "Oook! cost:$LOOPS"
+ `rm $pidfile`
+ break;
+ fi
+ let LOOPS=LOOPS+1
+ sleep 1
+done
\ No newline at end of file
diff --git a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/config/WebConfig.java b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/config/WebConfig.java
index fde7d6b4..07512fce 100644
--- a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/config/WebConfig.java
+++ b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/config/WebConfig.java
@@ -74,8 +74,8 @@ public class WebConfig implements WebMvcConfigurer {
httpServletResponse.setContentType("application/json;charset=UTF-8");
PrintWriter out = httpServletResponse.getWriter();
out.print(json);
- } catch (Exception e) {
- e.printStackTrace();
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
}
return false;
}
@@ -84,6 +84,7 @@ public class WebConfig implements WebMvcConfigurer {
}
})
.addPathPatterns("/api/**")
+ .excludePathPatterns("/api/**/config/**")
.excludePathPatterns("/api/**/user/login")
.excludePathPatterns("/api/**/user/logout")
.excludePathPatterns("/api/**/user/info");
diff --git a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/controller/CanalConfigController.java b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/controller/CanalConfigController.java
index 1bc65b9a..3ebc392a 100644
--- a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/controller/CanalConfigController.java
+++ b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/controller/CanalConfigController.java
@@ -1,7 +1,12 @@
package com.alibaba.otter.canal.admin.controller;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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 com.alibaba.otter.canal.admin.model.BaseModel;
import com.alibaba.otter.canal.admin.model.CanalConfig;
@@ -31,17 +36,6 @@ public class CanalConfigController {
return BaseModel.getInstance(canalConfigService.getCanalConfig());
}
- /**
- * 获取配置信息摘要(无配置内容)
- *
- * @param env 环境变量
- * @return 配置信息摘要
- */
- @GetMapping(value = "/config/summary")
- public BaseModel canalConfigSummary(@PathVariable String env) {
- return BaseModel.getInstance(canalConfigService.getCanalConfigSummary());
- }
-
/**
* 修改配置
*
@@ -54,4 +48,5 @@ public class CanalConfigController {
canalConfigService.updateContent(canalConfig);
return BaseModel.getInstance("success");
}
+
}
diff --git a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/controller/PollConfigController.java b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/controller/PollConfigController.java
new file mode 100644
index 00000000..0ac74ef1
--- /dev/null
+++ b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/controller/PollConfigController.java
@@ -0,0 +1,155 @@
+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 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.protocol.SecurityUtil;
+import com.google.common.base.Joiner;
+
+/**
+ * Canal Instance配置管理控制层
+ *
+ * @author rewerma 2019-07-13 下午05:12:16
+ * @version 1.0.0
+ */
+@RestController
+@RequestMapping("/api/{env}/config")
+public class PollConfigController {
+
+ 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;
+
+ /**
+ * 获取server全局配置
+ */
+ @GetMapping(value = "/server_poll")
+ public BaseModel canalConfigPoll(@RequestHeader String user, @RequestHeader String passwd,
+ @PathVariable String env, @RequestParam String md5) {
+ 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);
+ }
+ }
+
+ /**
+ * 获取单个instance的配置
+ */
+ @GetMapping(value = "/instance_poll/{destination}")
+ public BaseModel instanceConfigPoll(@RequestHeader String user, @RequestHeader String passwd,
+ @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);
+ }
+ }
+
+ /**
+ * 获取对应server(ip+port)所需要运行的instance列表
+ */
+ @GetMapping(value = "/instances_poll")
+ public BaseModel instancesPoll(@RequestHeader String user, @RequestHeader String passwd,
+ @PathVariable String env, @RequestParam String ip,
+ @RequestParam String port, @RequestParam String md5) {
+ if (!auth(user, passwd)) {
+ throw new RuntimeException("auth :" + user + " is failed");
+ }
+
+ CanalInstanceConfig canalInstanceConfig = new CanalInstanceConfig();
+ List configs = canalInstanceConfigService.findList(canalInstanceConfig);
+ List instances = configs.stream().map(config -> config.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);
+ }
+ }
+
+ private boolean auth(String user, String passwd) {
+ // 如果user/passwd密码为空,则任何用户账户都能登录
+ if ((StringUtils.isEmpty(this.user) || StringUtils.equals(this.user, user))) {
+ if (StringUtils.isEmpty(this.passwd)) {
+ return true;
+ } else if (StringUtils.isEmpty(passwd)) {
+ // 如果server密码有配置,客户端密码为空,则拒绝
+ return false;
+ }
+
+ try {
+ // manager这里保存了原始密码,反过来和canal发送过来的进行校验
+ byte[] passForClient = SecurityUtil.scramble411(this.passwd.getBytes(), seeds);
+ return SecurityUtil.scrambleServerAuth(passForClient, SecurityUtil.hexStr2Bytes(passwd), seeds);
+ } catch (NoSuchAlgorithmException e) {
+ return false;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/CanalConfig.java b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/CanalConfig.java
index f9220afe..409d07e7 100644
--- a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/CanalConfig.java
+++ b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/CanalConfig.java
@@ -33,6 +33,7 @@ public class CanalConfig extends Model {
private Long id;
private String name;
private String content;
+ private String status;
private Date modifiedTime;
public Long getId() {
@@ -66,4 +67,13 @@ public class CanalConfig extends Model {
public void setModifiedTime(Date modifiedTime) {
this.modifiedTime = modifiedTime;
}
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
}
diff --git a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/CanalInstanceConfig.java b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/CanalInstanceConfig.java
index 490c0ea6..e103a1e6 100644
--- a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/CanalInstanceConfig.java
+++ b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/CanalInstanceConfig.java
@@ -2,10 +2,11 @@ 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 java.util.Date;
/**
* Canal实例配置信息实体类
@@ -33,6 +34,7 @@ public class CanalInstanceConfig extends Model {
private Long id;
private String name;
private String content;
+ private String status;
private Date modifiedTime;
@Transient
@@ -64,6 +66,14 @@ public class CanalInstanceConfig extends Model {
this.content = content;
}
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
public Date getModifiedTime() {
return modifiedTime;
}
diff --git a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/NodeServer.java b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/NodeServer.java
index 20369c05..1f9834ee 100644
--- a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/NodeServer.java
+++ b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/model/NodeServer.java
@@ -1,13 +1,13 @@
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.Table;
-import io.ebean.Finder;
-
/**
* 节点信息实体类
*
@@ -35,13 +35,14 @@ public class NodeServer extends Model {
private Long id;
private String name;
private String ip;
- private Integer port;
- private Integer port2;
- private Integer status;
+ private Integer adminPort;
+ private Integer metricPort;
+ private Integer tcpPort;
+ private String status;
private Date modifiedTime;
public void init() {
- status = -1;
+ status = "-1";
}
public Long getId() {
@@ -68,27 +69,35 @@ public class NodeServer extends Model {
this.ip = ip;
}
- public Integer getPort() {
- return port;
+ public Integer getAdminPort() {
+ return adminPort;
}
- public void setPort(Integer port) {
- this.port = port;
+ public void setAdminPort(Integer adminPort) {
+ this.adminPort = adminPort;
}
- public Integer getPort2() {
- return port2;
+ public Integer getMetricPort() {
+ return metricPort;
}
- public void setPort2(Integer port2) {
- this.port2 = port2;
+ public void setMetricPort(Integer metricPort) {
+ this.metricPort = metricPort;
}
- public Integer getStatus() {
+ public Integer getTcpPort() {
+ return tcpPort;
+ }
+
+ public void setTcpPort(Integer tcpPort) {
+ this.tcpPort = tcpPort;
+ }
+
+ public String getStatus() {
return status;
}
- public void setStatus(Integer status) {
+ public void setStatus(String status) {
this.status = status;
}
diff --git a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/CanalInstanceService.java b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/CanalInstanceService.java
index 5f7ae443..1bc9c29a 100644
--- a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/CanalInstanceService.java
+++ b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/CanalInstanceService.java
@@ -1,10 +1,10 @@
package com.alibaba.otter.canal.admin.service;
-import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
-
import java.util.List;
import java.util.Map;
+import com.alibaba.otter.canal.admin.model.CanalInstanceConfig;
+
/**
* Canal实例配置信息业务层接口
*
@@ -19,6 +19,8 @@ public interface CanalInstanceService {
CanalInstanceConfig detail(Long id);
+ CanalInstanceConfig findOne(String name);
+
void updateContent(CanalInstanceConfig canalInstanceConfig);
void delete(Long id);
diff --git a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/CanalInstanceServiceImpl.java b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/CanalInstanceServiceImpl.java
index 659eff08..f60d767e 100644
--- a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/CanalInstanceServiceImpl.java
+++ b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/CanalInstanceServiceImpl.java
@@ -40,7 +40,7 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
List nodeServers = NodeServer.find.query().findList();
for (NodeServer nodeServer : nodeServers) {
String runningInstances = SimpleAdminConnectors.execute(nodeServer.getIp(),
- nodeServer.getPort(),
+ nodeServer.getAdminPort(),
AdminConnector::getRunningInstances);
if (runningInstances == null) {
continue;
@@ -79,6 +79,16 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
}
}
+ @Override
+ public CanalInstanceConfig findOne(String name) {
+ CanalInstanceConfig config = CanalInstanceConfig.find.query()
+ .setDisableLazyLoading(true)
+ .where()
+ .eq("name", name)
+ .findOne();
+ return config;
+ }
+
public Map remoteInstanceLog(Long id, Long nodeId) {
Map result = new HashMap<>();
@@ -92,7 +102,7 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
}
String log = SimpleAdminConnectors.execute(nodeServer.getIp(),
- nodeServer.getPort(),
+ nodeServer.getAdminPort(),
adminConnector -> adminConnector.instanceLog(canalInstanceConfig.getName(), null, 100));
result.put("instance", canalInstanceConfig.getName());
@@ -124,11 +134,11 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
Boolean resutl = null;
if ("start".equals(option)) {
resutl = SimpleAdminConnectors.execute(nodeServer.getIp(),
- nodeServer.getPort(),
+ nodeServer.getAdminPort(),
adminConnector -> adminConnector.startInstance(canalInstanceConfig.getName()));
} else if ("stop".equals(option)) {
resutl = SimpleAdminConnectors.execute(nodeServer.getIp(),
- nodeServer.getPort(),
+ nodeServer.getAdminPort(),
adminConnector -> adminConnector.stopInstance(canalInstanceConfig.getName()));
} else {
return false;
@@ -139,4 +149,5 @@ public class CanalInstanceServiceImpl implements CanalInstanceService {
}
return resutl;
}
+
}
diff --git a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/NodeServerServiceImpl.java b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/NodeServerServiceImpl.java
index d6b2ce8b..5f9610af 100644
--- a/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/NodeServerServiceImpl.java
+++ b/canal-admin/canal-admin-server/src/main/java/com/alibaba/otter/canal/admin/service/impl/NodeServerServiceImpl.java
@@ -31,7 +31,7 @@ public class NodeServerServiceImpl implements NodeServerService {
int cnt = NodeServer.find.query()
.where()
.eq("ip", nodeServer.getIp())
- .eq("port", nodeServer.getPort())
+ .eq("admin_port", nodeServer.getAdminPort())
.findCount();
if (cnt > 0) {
throw new ServiceException("节点信息已存在");
@@ -48,14 +48,14 @@ public class NodeServerServiceImpl implements NodeServerService {
int cnt = NodeServer.find.query()
.where()
.eq("ip", nodeServer.getIp())
- .eq("port", nodeServer.getPort())
+ .eq("admin_port", nodeServer.getAdminPort())
.ne("id", nodeServer.getId())
.findCount();
if (cnt > 0) {
throw new ServiceException("节点信息已存在");
}
- nodeServer.update("name", "ip", "port", "port2");
+ nodeServer.update("name", "ip", "admin_port", "tcp_port", "metric_port");
}
public void delete(Long id) {
@@ -86,8 +86,8 @@ public class NodeServerServiceImpl implements NodeServerService {
// get all nodes status
for (NodeServer ns : nodeServers) {
futures.add(executorService.submit(() -> {
- boolean status = SimpleAdminConnectors.execute(ns.getIp(), ns.getPort(), AdminConnector::check);
- ns.setStatus(status ? 1 : 0);
+ boolean status = SimpleAdminConnectors.execute(ns.getIp(), ns.getAdminPort(), AdminConnector::check);
+ ns.setStatus(status ? "1" : "0");
return !status;
}));
}
@@ -115,7 +115,7 @@ public class NodeServerServiceImpl implements NodeServerService {
return "";
}
return SimpleAdminConnectors.execute(nodeServer.getIp(),
- nodeServer.getPort(),
+ nodeServer.getAdminPort(),
adminConnector -> adminConnector.canalLog(100));
}
@@ -126,9 +126,9 @@ public class NodeServerServiceImpl implements NodeServerService {
}
Boolean result = null;
if ("start".equals(option)) {
- result = SimpleAdminConnectors.execute(nodeServer.getIp(), nodeServer.getPort(), AdminConnector::start);
+ result = SimpleAdminConnectors.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::start);
} else if ("stop".equals(option)) {
- result = SimpleAdminConnectors.execute(nodeServer.getIp(), nodeServer.getPort(), AdminConnector::stop);
+ result = SimpleAdminConnectors.execute(nodeServer.getIp(), nodeServer.getAdminPort(), AdminConnector::stop);
} else {
return false;
}
diff --git a/canal-admin/canal-admin-server/src/main/resources/application.yml b/canal-admin/canal-admin-server/src/main/resources/application.yml
index d241e35a..7adc1c7a 100644
--- a/canal-admin/canal-admin-server/src/main/resources/application.yml
+++ b/canal-admin/canal-admin-server/src/main/resources/application.yml
@@ -13,3 +13,7 @@ spring.datasource:
hikari:
maximum-pool-size: 10
minimum-idle: 1
+
+canal:
+ adminUser: admin
+ adminPasswd: admin
diff --git a/canal-admin/canal-admin-server/src/main/resources/canal_manager.sql b/canal-admin/canal-admin-server/src/main/resources/canal_manager.sql
index 9ca6de4f..a926380d 100644
--- a/canal-admin/canal-admin-server/src/main/resources/canal_manager.sql
+++ b/canal-admin/canal-admin-server/src/main/resources/canal_manager.sql
@@ -13,10 +13,11 @@ CREATE TABLE `canal_adapter_config` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`category` varchar(45) NOT NULL,
`name` varchar(45) NOT NULL,
+ `status` varchar(45) DEFAULT NULL,
`content` text NOT NULL,
`modified_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
-) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for canal_config
@@ -25,11 +26,12 @@ DROP TABLE IF EXISTS `canal_config`;
CREATE TABLE `canal_config` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(45) NOT NULL,
+ `status` varchar(45) DEFAULT NULL,
`content` text 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=3 DEFAULT CHARSET=utf8mb4;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for canal_instance_config
@@ -38,11 +40,12 @@ DROP TABLE IF EXISTS `canal_instance_config`;
CREATE TABLE `canal_instance_config` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(45) NOT NULL,
+ `status` varchar(45) DEFAULT NULL,
`content` text 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=2 DEFAULT CHARSET=utf8mb4;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Table structure for canal_node_server
@@ -52,9 +55,10 @@ CREATE TABLE `canal_node_server` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(63) NOT NULL,
`ip` varchar(63) NOT NULL,
- `port` int(11) DEFAULT NULL,
- `port2` int(11) DEFAULT NULL,
- `status` int(11) NOT NULL,
+ `admin_port` int(11) DEFAULT NULL,
+ `tcp_port` int(11) DEFAULT NULL,
+ `metric_port` int(11) DEFAULT NULL,
+ `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;
@@ -73,7 +77,7 @@ 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=2 DEFAULT CHARSET=utf8mb4;
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
-- ----------------------------
-- Records of canal_user
diff --git a/canal-admin/canal-admin-server/src/main/resources/public/index.html b/canal-admin/canal-admin-server/src/main/resources/public/index.html
index b76917f2..6f6beecc 100644
--- a/canal-admin/canal-admin-server/src/main/resources/public/index.html
+++ b/canal-admin/canal-admin-server/src/main/resources/public/index.html
@@ -1 +1 @@
-Canal Admin
\ No newline at end of file
+Canal Admin
\ No newline at end of file
diff --git a/canal-admin/canal-admin-server/src/main/resources/public/static/js/chunk-e1a839e4.7ee86dd8.js b/canal-admin/canal-admin-server/src/main/resources/public/static/js/chunk-e1a839e4.7ee86dd8.js
deleted file mode 100644
index 33f85501..00000000
--- a/canal-admin/canal-admin-server/src/main/resources/public/static/js/chunk-e1a839e4.7ee86dd8.js
+++ /dev/null
@@ -1 +0,0 @@
-(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-e1a839e4"],{"9f66":function(e,t,n){"use strict";n.r(t);var r=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"app-container"},[n("div",{staticClass:"filter-container"},[n("el-button",{staticClass:"filter-item",attrs:{type:"primary"},on:{click:function(t){return e.handleCreate()}}},[e._v("新建Server")]),e._v(" "),n("el-button",{staticClass:"filter-item",attrs:{type:"info"},on:{click:function(t){return e.fetchData()}}},[e._v("刷新列表")])],1),e._v(" "),n("el-table",{directives:[{name:"loading",rawName:"v-loading",value:e.listLoading,expression:"listLoading"}],attrs:{data:e.list,"element-loading-text":"Loading",border:"",fit:"","highlight-current-row":""}},[n("el-table-column",{attrs:{label:"Server 名称","min-width":"200",align:"center"},scopedSlots:e._u([{key:"default",fn:function(t){return[e._v("\n "+e._s(t.row.name)+"\n ")]}}])}),e._v(" "),n("el-table-column",{attrs:{label:"Server IP","min-width":"200",align:"center"},scopedSlots:e._u([{key:"default",fn:function(t){return[n("span",[e._v(e._s(t.row.ip))])]}}])}),e._v(" "),n("el-table-column",{attrs:{label:"Admin 端口","min-width":"100",align:"center"},scopedSlots:e._u([{key:"default",fn:function(t){return[e._v("\n "+e._s(t.row.port)+"\n ")]}}])}),e._v(" "),n("el-table-column",{attrs:{label:"监控端口","min-width":"100",align:"center"},scopedSlots:e._u([{key:"default",fn:function(t){return[e._v("\n "+e._s(t.row.port2)+"\n ")]}}])}),e._v(" "),n("el-table-column",{attrs:{"class-name":"status-col",label:"状态","min-width":"150",align:"center"},scopedSlots:e._u([{key:"default",fn:function(t){return[n("el-tag",{attrs:{type:e._f("statusFilter")(t.row.status)}},[e._v(e._s(e._f("statusLabel")(t.row.status)))])]}}])}),e._v(" "),n("el-table-column",{attrs:{align:"center",prop:"created_at",label:"操作","min-width":"150"},scopedSlots:e._u([{key:"default",fn:function(t){return[n("el-dropdown",{attrs:{trigger:"click"}},[n("el-button",{attrs:{type:"primary",size:"mini"}},[e._v("\n 操作"),n("i",{staticClass:"el-icon-arrow-down el-icon--right"})]),e._v(" "),n("el-dropdown-menu",{attrs:{slot:"dropdown"},slot:"dropdown"},[n("el-dropdown-item",{nativeOn:{click:function(n){return e.handleUpdate(t.row)}}},[e._v("修改")]),e._v(" "),n("el-dropdown-item",{nativeOn:{click:function(n){return e.handleDelete(t.row)}}},[e._v("删除")]),e._v(" "),n("el-dropdown-item",{nativeOn:{click:function(n){return e.handleStart(t.row)}}},[e._v("启动")]),e._v(" "),n("el-dropdown-item",{nativeOn:{click:function(n){return e.handleStop(t.row)}}},[e._v("停止")]),e._v(" "),n("el-dropdown-item",{nativeOn:{click:function(n){return e.handleLog(t.row)}}},[e._v("日志")])],1)],1)]}}])})],1),e._v(" "),n("el-dialog",{attrs:{visible:e.dialogFormVisible,title:e.textMap[e.dialogStatus],width:"600px"},on:{"update:visible":function(t){e.dialogFormVisible=t}}},[n("el-form",{ref:"dataForm",staticStyle:{width:"400px","margin-left":"30px"},attrs:{rules:e.rules,model:e.nodeModel,"label-position":"left","label-width":"120px"}},[n("el-form-item",{attrs:{label:"Server 名称",prop:"name"}},[n("el-input",{model:{value:e.nodeModel.name,callback:function(t){e.$set(e.nodeModel,"name",t)},expression:"nodeModel.name"}})],1),e._v(" "),n("el-form-item",{attrs:{label:"Server IP",prop:"ip"}},[n("el-input",{model:{value:e.nodeModel.ip,callback:function(t){e.$set(e.nodeModel,"ip",t)},expression:"nodeModel.ip"}})],1),e._v(" "),n("el-form-item",{attrs:{label:"Admin 端口",prop:"port"}},[n("el-input",{attrs:{placeholder:"11110",type:"number"},model:{value:e.nodeModel.port,callback:function(t){e.$set(e.nodeModel,"port",t)},expression:"nodeModel.port"}})],1),e._v(" "),n("el-form-item",{attrs:{label:"监控端口",prop:"port2"}},[n("el-input",{attrs:{placeholder:"11112",type:"number"},model:{value:e.nodeModel.port2,callback:function(t){e.$set(e.nodeModel,"port2",t)},expression:"nodeModel.port2"}})],1)],1),e._v(" "),n("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[n("el-button",{on:{click:function(t){e.dialogFormVisible=!1}}},[e._v("取消")]),e._v(" "),n("el-button",{attrs:{type:"primary"},on:{click:function(t){return e.dataOperation()}}},[e._v("确定")])],1)],1)],1)},o=[],a=n("c6ed"),i={filters:{statusFilter:function(e){var t={1:"success",0:"gray","-1":"danger"};return t[e]},statusLabel:function(e){var t={1:"启动",0:"停止","-1":"断开"};return t[e]}},data:function(){return{list:null,listLoading:!0,listQuery:{name:"",ip:""},dialogFormVisible:!1,textMap:{create:"新建Server信息",update:"修改Server信息"},nodeModel:{id:void 0,name:null,ip:null,port:11110,port2:11112},rules:{name:[{required:!0,message:"Server 名称不能为空",trigger:"change"}],ip:[{required:!0,message:"Server IP不能为空",trigger:"change"}],port:[{required:!0,message:"Server Admin端口不能为空",trigger:"change"}]},dialogStatus:"create"}},created:function(){this.fetchData()},methods:{fetchData:function(){var e=this;this.listLoading=!0,Object(a["c"])(this.listQuery).then(function(t){e.list=t.data,e.listLoading=!1})},resetModel:function(){this.nodeModel={id:void 0,name:null,ip:null,port:null,port2:null}},handleCreate:function(){var e=this;this.resetModel(),this.dialogStatus="create",this.dialogFormVisible=!0,this.$nextTick(function(){e.$refs["dataForm"].clearValidate()})},dataOperation:function(){var e=this;this.$refs["dataForm"].validate(function(t){t&&("create"===e.dialogStatus&&Object(a["a"])(e.nodeModel).then(function(t){e.operationRes(t)}),"update"===e.dialogStatus&&Object(a["g"])(e.nodeModel).then(function(t){e.operationRes(t)}))})},operationRes:function(e){"success"===e.data?(this.fetchData(),this.dialogFormVisible=!1,this.$message({message:this.textMap[this.dialogStatus]+"成功",type:"success"})):this.$message({message:this.textMap[this.dialogStatus]+"失败",type:"error"})},handleUpdate:function(e){var t=this;this.resetModel(),this.nodeModel=Object.assign({},e),this.dialogStatus="update",this.dialogFormVisible=!0,this.$nextTick(function(){t.$refs["dataForm"].clearValidate()})},handleDelete:function(e){var t=this;this.$confirm("删除Server信息并不会导致节点服务停止","确定删除Server信息",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then(function(){Object(a["b"])(e.id).then(function(e){"success"===e.data?(t.fetchData(),t.$message({message:"删除Server信息成功",type:"success"})):t.$message({message:"删除Server信息失败",type:"error"})})})},handleStart:function(e){var t=this;0===e.status?this.$confirm("启动Server服务","确定启动Server服务",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then(function(){Object(a["e"])(e.id).then(function(e){e.data?(t.fetchData(),t.$message({message:"启动成功",type:"success"})):t.$message({message:"启动Server服务出现异常",type:"error"})})}):this.$message({message:"当前Server不是停止状态,无法启动",type:"error"})},handleStop:function(e){var t=this;1===e.status?this.$confirm("停止 Server 服务","确定停止Server服务",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then(function(){Object(a["f"])(e.id).then(function(e){e.data?(t.fetchData(),t.$message({message:"停止成功",type:"success"})):t.$message({message:"停止Server服务出现异常",type:"error"})})}):this.$message({message:"当前Server不是启动状态,无法停止",type:"error"})},handleLog:function(e){this.$router.push("nodeServer/log?id="+e.id)}}},l=i,s=n("2877"),d=Object(s["a"])(l,r,o,!1,null,null,null);t["default"]=d.exports},c6ed:function(e,t,n){"use strict";n.d(t,"c",function(){return o}),n.d(t,"a",function(){return a}),n.d(t,"g",function(){return i}),n.d(t,"b",function(){return l}),n.d(t,"e",function(){return s}),n.d(t,"f",function(){return d}),n.d(t,"d",function(){return u});var r=n("b775");function o(e){return Object(r["a"])({url:"/nodeServers",method:"get",params:e})}function a(e){return Object(r["a"])({url:"/nodeServer",method:"post",data:e})}function i(e){return Object(r["a"])({url:"/nodeServer",method:"put",data:e})}function l(e){return Object(r["a"])({url:"/nodeServer/"+e,method:"delete"})}function s(e){return Object(r["a"])({url:"/nodeServer/start/"+e,method:"put"})}function d(e){return Object(r["a"])({url:"/nodeServer/stop/"+e,method:"put"})}function u(e){return Object(r["a"])({url:"/nodeServer/log/"+e,method:"get"})}}}]);
\ No newline at end of file
diff --git a/canal-admin/canal-admin-server/src/main/resources/public/static/js/chunk-e1a839e4.e9eb1b06.js b/canal-admin/canal-admin-server/src/main/resources/public/static/js/chunk-e1a839e4.e9eb1b06.js
new file mode 100644
index 00000000..33ec1b50
--- /dev/null
+++ b/canal-admin/canal-admin-server/src/main/resources/public/static/js/chunk-e1a839e4.e9eb1b06.js
@@ -0,0 +1 @@
+(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-e1a839e4"],{"9f66":function(e,t,n){"use strict";n.r(t);var r=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{staticClass:"app-container"},[n("div",{staticClass:"filter-container"},[n("el-button",{staticClass:"filter-item",attrs:{type:"primary"},on:{click:function(t){return e.handleCreate()}}},[e._v("新建Server")]),e._v(" "),n("el-button",{staticClass:"filter-item",attrs:{type:"info"},on:{click:function(t){return e.fetchData()}}},[e._v("刷新列表")])],1),e._v(" "),n("el-table",{directives:[{name:"loading",rawName:"v-loading",value:e.listLoading,expression:"listLoading"}],attrs:{data:e.list,"element-loading-text":"Loading",border:"",fit:"","highlight-current-row":""}},[n("el-table-column",{attrs:{label:"Server 名称","min-width":"200",align:"center"},scopedSlots:e._u([{key:"default",fn:function(t){return[e._v("\n "+e._s(t.row.name)+"\n ")]}}])}),e._v(" "),n("el-table-column",{attrs:{label:"Server IP","min-width":"200",align:"center"},scopedSlots:e._u([{key:"default",fn:function(t){return[n("span",[e._v(e._s(t.row.ip))])]}}])}),e._v(" "),n("el-table-column",{attrs:{label:"admin 端口","min-width":"100",align:"center"},scopedSlots:e._u([{key:"default",fn:function(t){return[e._v("\n "+e._s(t.row.adminPort)+"\n ")]}}])}),e._v(" "),n("el-table-column",{attrs:{label:"tcp 端口","min-width":"100",align:"center"},scopedSlots:e._u([{key:"default",fn:function(t){return[e._v("\n "+e._s(t.row.tcpPort)+"\n ")]}}])}),e._v(" "),n("el-table-column",{attrs:{label:"metric 端口","min-width":"100",align:"center"},scopedSlots:e._u([{key:"default",fn:function(t){return[e._v("\n "+e._s(t.row.metricPort)+"\n ")]}}])}),e._v(" "),n("el-table-column",{attrs:{"class-name":"status-col",label:"状态","min-width":"150",align:"center"},scopedSlots:e._u([{key:"default",fn:function(t){return[n("el-tag",{attrs:{type:e._f("statusFilter")(t.row.status)}},[e._v(e._s(e._f("statusLabel")(t.row.status)))])]}}])}),e._v(" "),n("el-table-column",{attrs:{align:"center",prop:"created_at",label:"操作","min-width":"150"},scopedSlots:e._u([{key:"default",fn:function(t){return[n("el-dropdown",{attrs:{trigger:"click"}},[n("el-button",{attrs:{type:"primary",size:"mini"}},[e._v("\n 操作"),n("i",{staticClass:"el-icon-arrow-down el-icon--right"})]),e._v(" "),n("el-dropdown-menu",{attrs:{slot:"dropdown"},slot:"dropdown"},[n("el-dropdown-item",{nativeOn:{click:function(n){return e.handleUpdate(t.row)}}},[e._v("修改")]),e._v(" "),n("el-dropdown-item",{nativeOn:{click:function(n){return e.handleDelete(t.row)}}},[e._v("删除")]),e._v(" "),n("el-dropdown-item",{nativeOn:{click:function(n){return e.handleStart(t.row)}}},[e._v("启动")]),e._v(" "),n("el-dropdown-item",{nativeOn:{click:function(n){return e.handleStop(t.row)}}},[e._v("停止")]),e._v(" "),n("el-dropdown-item",{nativeOn:{click:function(n){return e.handleLog(t.row)}}},[e._v("日志")])],1)],1)]}}])})],1),e._v(" "),n("el-dialog",{attrs:{visible:e.dialogFormVisible,title:e.textMap[e.dialogStatus],width:"600px"},on:{"update:visible":function(t){e.dialogFormVisible=t}}},[n("el-form",{ref:"dataForm",staticStyle:{width:"400px","margin-left":"30px"},attrs:{rules:e.rules,model:e.nodeModel,"label-position":"left","label-width":"120px"}},[n("el-form-item",{attrs:{label:"Server 名称",prop:"name"}},[n("el-input",{model:{value:e.nodeModel.name,callback:function(t){e.$set(e.nodeModel,"name",t)},expression:"nodeModel.name"}})],1),e._v(" "),n("el-form-item",{attrs:{label:"Server IP",prop:"ip"}},[n("el-input",{model:{value:e.nodeModel.ip,callback:function(t){e.$set(e.nodeModel,"ip",t)},expression:"nodeModel.ip"}})],1),e._v(" "),n("el-form-item",{attrs:{label:"admin 端口",prop:"adminPort"}},[n("el-input",{attrs:{placeholder:"11110",type:"number"},model:{value:e.nodeModel.adminPort,callback:function(t){e.$set(e.nodeModel,"adminPort",t)},expression:"nodeModel.adminPort"}})],1),e._v(" "),n("el-form-item",{attrs:{label:"tcp 端口",prop:"tcpPort"}},[n("el-input",{attrs:{placeholder:"11111",type:"number"},model:{value:e.nodeModel.tcpPort,callback:function(t){e.$set(e.nodeModel,"tcpPort",t)},expression:"nodeModel.tcpPort"}})],1),e._v(" "),n("el-form-item",{attrs:{label:"metric 端口",prop:"metricPort"}},[n("el-input",{attrs:{placeholder:"11112",type:"number"},model:{value:e.nodeModel.metricPort,callback:function(t){e.$set(e.nodeModel,"metricPort",t)},expression:"nodeModel.metricPort"}})],1)],1),e._v(" "),n("div",{staticClass:"dialog-footer",attrs:{slot:"footer"},slot:"footer"},[n("el-button",{on:{click:function(t){e.dialogFormVisible=!1}}},[e._v("取消")]),e._v(" "),n("el-button",{attrs:{type:"primary"},on:{click:function(t){return e.dataOperation()}}},[e._v("确定")])],1)],1)],1)},o=[],a=n("c6ed"),i={filters:{statusFilter:function(e){var t={1:"success",0:"gray","-1":"danger"};return t[e]},statusLabel:function(e){var t={1:"启动",0:"停止","-1":"断开"};return t[e]}},data:function(){return{list:null,listLoading:!0,listQuery:{name:"",ip:""},dialogFormVisible:!1,textMap:{create:"新建Server信息",update:"修改Server信息"},nodeModel:{id:void 0,name:null,ip:null,adminPort:11110,tcpPort:11111,metricPort:11112},rules:{name:[{required:!0,message:"Server 名称不能为空",trigger:"change"}],ip:[{required:!0,message:"Server IP不能为空",trigger:"change"}],port:[{required:!0,message:"Server admin端口不能为空",trigger:"change"}]},dialogStatus:"create"}},created:function(){this.fetchData()},methods:{fetchData:function(){var e=this;this.listLoading=!0,Object(a["c"])(this.listQuery).then(function(t){e.list=t.data,e.listLoading=!1})},resetModel:function(){this.nodeModel={id:void 0,name:null,ip:null,adminPort:null,tcpPort:null,metricPort:null}},handleCreate:function(){var e=this;this.resetModel(),this.dialogStatus="create",this.dialogFormVisible=!0,this.$nextTick(function(){e.$refs["dataForm"].clearValidate()})},dataOperation:function(){var e=this;this.$refs["dataForm"].validate(function(t){t&&("create"===e.dialogStatus&&Object(a["a"])(e.nodeModel).then(function(t){e.operationRes(t)}),"update"===e.dialogStatus&&Object(a["g"])(e.nodeModel).then(function(t){e.operationRes(t)}))})},operationRes:function(e){"success"===e.data?(this.fetchData(),this.dialogFormVisible=!1,this.$message({message:this.textMap[this.dialogStatus]+"成功",type:"success"})):this.$message({message:this.textMap[this.dialogStatus]+"失败",type:"error"})},handleUpdate:function(e){var t=this;this.resetModel(),this.nodeModel=Object.assign({},e),this.dialogStatus="update",this.dialogFormVisible=!0,this.$nextTick(function(){t.$refs["dataForm"].clearValidate()})},handleDelete:function(e){var t=this;this.$confirm("删除Server信息并不会导致节点服务停止","确定删除Server信息",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then(function(){Object(a["b"])(e.id).then(function(e){"success"===e.data?(t.fetchData(),t.$message({message:"删除Server信息成功",type:"success"})):t.$message({message:"删除Server信息失败",type:"error"})})})},handleStart:function(e){var t=this;"0"===e.status?this.$confirm("启动Server服务","确定启动Server服务",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then(function(){Object(a["e"])(e.id).then(function(e){e.data?(t.fetchData(),t.$message({message:"启动成功",type:"success"})):t.$message({message:"启动Server服务出现异常",type:"error"})})}):this.$message({message:"当前Server不是停止状态,无法启动",type:"error"})},handleStop:function(e){var t=this;"1"===e.status?this.$confirm("停止 Server 服务","确定停止Server服务",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}).then(function(){Object(a["f"])(e.id).then(function(e){e.data?(t.fetchData(),t.$message({message:"停止成功",type:"success"})):t.$message({message:"停止Server服务出现异常",type:"error"})})}):this.$message({message:"当前Server不是启动状态,无法停止",type:"error"})},handleLog:function(e){this.$router.push("nodeServer/log?id="+e.id)}}},l=i,s=n("2877"),c=Object(s["a"])(l,r,o,!1,null,null,null);t["default"]=c.exports},c6ed:function(e,t,n){"use strict";n.d(t,"c",function(){return o}),n.d(t,"a",function(){return a}),n.d(t,"g",function(){return i}),n.d(t,"b",function(){return l}),n.d(t,"e",function(){return s}),n.d(t,"f",function(){return c}),n.d(t,"d",function(){return d});var r=n("b775");function o(e){return Object(r["a"])({url:"/nodeServers",method:"get",params:e})}function a(e){return Object(r["a"])({url:"/nodeServer",method:"post",data:e})}function i(e){return Object(r["a"])({url:"/nodeServer",method:"put",data:e})}function l(e){return Object(r["a"])({url:"/nodeServer/"+e,method:"delete"})}function s(e){return Object(r["a"])({url:"/nodeServer/start/"+e,method:"put"})}function c(e){return Object(r["a"])({url:"/nodeServer/stop/"+e,method:"put"})}function d(e){return Object(r["a"])({url:"/nodeServer/log/"+e,method:"get"})}}}]);
\ No newline at end of file
diff --git a/canal-admin/canal-admin-ui/src/views/canalServer/NodeServer.vue b/canal-admin/canal-admin-ui/src/views/canalServer/NodeServer.vue
index c639547f..cdc05369 100644
--- a/canal-admin/canal-admin-ui/src/views/canalServer/NodeServer.vue
+++ b/canal-admin/canal-admin-ui/src/views/canalServer/NodeServer.vue
@@ -25,14 +25,19 @@
{{ scope.row.ip }}
-
+
- {{ scope.row.port }}
+ {{ scope.row.adminPort }}
-
+
- {{ scope.row.port2 }}
+ {{ scope.row.tcpPort }}
+
+
+
+
+ {{ scope.row.metricPort }}
@@ -65,11 +70,14 @@
-
-
+
+
-
-
+
+
+
+
+