mirror of
https://gitee.com/dromara/Jpom.git
synced 2024-12-02 20:08:40 +08:00
feat(fix) 在线升级执行脚本、脚本模版等兼容 debian
This commit is contained in:
parent
37731c12c1
commit
b2cba06872
@ -14,6 +14,7 @@
|
||||
3. 【server】在线构建 ssh 发布选择授权目录切换不生效问题(感谢@天天)
|
||||
4. 【server】在线构建本地构建命令不能换行问题(感谢@华仔)
|
||||
5. 【server】日志弹窗新增行号
|
||||
6. 【server】在线升级执行脚本、脚本模版等兼容 `debian` (感谢@wxyShine [Gitee issues I4UQBD](https://gitee.com/dromara/Jpom/issues/I4UQBD) )
|
||||
|
||||
------
|
||||
|
||||
|
@ -29,7 +29,6 @@ import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.io.LineHandler;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.system.SystemUtil;
|
||||
import cn.jiangzeyin.common.DefaultSystemLog;
|
||||
import cn.jiangzeyin.common.spring.SpringUtil;
|
||||
import io.jpom.model.data.DslYmlDto;
|
||||
@ -75,9 +74,7 @@ public class DslScriptBuilder extends BaseRunScript implements Runnable {
|
||||
ProcessBuilder processBuilder = new ProcessBuilder();
|
||||
List<String> command = StrUtil.splitTrim(args, StrUtil.SPACE);
|
||||
command.add(0, script);
|
||||
if (SystemUtil.getOsInfo().isLinux() || SystemUtil.getOsInfo().isMac()) {
|
||||
command.add(0, CommandUtil.SUFFIX);
|
||||
}
|
||||
command.add(0, CommandUtil.EXECUTE_PREFIX);
|
||||
DefaultSystemLog.getLog().debug(CollUtil.join(command, StrUtil.SPACE));
|
||||
if (environment != null) {
|
||||
processBuilder.environment().putAll(environment);
|
||||
|
@ -30,7 +30,6 @@ import cn.hutool.core.io.LineHandler;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.system.SystemUtil;
|
||||
import cn.jiangzeyin.common.DefaultSystemLog;
|
||||
import cn.jiangzeyin.common.JsonMessage;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
@ -53,171 +52,169 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* @date 2019/4/25
|
||||
*/
|
||||
public class ScriptProcessBuilder extends BaseRunScript implements Runnable {
|
||||
/**
|
||||
* 执行中的缓存
|
||||
*/
|
||||
private static final ConcurrentHashMap<String, ScriptProcessBuilder> FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* 执行中的缓存
|
||||
*/
|
||||
private static final ConcurrentHashMap<String, ScriptProcessBuilder> FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private final ProcessBuilder processBuilder;
|
||||
private final Set<Session> sessions = new HashSet<>();
|
||||
private final String executeId;
|
||||
private final ProcessBuilder processBuilder;
|
||||
private final Set<Session> sessions = new HashSet<>();
|
||||
private final String executeId;
|
||||
|
||||
private ScriptProcessBuilder(NodeScriptModel nodeScriptModel, String executeId, String args) {
|
||||
super(nodeScriptModel.logFile(executeId));
|
||||
this.executeId = executeId;
|
||||
private ScriptProcessBuilder(NodeScriptModel nodeScriptModel, String executeId, String args) {
|
||||
super(nodeScriptModel.logFile(executeId));
|
||||
this.executeId = executeId;
|
||||
|
||||
File scriptFile = nodeScriptModel.getFile(true);
|
||||
//
|
||||
String script = FileUtil.getAbsolutePath(scriptFile);
|
||||
processBuilder = new ProcessBuilder();
|
||||
List<String> command = StrUtil.splitTrim(args, StrUtil.SPACE);
|
||||
command.add(0, script);
|
||||
if (SystemUtil.getOsInfo().isLinux() || SystemUtil.getOsInfo().isMac()) {
|
||||
command.add(0, CommandUtil.SUFFIX);
|
||||
}
|
||||
DefaultSystemLog.getLog().debug(CollUtil.join(command, StrUtil.SPACE));
|
||||
processBuilder.redirectErrorStream(true);
|
||||
processBuilder.command(command);
|
||||
processBuilder.directory(scriptFile.getParentFile());
|
||||
}
|
||||
File scriptFile = nodeScriptModel.getFile(true);
|
||||
//
|
||||
String script = FileUtil.getAbsolutePath(scriptFile);
|
||||
processBuilder = new ProcessBuilder();
|
||||
List<String> command = StrUtil.splitTrim(args, StrUtil.SPACE);
|
||||
command.add(0, script);
|
||||
command.add(0, CommandUtil.EXECUTE_PREFIX);
|
||||
DefaultSystemLog.getLog().debug(CollUtil.join(command, StrUtil.SPACE));
|
||||
processBuilder.redirectErrorStream(true);
|
||||
processBuilder.command(command);
|
||||
processBuilder.directory(scriptFile.getParentFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建执行 并监听
|
||||
*
|
||||
* @param nodeScriptModel 脚本模版
|
||||
* @param executeId 执行ID
|
||||
* @param args 参数
|
||||
*/
|
||||
public static ScriptProcessBuilder create(NodeScriptModel nodeScriptModel, String executeId, String args) {
|
||||
return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.computeIfAbsent(executeId, file1 -> {
|
||||
ScriptProcessBuilder scriptProcessBuilder1 = new ScriptProcessBuilder(nodeScriptModel, executeId, args);
|
||||
ThreadUtil.execute(scriptProcessBuilder1);
|
||||
return scriptProcessBuilder1;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 创建执行 并监听
|
||||
*
|
||||
* @param nodeScriptModel 脚本模版
|
||||
* @param executeId 执行ID
|
||||
* @param args 参数
|
||||
*/
|
||||
public static ScriptProcessBuilder create(NodeScriptModel nodeScriptModel, String executeId, String args) {
|
||||
return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.computeIfAbsent(executeId, file1 -> {
|
||||
ScriptProcessBuilder scriptProcessBuilder1 = new ScriptProcessBuilder(nodeScriptModel, executeId, args);
|
||||
ThreadUtil.execute(scriptProcessBuilder1);
|
||||
return scriptProcessBuilder1;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建执行 并监听
|
||||
*
|
||||
* @param nodeScriptModel 脚本模版
|
||||
* @param executeId 执行ID
|
||||
* @param args 参数
|
||||
* @param session 会话
|
||||
*/
|
||||
public static void addWatcher(NodeScriptModel nodeScriptModel, String executeId, String args, Session session) {
|
||||
ScriptProcessBuilder scriptProcessBuilder = create(nodeScriptModel, executeId, args);
|
||||
//
|
||||
if (scriptProcessBuilder.sessions.add(session)) {
|
||||
if (FileUtil.exist(scriptProcessBuilder.logFile)) {
|
||||
// 读取之前的信息并发送
|
||||
FileUtil.readLines(scriptProcessBuilder.logFile, CharsetUtil.CHARSET_UTF_8, (LineHandler) line -> {
|
||||
try {
|
||||
SocketSessionUtil.send(session, line);
|
||||
} catch (IOException e) {
|
||||
DefaultSystemLog.getLog().error("发送消息失败", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 创建执行 并监听
|
||||
*
|
||||
* @param nodeScriptModel 脚本模版
|
||||
* @param executeId 执行ID
|
||||
* @param args 参数
|
||||
* @param session 会话
|
||||
*/
|
||||
public static void addWatcher(NodeScriptModel nodeScriptModel, String executeId, String args, Session session) {
|
||||
ScriptProcessBuilder scriptProcessBuilder = create(nodeScriptModel, executeId, args);
|
||||
//
|
||||
if (scriptProcessBuilder.sessions.add(session)) {
|
||||
if (FileUtil.exist(scriptProcessBuilder.logFile)) {
|
||||
// 读取之前的信息并发送
|
||||
FileUtil.readLines(scriptProcessBuilder.logFile, CharsetUtil.CHARSET_UTF_8, (LineHandler) line -> {
|
||||
try {
|
||||
SocketSessionUtil.send(session, line);
|
||||
} catch (IOException e) {
|
||||
DefaultSystemLog.getLog().error("发送消息失败", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否还在执行中
|
||||
*
|
||||
* @param executeId 执行id
|
||||
* @return true 还在执行
|
||||
*/
|
||||
public static boolean isRun(String executeId) {
|
||||
return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.containsKey(executeId);
|
||||
}
|
||||
/**
|
||||
* 判断是否还在执行中
|
||||
*
|
||||
* @param executeId 执行id
|
||||
* @return true 还在执行
|
||||
*/
|
||||
public static boolean isRun(String executeId) {
|
||||
return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.containsKey(executeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭会话
|
||||
*
|
||||
* @param session 会话
|
||||
*/
|
||||
public static void stopWatcher(Session session) {
|
||||
Collection<ScriptProcessBuilder> scriptProcessBuilders = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.values();
|
||||
for (ScriptProcessBuilder scriptProcessBuilder : scriptProcessBuilders) {
|
||||
Set<Session> sessions = scriptProcessBuilder.sessions;
|
||||
sessions.removeIf(session1 -> session1.getId().equals(session.getId()));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 关闭会话
|
||||
*
|
||||
* @param session 会话
|
||||
*/
|
||||
public static void stopWatcher(Session session) {
|
||||
Collection<ScriptProcessBuilder> scriptProcessBuilders = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.values();
|
||||
for (ScriptProcessBuilder scriptProcessBuilder : scriptProcessBuilders) {
|
||||
Set<Session> sessions = scriptProcessBuilder.sessions;
|
||||
sessions.removeIf(session1 -> session1.getId().equals(session.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止脚本命令
|
||||
*
|
||||
* @param executeId 执行ID
|
||||
*/
|
||||
public static void stopRun(String executeId) {
|
||||
ScriptProcessBuilder scriptProcessBuilder = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.get(executeId);
|
||||
if (scriptProcessBuilder != null) {
|
||||
scriptProcessBuilder.end("停止运行");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 停止脚本命令
|
||||
*
|
||||
* @param executeId 执行ID
|
||||
*/
|
||||
public static void stopRun(String executeId) {
|
||||
ScriptProcessBuilder scriptProcessBuilder = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.get(executeId);
|
||||
if (scriptProcessBuilder != null) {
|
||||
scriptProcessBuilder.end("停止运行");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
//初始化ProcessBuilder对象
|
||||
try {
|
||||
this.handle("start execute:" + DateUtil.now());
|
||||
process = processBuilder.start();
|
||||
{
|
||||
inputStream = process.getInputStream();
|
||||
IoUtil.readLines(inputStream, ExtConfigBean.getInstance().getConsoleLogCharset(), (LineHandler) ScriptProcessBuilder.this::handle);
|
||||
}
|
||||
int waitFor = process.waitFor();
|
||||
JsonMessage<String> jsonMessage = new JsonMessage<>(200, "执行完毕:" + waitFor);
|
||||
JSONObject jsonObject = jsonMessage.toJson();
|
||||
jsonObject.put("op", ConsoleCommandOp.stop.name());
|
||||
this.end(jsonObject.toString());
|
||||
this.handle("execute done:" + waitFor + " time:" + DateUtil.now());
|
||||
} catch (Exception e) {
|
||||
DefaultSystemLog.getLog().error("执行异常", e);
|
||||
this.end("执行异常:" + e.getMessage());
|
||||
} finally {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
//初始化ProcessBuilder对象
|
||||
try {
|
||||
this.handle("start execute:" + DateUtil.now());
|
||||
process = processBuilder.start();
|
||||
{
|
||||
inputStream = process.getInputStream();
|
||||
IoUtil.readLines(inputStream, ExtConfigBean.getInstance().getConsoleLogCharset(), (LineHandler) ScriptProcessBuilder.this::handle);
|
||||
}
|
||||
int waitFor = process.waitFor();
|
||||
JsonMessage<String> jsonMessage = new JsonMessage<>(200, "执行完毕:" + waitFor);
|
||||
JSONObject jsonObject = jsonMessage.toJson();
|
||||
jsonObject.put("op", ConsoleCommandOp.stop.name());
|
||||
this.end(jsonObject.toString());
|
||||
this.handle("execute done:" + waitFor + " time:" + DateUtil.now());
|
||||
} catch (Exception e) {
|
||||
DefaultSystemLog.getLog().error("执行异常", e);
|
||||
this.end("执行异常:" + e.getMessage());
|
||||
} finally {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束执行
|
||||
*
|
||||
* @param msg 响应的消息
|
||||
*/
|
||||
@Override
|
||||
protected void end(String msg) {
|
||||
Iterator<Session> iterator = sessions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Session session = iterator.next();
|
||||
try {
|
||||
SocketSessionUtil.send(session, msg);
|
||||
} catch (IOException e) {
|
||||
DefaultSystemLog.getLog().error("发送消息失败", e);
|
||||
}
|
||||
iterator.remove();
|
||||
}
|
||||
FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.remove(this.executeId);
|
||||
}
|
||||
/**
|
||||
* 结束执行
|
||||
*
|
||||
* @param msg 响应的消息
|
||||
*/
|
||||
@Override
|
||||
protected void end(String msg) {
|
||||
Iterator<Session> iterator = sessions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Session session = iterator.next();
|
||||
try {
|
||||
SocketSessionUtil.send(session, msg);
|
||||
} catch (IOException e) {
|
||||
DefaultSystemLog.getLog().error("发送消息失败", e);
|
||||
}
|
||||
iterator.remove();
|
||||
}
|
||||
FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.remove(this.executeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应
|
||||
*
|
||||
* @param line 信息
|
||||
*/
|
||||
@Override
|
||||
protected void handle(String line) {
|
||||
super.handle(line);
|
||||
//
|
||||
Iterator<Session> iterator = sessions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Session session = iterator.next();
|
||||
try {
|
||||
SocketSessionUtil.send(session, line);
|
||||
} catch (IOException e) {
|
||||
DefaultSystemLog.getLog().error("发送消息失败", e);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 响应
|
||||
*
|
||||
* @param line 信息
|
||||
*/
|
||||
@Override
|
||||
protected void handle(String line) {
|
||||
super.handle(line);
|
||||
//
|
||||
Iterator<Session> iterator = sessions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Session session = iterator.next();
|
||||
try {
|
||||
SocketSessionUtil.send(session, line);
|
||||
} catch (IOException e) {
|
||||
DefaultSystemLog.getLog().error("发送消息失败", e);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -196,9 +196,7 @@ public class JpomApplication extends ApplicationBuilder {
|
||||
// Waiting for method caller,For example, the interface response
|
||||
ThreadUtil.sleep(2, TimeUnit.SECONDS);
|
||||
try {
|
||||
String command = SystemUtil.getOsInfo().isWindows() ? StrUtil.EMPTY : CommandUtil.SUFFIX;
|
||||
|
||||
command += " " + FileUtil.getAbsolutePath(scriptFile) + " restart upgrade";
|
||||
String command = CommandUtil.EXECUTE_PREFIX + StrUtil.SPACE + FileUtil.getAbsolutePath(scriptFile) + " restart upgrade";
|
||||
if (SystemUtil.getOsInfo().isWindows()) {
|
||||
CommandUtil.execSystemCommand(command, scriptFile.getParentFile());
|
||||
} else {
|
||||
|
@ -23,7 +23,10 @@
|
||||
package io.jpom.util;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.*;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RuntimeUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.system.SystemUtil;
|
||||
import cn.jiangzeyin.common.DefaultSystemLog;
|
||||
import io.jpom.system.ExtConfigBean;
|
||||
@ -42,189 +45,193 @@ import java.util.List;
|
||||
* @date 2019/4/15
|
||||
*/
|
||||
public class CommandUtil {
|
||||
/**
|
||||
* 系统命令
|
||||
*/
|
||||
private static final List<String> COMMAND = new ArrayList<>();
|
||||
/**
|
||||
* 文件后缀
|
||||
*/
|
||||
public static final String SUFFIX;
|
||||
/**
|
||||
* 系统命令
|
||||
*/
|
||||
private static final List<String> COMMAND = new ArrayList<>();
|
||||
/**
|
||||
* 文件后缀
|
||||
*/
|
||||
public static final String SUFFIX;
|
||||
/**
|
||||
* 执行前缀
|
||||
*/
|
||||
public static final String EXECUTE_PREFIX;
|
||||
|
||||
static {
|
||||
if (SystemUtil.getOsInfo().isLinux()) {
|
||||
//执行linux系统命令
|
||||
COMMAND.add("/bin/bash");
|
||||
COMMAND.add("-c");
|
||||
} else if (SystemUtil.getOsInfo().isMac()) {
|
||||
COMMAND.add("/bin/bash");
|
||||
COMMAND.add("-c");
|
||||
} else {
|
||||
COMMAND.add("cmd");
|
||||
COMMAND.add("/c");
|
||||
}
|
||||
/**
|
||||
* 文件后缀
|
||||
*/
|
||||
if (SystemUtil.getOsInfo().isWindows()) {
|
||||
SUFFIX = "bat";
|
||||
} else {
|
||||
SUFFIX = "sh";
|
||||
}
|
||||
}
|
||||
static {
|
||||
if (SystemUtil.getOsInfo().isLinux()) {
|
||||
//执行linux系统命令
|
||||
COMMAND.add("/bin/bash");
|
||||
COMMAND.add("-c");
|
||||
} else if (SystemUtil.getOsInfo().isMac()) {
|
||||
COMMAND.add("/bin/bash");
|
||||
COMMAND.add("-c");
|
||||
} else {
|
||||
COMMAND.add("cmd");
|
||||
COMMAND.add("/c");
|
||||
}
|
||||
//
|
||||
if (SystemUtil.getOsInfo().isWindows()) {
|
||||
SUFFIX = "bat";
|
||||
EXECUTE_PREFIX = StrUtil.EMPTY;
|
||||
} else {
|
||||
SUFFIX = "sh";
|
||||
EXECUTE_PREFIX = "bash";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取执行命令的 前缀
|
||||
*
|
||||
* @return list
|
||||
*/
|
||||
public static List<String> getCommand() {
|
||||
return ObjectUtil.clone(COMMAND);
|
||||
}
|
||||
/**
|
||||
* 获取执行命令的 前缀
|
||||
*
|
||||
* @return list
|
||||
*/
|
||||
public static List<String> getCommand() {
|
||||
return ObjectUtil.clone(COMMAND);
|
||||
}
|
||||
|
||||
public static String execSystemCommand(String command) {
|
||||
return execSystemCommand(command, null);
|
||||
}
|
||||
public static String execSystemCommand(String command) {
|
||||
return execSystemCommand(command, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定文件夹下执行命令
|
||||
*
|
||||
* @param command 命令
|
||||
* @param file 文件夹
|
||||
* @return msg
|
||||
*/
|
||||
public static String execSystemCommand(String command, File file) {
|
||||
String newCommand = StrUtil.replace(command, StrUtil.CRLF, StrUtil.SPACE);
|
||||
newCommand = StrUtil.replace(newCommand, StrUtil.LF, StrUtil.SPACE);
|
||||
String result = "error";
|
||||
try {
|
||||
List<String> commands = getCommand();
|
||||
commands.add(newCommand);
|
||||
String[] cmd = commands.toArray(new String[]{});
|
||||
result = exec(cmd, file);
|
||||
} catch (Exception e) {
|
||||
DefaultSystemLog.getLog().error("执行命令异常", e);
|
||||
result += e.getMessage();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* 在指定文件夹下执行命令
|
||||
*
|
||||
* @param command 命令
|
||||
* @param file 文件夹
|
||||
* @return msg
|
||||
*/
|
||||
public static String execSystemCommand(String command, File file) {
|
||||
String newCommand = StrUtil.replace(command, StrUtil.CRLF, StrUtil.SPACE);
|
||||
newCommand = StrUtil.replace(newCommand, StrUtil.LF, StrUtil.SPACE);
|
||||
String result = "error";
|
||||
try {
|
||||
List<String> commands = getCommand();
|
||||
commands.add(newCommand);
|
||||
String[] cmd = commands.toArray(new String[]{});
|
||||
result = exec(cmd, file);
|
||||
} catch (Exception e) {
|
||||
DefaultSystemLog.getLog().error("执行命令异常", e);
|
||||
result += e.getMessage();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行命令
|
||||
*
|
||||
* @param cmd 命令行
|
||||
* @return 结果
|
||||
* @throws IOException IO
|
||||
*/
|
||||
private static String exec(String[] cmd, File file) throws IOException {
|
||||
Process process = new ProcessBuilder(cmd).directory(file).redirectErrorStream(true).start();
|
||||
Charset charset;
|
||||
boolean log;
|
||||
try {
|
||||
charset = ExtConfigBean.getInstance().getConsoleLogCharset();
|
||||
log = true;
|
||||
} catch (Exception e) {
|
||||
// 直接执行,使用默认编码格式
|
||||
charset = CharsetUtil.systemCharset();
|
||||
// 不记录日志
|
||||
log = false;
|
||||
}
|
||||
charset = ObjectUtil.defaultIfNull(charset, CharsetUtil.defaultCharset());
|
||||
String result = RuntimeUtil.getResult(process, charset);
|
||||
if (log) {
|
||||
DefaultSystemLog.getLog().debug("exec {} {} {}", charset.name(), Arrays.toString(cmd), result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* 执行命令
|
||||
*
|
||||
* @param cmd 命令行
|
||||
* @return 结果
|
||||
* @throws IOException IO
|
||||
*/
|
||||
private static String exec(String[] cmd, File file) throws IOException {
|
||||
Process process = new ProcessBuilder(cmd).directory(file).redirectErrorStream(true).start();
|
||||
Charset charset;
|
||||
boolean log;
|
||||
try {
|
||||
charset = ExtConfigBean.getInstance().getConsoleLogCharset();
|
||||
log = true;
|
||||
} catch (Exception e) {
|
||||
// 直接执行,使用默认编码格式
|
||||
charset = CharsetUtil.systemCharset();
|
||||
// 不记录日志
|
||||
log = false;
|
||||
}
|
||||
charset = ObjectUtil.defaultIfNull(charset, CharsetUtil.defaultCharset());
|
||||
String result = RuntimeUtil.getResult(process, charset);
|
||||
if (log) {
|
||||
DefaultSystemLog.getLog().debug("exec {} {} {}", charset.name(), Arrays.toString(cmd), result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步执行命令
|
||||
*
|
||||
* @param file 文件夹
|
||||
* @param command 命令
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public static void asyncExeLocalCommand(File file, String command) throws Exception {
|
||||
String newCommand = StrUtil.replace(command, StrUtil.CRLF, StrUtil.SPACE);
|
||||
newCommand = StrUtil.replace(newCommand, StrUtil.LF, StrUtil.SPACE);
|
||||
//
|
||||
DefaultSystemLog.getLog().debug(newCommand);
|
||||
List<String> commands = getCommand();
|
||||
commands.add(newCommand);
|
||||
ProcessBuilder pb = new ProcessBuilder(commands);
|
||||
if (file != null) {
|
||||
pb.directory(file);
|
||||
}
|
||||
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
|
||||
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
|
||||
pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
|
||||
pb.start();
|
||||
}
|
||||
/**
|
||||
* 异步执行命令
|
||||
*
|
||||
* @param file 文件夹
|
||||
* @param command 命令
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public static void asyncExeLocalCommand(File file, String command) throws Exception {
|
||||
String newCommand = StrUtil.replace(command, StrUtil.CRLF, StrUtil.SPACE);
|
||||
newCommand = StrUtil.replace(newCommand, StrUtil.LF, StrUtil.SPACE);
|
||||
//
|
||||
DefaultSystemLog.getLog().debug(newCommand);
|
||||
List<String> commands = getCommand();
|
||||
commands.add(newCommand);
|
||||
ProcessBuilder pb = new ProcessBuilder(commands);
|
||||
if (file != null) {
|
||||
pb.directory(file);
|
||||
}
|
||||
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
|
||||
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
|
||||
pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
|
||||
pb.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否包含删除命令
|
||||
*
|
||||
* @param script 命令行
|
||||
* @return true 包含
|
||||
*/
|
||||
public static boolean checkContainsDel(String script) {
|
||||
// 判断删除
|
||||
String[] commands = StrUtil.splitToArray(script, StrUtil.LF);
|
||||
for (String commandItem : commands) {
|
||||
if (checkContainsDelItem(commandItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* 判断是否包含删除命令
|
||||
*
|
||||
* @param script 命令行
|
||||
* @return true 包含
|
||||
*/
|
||||
public static boolean checkContainsDel(String script) {
|
||||
// 判断删除
|
||||
String[] commands = StrUtil.splitToArray(script, StrUtil.LF);
|
||||
for (String commandItem : commands) {
|
||||
if (checkContainsDelItem(commandItem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行系统命令 快速删除.
|
||||
* 执行删除后再检查文件是否存在
|
||||
*
|
||||
* @param file 文件或者文件夹
|
||||
* @return true 文件还存在
|
||||
*/
|
||||
public static boolean systemFastDel(File file) {
|
||||
String path = FileUtil.getAbsolutePath(file);
|
||||
String command;
|
||||
if (SystemUtil.getOsInfo().isWindows()) {
|
||||
// Windows
|
||||
command = StrUtil.format("rd /s/q \"{}\"", path);
|
||||
} else {
|
||||
// Linux MacOS
|
||||
command = StrUtil.format("rm -rf '{}'", path);
|
||||
}
|
||||
CommandUtil.execSystemCommand(command);
|
||||
// 再次尝试
|
||||
boolean del = FileUtil.del(file);
|
||||
if (!del) {
|
||||
FileUtil.del(file.toPath());
|
||||
}
|
||||
return FileUtil.exist(file);
|
||||
}
|
||||
/**
|
||||
* 执行系统命令 快速删除.
|
||||
* 执行删除后再检查文件是否存在
|
||||
*
|
||||
* @param file 文件或者文件夹
|
||||
* @return true 文件还存在
|
||||
*/
|
||||
public static boolean systemFastDel(File file) {
|
||||
String path = FileUtil.getAbsolutePath(file);
|
||||
String command;
|
||||
if (SystemUtil.getOsInfo().isWindows()) {
|
||||
// Windows
|
||||
command = StrUtil.format("rd /s/q \"{}\"", path);
|
||||
} else {
|
||||
// Linux MacOS
|
||||
command = StrUtil.format("rm -rf '{}'", path);
|
||||
}
|
||||
CommandUtil.execSystemCommand(command);
|
||||
// 再次尝试
|
||||
boolean del = FileUtil.del(file);
|
||||
if (!del) {
|
||||
FileUtil.del(file.toPath());
|
||||
}
|
||||
return FileUtil.exist(file);
|
||||
}
|
||||
|
||||
private static boolean checkContainsDelItem(String script) {
|
||||
String[] split = StrUtil.splitToArray(script, StrUtil.SPACE);
|
||||
if (SystemUtil.getOsInfo().isWindows()) {
|
||||
for (String s : split) {
|
||||
if (StrUtil.startWithAny(s, "rd", "del")) {
|
||||
return true;
|
||||
}
|
||||
if (StrUtil.containsAnyIgnoreCase(s, " rd", " del")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (String s : split) {
|
||||
if (StrUtil.startWithAny(s, "rm", "\\rm")) {
|
||||
return true;
|
||||
}
|
||||
if (StrUtil.containsAnyIgnoreCase(s, " rm", " \\rm", "&rm", "&\\rm")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static boolean checkContainsDelItem(String script) {
|
||||
String[] split = StrUtil.splitToArray(script, StrUtil.SPACE);
|
||||
if (SystemUtil.getOsInfo().isWindows()) {
|
||||
for (String s : split) {
|
||||
if (StrUtil.startWithAny(s, "rd", "del")) {
|
||||
return true;
|
||||
}
|
||||
if (StrUtil.containsAnyIgnoreCase(s, " rd", " del")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (String s : split) {
|
||||
if (StrUtil.startWithAny(s, "rm", "\\rm")) {
|
||||
return true;
|
||||
}
|
||||
if (StrUtil.containsAnyIgnoreCase(s, " rm", " \\rm", "&rm", "&\\rm")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.extra.ssh.JschUtil;
|
||||
import cn.hutool.extra.ssh.Sftp;
|
||||
import cn.hutool.http.HttpStatus;
|
||||
import cn.hutool.system.SystemUtil;
|
||||
import cn.jiangzeyin.common.JsonMessage;
|
||||
import cn.jiangzeyin.common.spring.SpringUtil;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
@ -86,22 +85,22 @@ import java.util.stream.Collectors;
|
||||
@Builder
|
||||
public class ReleaseManage implements Runnable {
|
||||
|
||||
private final UserModel userModel;
|
||||
private final int buildId;
|
||||
private final BuildExtraModule buildExtraModule;
|
||||
private final String logId;
|
||||
private final BuildExecuteService buildExecuteService;
|
||||
private final UserModel userModel;
|
||||
private final int buildId;
|
||||
private final BuildExtraModule buildExtraModule;
|
||||
private final String logId;
|
||||
private final BuildExecuteService buildExecuteService;
|
||||
|
||||
private LogRecorder logRecorder;
|
||||
private File resultFile;
|
||||
private LogRecorder logRecorder;
|
||||
private File resultFile;
|
||||
|
||||
private void init() {
|
||||
if (this.logRecorder == null) {
|
||||
File logFile = BuildUtil.getLogFile(buildExtraModule.getId(), buildId);
|
||||
this.logRecorder = LogRecorder.builder().file(logFile).build();
|
||||
}
|
||||
this.resultFile = BuildUtil.getHistoryPackageFile(buildExtraModule.getId(), this.buildId, buildExtraModule.getResultDirFile());
|
||||
}
|
||||
private void init() {
|
||||
if (this.logRecorder == null) {
|
||||
File logFile = BuildUtil.getLogFile(buildExtraModule.getId(), buildId);
|
||||
this.logRecorder = LogRecorder.builder().file(logFile).build();
|
||||
}
|
||||
this.resultFile = BuildUtil.getHistoryPackageFile(buildExtraModule.getId(), this.buildId, buildExtraModule.getResultDirFile());
|
||||
}
|
||||
|
||||
// /**
|
||||
// * new ReleaseManage constructor
|
||||
@ -138,417 +137,417 @@ public class ReleaseManage implements Runnable {
|
||||
// }
|
||||
|
||||
|
||||
public void updateStatus(BuildStatus status) {
|
||||
buildExecuteService.updateStatus(this.buildExtraModule.getId(), this.logId, status);
|
||||
}
|
||||
public void updateStatus(BuildStatus status) {
|
||||
buildExecuteService.updateStatus(this.buildExtraModule.getId(), this.logId, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 不修改为发布中状态
|
||||
*/
|
||||
public void start() {
|
||||
init();
|
||||
updateStatus(BuildStatus.PubIng);
|
||||
logRecorder.info("start release:" + FileUtil.readableFileSize(FileUtil.size(this.resultFile)));
|
||||
if (!this.resultFile.exists()) {
|
||||
logRecorder.info("不存在构建产物");
|
||||
updateStatus(BuildStatus.PubError);
|
||||
return;
|
||||
}
|
||||
long time = SystemClock.now();
|
||||
int releaseMethod = this.buildExtraModule.getReleaseMethod();
|
||||
logRecorder.info("release method:" + BaseEnum.getDescByCode(BuildReleaseMethod.class, releaseMethod));
|
||||
try {
|
||||
if (releaseMethod == BuildReleaseMethod.Outgiving.getCode()) {
|
||||
//
|
||||
this.doOutGiving();
|
||||
} else if (releaseMethod == BuildReleaseMethod.Project.getCode()) {
|
||||
this.doProject();
|
||||
} else if (releaseMethod == BuildReleaseMethod.Ssh.getCode()) {
|
||||
this.doSsh();
|
||||
} else if (releaseMethod == BuildReleaseMethod.LocalCommand.getCode()) {
|
||||
this.localCommand();
|
||||
} else if (releaseMethod == BuildReleaseMethod.DockerImage.getCode()) {
|
||||
this.doDockerImage();
|
||||
} else {
|
||||
logRecorder.info(" 没有实现的发布分发:" + releaseMethod);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.pubLog("发布异常", e);
|
||||
return;
|
||||
}
|
||||
logRecorder.info("release complete : " + DateUtil.formatBetween(SystemClock.now() - time, BetweenFormatter.Level.MILLISECOND));
|
||||
updateStatus(BuildStatus.PubSuccess);
|
||||
}
|
||||
/**
|
||||
* 不修改为发布中状态
|
||||
*/
|
||||
public void start() {
|
||||
init();
|
||||
updateStatus(BuildStatus.PubIng);
|
||||
logRecorder.info("start release:" + FileUtil.readableFileSize(FileUtil.size(this.resultFile)));
|
||||
if (!this.resultFile.exists()) {
|
||||
logRecorder.info("不存在构建产物");
|
||||
updateStatus(BuildStatus.PubError);
|
||||
return;
|
||||
}
|
||||
long time = SystemClock.now();
|
||||
int releaseMethod = this.buildExtraModule.getReleaseMethod();
|
||||
logRecorder.info("release method:" + BaseEnum.getDescByCode(BuildReleaseMethod.class, releaseMethod));
|
||||
try {
|
||||
if (releaseMethod == BuildReleaseMethod.Outgiving.getCode()) {
|
||||
//
|
||||
this.doOutGiving();
|
||||
} else if (releaseMethod == BuildReleaseMethod.Project.getCode()) {
|
||||
this.doProject();
|
||||
} else if (releaseMethod == BuildReleaseMethod.Ssh.getCode()) {
|
||||
this.doSsh();
|
||||
} else if (releaseMethod == BuildReleaseMethod.LocalCommand.getCode()) {
|
||||
this.localCommand();
|
||||
} else if (releaseMethod == BuildReleaseMethod.DockerImage.getCode()) {
|
||||
this.doDockerImage();
|
||||
} else {
|
||||
logRecorder.info(" 没有实现的发布分发:" + releaseMethod);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.pubLog("发布异常", e);
|
||||
return;
|
||||
}
|
||||
logRecorder.info("release complete : " + DateUtil.formatBetween(SystemClock.now() - time, BetweenFormatter.Level.MILLISECOND));
|
||||
updateStatus(BuildStatus.PubSuccess);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 格式化命令模版
|
||||
*
|
||||
* @param commands 命令
|
||||
*/
|
||||
private void formatCommand(String[] commands) {
|
||||
for (int i = 0; i < commands.length; i++) {
|
||||
commands[i] = this.formatCommandItem(commands[i]);
|
||||
}
|
||||
//
|
||||
WorkspaceEnvVarService workspaceEnvVarService = SpringUtil.getBean(WorkspaceEnvVarService.class);
|
||||
workspaceEnvVarService.formatCommand(this.buildExtraModule.getWorkspaceId(), commands);
|
||||
/**
|
||||
* 格式化命令模版
|
||||
*
|
||||
* @param commands 命令
|
||||
*/
|
||||
private void formatCommand(String[] commands) {
|
||||
for (int i = 0; i < commands.length; i++) {
|
||||
commands[i] = this.formatCommandItem(commands[i]);
|
||||
}
|
||||
//
|
||||
WorkspaceEnvVarService workspaceEnvVarService = SpringUtil.getBean(WorkspaceEnvVarService.class);
|
||||
workspaceEnvVarService.formatCommand(this.buildExtraModule.getWorkspaceId(), commands);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化命令模版
|
||||
*
|
||||
* @param command 命令
|
||||
* @return 格式化后
|
||||
*/
|
||||
private String formatCommandItem(String command) {
|
||||
String replace = StrUtil.replace(command, "#{BUILD_ID}", this.buildExtraModule.getId());
|
||||
replace = StrUtil.replace(replace, "#{BUILD_NAME}", this.buildExtraModule.getName());
|
||||
replace = StrUtil.replace(replace, "#{BUILD_RESULT_FILE}", FileUtil.getAbsolutePath(this.resultFile));
|
||||
replace = StrUtil.replace(replace, "#{BUILD_NUMBER_ID}", this.buildId + StrUtil.EMPTY);
|
||||
return replace;
|
||||
}
|
||||
/**
|
||||
* 格式化命令模版
|
||||
*
|
||||
* @param command 命令
|
||||
* @return 格式化后
|
||||
*/
|
||||
private String formatCommandItem(String command) {
|
||||
String replace = StrUtil.replace(command, "#{BUILD_ID}", this.buildExtraModule.getId());
|
||||
replace = StrUtil.replace(replace, "#{BUILD_NAME}", this.buildExtraModule.getName());
|
||||
replace = StrUtil.replace(replace, "#{BUILD_RESULT_FILE}", FileUtil.getAbsolutePath(this.resultFile));
|
||||
replace = StrUtil.replace(replace, "#{BUILD_NUMBER_ID}", this.buildId + StrUtil.EMPTY);
|
||||
return replace;
|
||||
}
|
||||
|
||||
private String parseDockerTag(File envFile, String tag) {
|
||||
if (!FileUtil.isFile(envFile)) {
|
||||
return tag;
|
||||
}
|
||||
final String[] newTag = {tag};
|
||||
FileUtil.readLines(envFile, StandardCharsets.UTF_8, (LineHandler) line -> {
|
||||
line = StrUtil.trim(line);
|
||||
if (StrUtil.startWith(line, "#")) {
|
||||
return;
|
||||
}
|
||||
List<String> list = StrUtil.splitTrim(line, "=");
|
||||
if (CollUtil.size(list) != 2) {
|
||||
return;
|
||||
}
|
||||
newTag[0] = StrUtil.replace(newTag[0], "${" + list.get(0) + "}", list.get(1));
|
||||
});
|
||||
return newTag[0];
|
||||
}
|
||||
private String parseDockerTag(File envFile, String tag) {
|
||||
if (!FileUtil.isFile(envFile)) {
|
||||
return tag;
|
||||
}
|
||||
final String[] newTag = {tag};
|
||||
FileUtil.readLines(envFile, StandardCharsets.UTF_8, (LineHandler) line -> {
|
||||
line = StrUtil.trim(line);
|
||||
if (StrUtil.startWith(line, "#")) {
|
||||
return;
|
||||
}
|
||||
List<String> list = StrUtil.splitTrim(line, "=");
|
||||
if (CollUtil.size(list) != 2) {
|
||||
return;
|
||||
}
|
||||
newTag[0] = StrUtil.replace(newTag[0], "${" + list.get(0) + "}", list.get(1));
|
||||
});
|
||||
return newTag[0];
|
||||
}
|
||||
|
||||
private void doDockerImage() {
|
||||
// 生成临时目录
|
||||
File tempPath = FileUtil.file(ConfigBean.getInstance().getTempPath(), "build_temp", "docker_image", this.buildExtraModule.getId() + StrUtil.DASHED + this.buildId);
|
||||
try {
|
||||
File sourceFile = BuildUtil.getSourceById(this.buildExtraModule.getId());
|
||||
FileUtil.copyContent(sourceFile, tempPath, true);
|
||||
File historyPackageFile = BuildUtil.getHistoryPackageFile(buildExtraModule.getId(), this.buildId, StrUtil.SLASH);
|
||||
FileUtil.copyContent(historyPackageFile, tempPath, true);
|
||||
// env file
|
||||
File envFile = FileUtil.file(tempPath, ".env");
|
||||
String dockerTag = this.buildExtraModule.getDockerTag();
|
||||
dockerTag = this.parseDockerTag(envFile, dockerTag);
|
||||
// docker file
|
||||
String moduleDockerfile = this.buildExtraModule.getDockerfile();
|
||||
List<String> list = StrUtil.splitTrim(moduleDockerfile, StrUtil.COLON);
|
||||
String dockerFile = CollUtil.getLast(list);
|
||||
File dockerfile = FileUtil.file(tempPath, dockerFile);
|
||||
if (!FileUtil.isFile(dockerfile)) {
|
||||
logRecorder.info("仓库目录下没有找到 Dockerfile 文件:", dockerFile);
|
||||
return;
|
||||
}
|
||||
File baseDir = FileUtil.file(tempPath, list.size() == 1 ? StrUtil.SLASH : CollUtil.get(list, 0));
|
||||
//
|
||||
String fromTag = this.buildExtraModule.getFromTag();
|
||||
// 根据 tag 查询
|
||||
List<DockerInfoModel> dockerInfoModels = buildExecuteService
|
||||
.dockerInfoService
|
||||
.queryByTag(this.buildExtraModule.getWorkspaceId(), 1, fromTag);
|
||||
DockerInfoModel dockerInfoModel = CollUtil.getFirst(dockerInfoModels);
|
||||
if (dockerInfoModel == null) {
|
||||
logRecorder.info("没有可用的 docker server");
|
||||
return;
|
||||
}
|
||||
for (DockerInfoModel infoModel : dockerInfoModels) {
|
||||
this.doDockerImage(infoModel, dockerfile, baseDir, dockerTag);
|
||||
}
|
||||
// 发布 docker 服务
|
||||
this.updateSwarmService(dockerTag, this.buildExtraModule.getDockerSwarmId(), this.buildExtraModule.getDockerSwarmServiceName());
|
||||
} finally {
|
||||
CommandUtil.systemFastDel(tempPath);
|
||||
}
|
||||
}
|
||||
private void doDockerImage() {
|
||||
// 生成临时目录
|
||||
File tempPath = FileUtil.file(ConfigBean.getInstance().getTempPath(), "build_temp", "docker_image", this.buildExtraModule.getId() + StrUtil.DASHED + this.buildId);
|
||||
try {
|
||||
File sourceFile = BuildUtil.getSourceById(this.buildExtraModule.getId());
|
||||
FileUtil.copyContent(sourceFile, tempPath, true);
|
||||
File historyPackageFile = BuildUtil.getHistoryPackageFile(buildExtraModule.getId(), this.buildId, StrUtil.SLASH);
|
||||
FileUtil.copyContent(historyPackageFile, tempPath, true);
|
||||
// env file
|
||||
File envFile = FileUtil.file(tempPath, ".env");
|
||||
String dockerTag = this.buildExtraModule.getDockerTag();
|
||||
dockerTag = this.parseDockerTag(envFile, dockerTag);
|
||||
// docker file
|
||||
String moduleDockerfile = this.buildExtraModule.getDockerfile();
|
||||
List<String> list = StrUtil.splitTrim(moduleDockerfile, StrUtil.COLON);
|
||||
String dockerFile = CollUtil.getLast(list);
|
||||
File dockerfile = FileUtil.file(tempPath, dockerFile);
|
||||
if (!FileUtil.isFile(dockerfile)) {
|
||||
logRecorder.info("仓库目录下没有找到 Dockerfile 文件:", dockerFile);
|
||||
return;
|
||||
}
|
||||
File baseDir = FileUtil.file(tempPath, list.size() == 1 ? StrUtil.SLASH : CollUtil.get(list, 0));
|
||||
//
|
||||
String fromTag = this.buildExtraModule.getFromTag();
|
||||
// 根据 tag 查询
|
||||
List<DockerInfoModel> dockerInfoModels = buildExecuteService
|
||||
.dockerInfoService
|
||||
.queryByTag(this.buildExtraModule.getWorkspaceId(), 1, fromTag);
|
||||
DockerInfoModel dockerInfoModel = CollUtil.getFirst(dockerInfoModels);
|
||||
if (dockerInfoModel == null) {
|
||||
logRecorder.info("没有可用的 docker server");
|
||||
return;
|
||||
}
|
||||
for (DockerInfoModel infoModel : dockerInfoModels) {
|
||||
this.doDockerImage(infoModel, dockerfile, baseDir, dockerTag);
|
||||
}
|
||||
// 发布 docker 服务
|
||||
this.updateSwarmService(dockerTag, this.buildExtraModule.getDockerSwarmId(), this.buildExtraModule.getDockerSwarmServiceName());
|
||||
} finally {
|
||||
CommandUtil.systemFastDel(tempPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSwarmService(String dockerTag, String swarmId, String serviceName) {
|
||||
if (StrUtil.isEmpty(swarmId)) {
|
||||
return;
|
||||
}
|
||||
List<String> splitTrim = StrUtil.splitTrim(dockerTag, StrUtil.COMMA);
|
||||
String first = CollUtil.getFirst(splitTrim);
|
||||
logRecorder.info("start update swarm service: {} use image {}", serviceName, first);
|
||||
Map<String, Object> pluginMap = buildExecuteService.dockerInfoService.getBySwarmPluginMap(swarmId);
|
||||
pluginMap.put("serviceId", serviceName);
|
||||
pluginMap.put("image", first);
|
||||
try {
|
||||
IPlugin plugin = PluginFactory.getPlugin(DockerSwarmInfoService.DOCKER_PLUGIN_NAME);
|
||||
plugin.execute("updateServiceImage", pluginMap);
|
||||
} catch (Exception e) {
|
||||
logRecorder.error("调用容器异常", e);
|
||||
}
|
||||
}
|
||||
private void updateSwarmService(String dockerTag, String swarmId, String serviceName) {
|
||||
if (StrUtil.isEmpty(swarmId)) {
|
||||
return;
|
||||
}
|
||||
List<String> splitTrim = StrUtil.splitTrim(dockerTag, StrUtil.COMMA);
|
||||
String first = CollUtil.getFirst(splitTrim);
|
||||
logRecorder.info("start update swarm service: {} use image {}", serviceName, first);
|
||||
Map<String, Object> pluginMap = buildExecuteService.dockerInfoService.getBySwarmPluginMap(swarmId);
|
||||
pluginMap.put("serviceId", serviceName);
|
||||
pluginMap.put("image", first);
|
||||
try {
|
||||
IPlugin plugin = PluginFactory.getPlugin(DockerSwarmInfoService.DOCKER_PLUGIN_NAME);
|
||||
plugin.execute("updateServiceImage", pluginMap);
|
||||
} catch (Exception e) {
|
||||
logRecorder.error("调用容器异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void doDockerImage(DockerInfoModel dockerInfoModel, File dockerfile, File baseDir, String dockerTag) {
|
||||
logRecorder.info("{} start build image {}", dockerInfoModel.getName(), dockerTag);
|
||||
Map<String, Object> map = dockerInfoModel.toParameter();
|
||||
map.put("Dockerfile", dockerfile);
|
||||
map.put("baseDirectory", baseDir);
|
||||
//
|
||||
map.put("tags", dockerTag);
|
||||
Consumer<String> logConsumer = s -> logRecorder.append(s);
|
||||
map.put("logConsumer", logConsumer);
|
||||
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
|
||||
try {
|
||||
plugin.execute("buildImage", map);
|
||||
} catch (Exception e) {
|
||||
logRecorder.error("调用容器异常", e);
|
||||
}
|
||||
}
|
||||
private void doDockerImage(DockerInfoModel dockerInfoModel, File dockerfile, File baseDir, String dockerTag) {
|
||||
logRecorder.info("{} start build image {}", dockerInfoModel.getName(), dockerTag);
|
||||
Map<String, Object> map = dockerInfoModel.toParameter();
|
||||
map.put("Dockerfile", dockerfile);
|
||||
map.put("baseDirectory", baseDir);
|
||||
//
|
||||
map.put("tags", dockerTag);
|
||||
Consumer<String> logConsumer = s -> logRecorder.append(s);
|
||||
map.put("logConsumer", logConsumer);
|
||||
IPlugin plugin = PluginFactory.getPlugin(DockerInfoService.DOCKER_PLUGIN_NAME);
|
||||
try {
|
||||
plugin.execute("buildImage", map);
|
||||
} catch (Exception e) {
|
||||
logRecorder.error("调用容器异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地命令执行
|
||||
*/
|
||||
private void localCommand() {
|
||||
// 执行命令
|
||||
String[] commands = StrUtil.splitToArray(this.buildExtraModule.getReleaseCommand(), StrUtil.LF);
|
||||
if (ArrayUtil.isEmpty(commands)) {
|
||||
logRecorder.info("没有需要执行的ssh命令");
|
||||
return;
|
||||
}
|
||||
String command = StrUtil.EMPTY;
|
||||
logRecorder.info(DateUtil.now() + " start exec");
|
||||
InputStream templateInputStream = null;
|
||||
try {
|
||||
templateInputStream = ResourceUtil.getStream("classpath:/bin/execTemplate." + CommandUtil.SUFFIX);
|
||||
if (templateInputStream == null) {
|
||||
logRecorder.info("系统中没有命令模版");
|
||||
return;
|
||||
}
|
||||
String sshExecTemplate = IoUtil.readUtf8(templateInputStream);
|
||||
StringBuilder stringBuilder = new StringBuilder(sshExecTemplate);
|
||||
// 替换变量
|
||||
this.formatCommand(commands);
|
||||
//
|
||||
stringBuilder.append(ArrayUtil.join(commands, StrUtil.LF));
|
||||
File tempPath = ConfigBean.getInstance().getTempPath();
|
||||
File commandFile = FileUtil.file(tempPath, "build", this.buildExtraModule.getId() + StrUtil.DOT + CommandUtil.SUFFIX);
|
||||
FileUtil.writeUtf8String(stringBuilder.toString(), commandFile);
|
||||
//
|
||||
command = SystemUtil.getOsInfo().isWindows() ? StrUtil.EMPTY : CommandUtil.SUFFIX;
|
||||
command += " " + FileUtil.getAbsolutePath(commandFile);
|
||||
String result = CommandUtil.execSystemCommand(command);
|
||||
logRecorder.info(result);
|
||||
} catch (Exception e) {
|
||||
this.pubLog("执行本地命令异常:" + command, e);
|
||||
} finally {
|
||||
IoUtil.close(templateInputStream);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 本地命令执行
|
||||
*/
|
||||
private void localCommand() {
|
||||
// 执行命令
|
||||
String[] commands = StrUtil.splitToArray(this.buildExtraModule.getReleaseCommand(), StrUtil.LF);
|
||||
if (ArrayUtil.isEmpty(commands)) {
|
||||
logRecorder.info("没有需要执行的ssh命令");
|
||||
return;
|
||||
}
|
||||
String command = StrUtil.EMPTY;
|
||||
logRecorder.info(DateUtil.now() + " start exec");
|
||||
InputStream templateInputStream = null;
|
||||
try {
|
||||
templateInputStream = ResourceUtil.getStream("classpath:/bin/execTemplate." + CommandUtil.SUFFIX);
|
||||
if (templateInputStream == null) {
|
||||
logRecorder.info("系统中没有命令模版");
|
||||
return;
|
||||
}
|
||||
String sshExecTemplate = IoUtil.readUtf8(templateInputStream);
|
||||
StringBuilder stringBuilder = new StringBuilder(sshExecTemplate);
|
||||
// 替换变量
|
||||
this.formatCommand(commands);
|
||||
//
|
||||
stringBuilder.append(ArrayUtil.join(commands, StrUtil.LF));
|
||||
File tempPath = ConfigBean.getInstance().getTempPath();
|
||||
File commandFile = FileUtil.file(tempPath, "build", this.buildExtraModule.getId() + StrUtil.DOT + CommandUtil.SUFFIX);
|
||||
FileUtil.writeUtf8String(stringBuilder.toString(), commandFile);
|
||||
//
|
||||
// command = SystemUtil.getOsInfo().isWindows() ? StrUtil.EMPTY : CommandUtil.SUFFIX;
|
||||
command = CommandUtil.EXECUTE_PREFIX + StrUtil.SPACE + FileUtil.getAbsolutePath(commandFile);
|
||||
String result = CommandUtil.execSystemCommand(command);
|
||||
logRecorder.info(result);
|
||||
} catch (Exception e) {
|
||||
this.pubLog("执行本地命令异常:" + command, e);
|
||||
} finally {
|
||||
IoUtil.close(templateInputStream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ssh 发布
|
||||
*/
|
||||
private void doSsh() {
|
||||
String releaseMethodDataId = this.buildExtraModule.getReleaseMethodDataId();
|
||||
SshService sshService = SpringUtil.getBean(SshService.class);
|
||||
List<String> strings = StrUtil.splitTrim(releaseMethodDataId, StrUtil.COMMA);
|
||||
for (String releaseMethodDataIdItem : strings) {
|
||||
SshModel item = sshService.getByKey(releaseMethodDataIdItem, false);
|
||||
if (item == null) {
|
||||
logRecorder.info("没有找到对应的ssh项:" + releaseMethodDataIdItem);
|
||||
continue;
|
||||
}
|
||||
this.doSsh(item, sshService);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ssh 发布
|
||||
*/
|
||||
private void doSsh() {
|
||||
String releaseMethodDataId = this.buildExtraModule.getReleaseMethodDataId();
|
||||
SshService sshService = SpringUtil.getBean(SshService.class);
|
||||
List<String> strings = StrUtil.splitTrim(releaseMethodDataId, StrUtil.COMMA);
|
||||
for (String releaseMethodDataIdItem : strings) {
|
||||
SshModel item = sshService.getByKey(releaseMethodDataIdItem, false);
|
||||
if (item == null) {
|
||||
logRecorder.info("没有找到对应的ssh项:" + releaseMethodDataIdItem);
|
||||
continue;
|
||||
}
|
||||
this.doSsh(item, sshService);
|
||||
}
|
||||
}
|
||||
|
||||
private void doSsh(SshModel item, SshService sshService) {
|
||||
Session session = SshService.getSessionByModel(item);
|
||||
try {
|
||||
String releasePath = this.buildExtraModule.getReleasePath();
|
||||
if (StrUtil.isEmpty(releasePath)) {
|
||||
logRecorder.info("发布目录为空");
|
||||
} else {
|
||||
logRecorder.info("{} {} start ftp upload", DateUtil.now(), item.getName());
|
||||
try (Sftp sftp = new Sftp(session, item.getCharsetT())) {
|
||||
String prefix = "";
|
||||
if (!StrUtil.startWith(releasePath, StrUtil.SLASH)) {
|
||||
prefix = sftp.pwd();
|
||||
}
|
||||
String normalizePath = FileUtil.normalize(prefix + StrUtil.SLASH + releasePath);
|
||||
if (this.buildExtraModule.isClearOld()) {
|
||||
try {
|
||||
sftp.delDir(normalizePath);
|
||||
} catch (Exception e) {
|
||||
if (!StrUtil.startWithIgnoreCase(e.getMessage(), "No such file")) {
|
||||
this.pubLog("清除构建产物失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
sftp.syncUpload(this.resultFile, normalizePath);
|
||||
logRecorder.info("{} ftp upload done", item.getName());
|
||||
} catch (Exception e) {
|
||||
this.pubLog("执行ssh发布异常", e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
JschUtil.close(session);
|
||||
}
|
||||
logRecorder.info("");
|
||||
// 执行命令
|
||||
String[] commands = StrUtil.splitToArray(this.buildExtraModule.getReleaseCommand(), StrUtil.LF);
|
||||
if (commands == null || commands.length <= 0) {
|
||||
logRecorder.info("没有需要执行的ssh命令");
|
||||
return;
|
||||
}
|
||||
// 替换变量
|
||||
this.formatCommand(commands);
|
||||
//
|
||||
logRecorder.info("{} {} start exec", DateUtil.now(), item.getName());
|
||||
try {
|
||||
String s = sshService.exec(item, commands);
|
||||
logRecorder.info(s);
|
||||
} catch (Exception e) {
|
||||
this.pubLog(item.getName() + " 执行异常", e);
|
||||
}
|
||||
}
|
||||
private void doSsh(SshModel item, SshService sshService) {
|
||||
Session session = SshService.getSessionByModel(item);
|
||||
try {
|
||||
String releasePath = this.buildExtraModule.getReleasePath();
|
||||
if (StrUtil.isEmpty(releasePath)) {
|
||||
logRecorder.info("发布目录为空");
|
||||
} else {
|
||||
logRecorder.info("{} {} start ftp upload", DateUtil.now(), item.getName());
|
||||
try (Sftp sftp = new Sftp(session, item.getCharsetT())) {
|
||||
String prefix = "";
|
||||
if (!StrUtil.startWith(releasePath, StrUtil.SLASH)) {
|
||||
prefix = sftp.pwd();
|
||||
}
|
||||
String normalizePath = FileUtil.normalize(prefix + StrUtil.SLASH + releasePath);
|
||||
if (this.buildExtraModule.isClearOld()) {
|
||||
try {
|
||||
sftp.delDir(normalizePath);
|
||||
} catch (Exception e) {
|
||||
if (!StrUtil.startWithIgnoreCase(e.getMessage(), "No such file")) {
|
||||
this.pubLog("清除构建产物失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
sftp.syncUpload(this.resultFile, normalizePath);
|
||||
logRecorder.info("{} ftp upload done", item.getName());
|
||||
} catch (Exception e) {
|
||||
this.pubLog("执行ssh发布异常", e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
JschUtil.close(session);
|
||||
}
|
||||
logRecorder.info("");
|
||||
// 执行命令
|
||||
String[] commands = StrUtil.splitToArray(this.buildExtraModule.getReleaseCommand(), StrUtil.LF);
|
||||
if (commands == null || commands.length <= 0) {
|
||||
logRecorder.info("没有需要执行的ssh命令");
|
||||
return;
|
||||
}
|
||||
// 替换变量
|
||||
this.formatCommand(commands);
|
||||
//
|
||||
logRecorder.info("{} {} start exec", DateUtil.now(), item.getName());
|
||||
try {
|
||||
String s = sshService.exec(item, commands);
|
||||
logRecorder.info(s);
|
||||
} catch (Exception e) {
|
||||
this.pubLog(item.getName() + " 执行异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 差异上传发布
|
||||
*
|
||||
* @param nodeModel 节点
|
||||
* @param projectId 项目ID
|
||||
* @param afterOpt 发布后的操作
|
||||
*/
|
||||
private void diffSyncProject(NodeModel nodeModel, String projectId, AfterOpt afterOpt, boolean clearOld) {
|
||||
File resultFile = this.resultFile;
|
||||
String resultFileParent = resultFile.isFile() ?
|
||||
FileUtil.getAbsolutePath(resultFile.getParent()) : FileUtil.getAbsolutePath(this.resultFile);
|
||||
//
|
||||
List<File> files = FileUtil.loopFiles(resultFile);
|
||||
List<JSONObject> collect = files.stream().map(file -> {
|
||||
//
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("name", StringUtil.delStartPath(file, resultFileParent, true));
|
||||
jsonObject.put("sha1", SecureUtil.sha1(file));
|
||||
return jsonObject;
|
||||
}).collect(Collectors.toList());
|
||||
//
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("id", projectId);
|
||||
jsonObject.put("data", collect);
|
||||
JsonMessage<JSONObject> requestBody = NodeForward.requestBody(nodeModel, NodeUrl.MANAGE_FILE_DIFF_FILE, this.userModel, jsonObject);
|
||||
if (requestBody.getCode() != HttpStatus.HTTP_OK) {
|
||||
throw new JpomRuntimeException("对比项目文件失败:" + requestBody);
|
||||
}
|
||||
JSONObject data = requestBody.getData();
|
||||
JSONArray diff = data.getJSONArray("diff");
|
||||
JSONArray del = data.getJSONArray("del");
|
||||
int delSize = CollUtil.size(del);
|
||||
int diffSize = CollUtil.size(diff);
|
||||
if (clearOld) {
|
||||
logRecorder.info(StrUtil.format("对比文件结果,产物文件 {} 个、需要上传 {} 个、需要删除 {} 个", CollUtil.size(collect), CollUtil.size(diff), delSize));
|
||||
} else {
|
||||
logRecorder.info(StrUtil.format("对比文件结果,产物文件 {} 个、需要上传 {} 个", CollUtil.size(collect), CollUtil.size(diff)));
|
||||
}
|
||||
// 清空发布才先执行删除
|
||||
if (delSize > 0 && clearOld) {
|
||||
jsonObject.put("data", del);
|
||||
requestBody = NodeForward.requestBody(nodeModel, NodeUrl.MANAGE_FILE_BATCH_DELETE, this.userModel, jsonObject);
|
||||
if (requestBody.getCode() != HttpStatus.HTTP_OK) {
|
||||
throw new JpomRuntimeException("删除项目文件失败:" + requestBody);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < diffSize; i++) {
|
||||
boolean last = (i == diffSize - 1);
|
||||
JSONObject diffData = (JSONObject) diff.get(i);
|
||||
String name = diffData.getString("name");
|
||||
File file = FileUtil.file(resultFileParent, name);
|
||||
//
|
||||
String startPath = StringUtil.delStartPath(file, resultFileParent, false);
|
||||
//
|
||||
JsonMessage<String> jsonMessage = OutGivingRun.fileUpload(file, startPath,
|
||||
projectId, false, last ? afterOpt : AfterOpt.No, nodeModel, this.userModel, false);
|
||||
if (jsonMessage.getCode() != HttpStatus.HTTP_OK) {
|
||||
throw new JpomRuntimeException("同步项目文件失败:" + jsonMessage);
|
||||
}
|
||||
if (last) {
|
||||
// 最后一个
|
||||
logRecorder.info("发布项目包成功:" + jsonMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 差异上传发布
|
||||
*
|
||||
* @param nodeModel 节点
|
||||
* @param projectId 项目ID
|
||||
* @param afterOpt 发布后的操作
|
||||
*/
|
||||
private void diffSyncProject(NodeModel nodeModel, String projectId, AfterOpt afterOpt, boolean clearOld) {
|
||||
File resultFile = this.resultFile;
|
||||
String resultFileParent = resultFile.isFile() ?
|
||||
FileUtil.getAbsolutePath(resultFile.getParent()) : FileUtil.getAbsolutePath(this.resultFile);
|
||||
//
|
||||
List<File> files = FileUtil.loopFiles(resultFile);
|
||||
List<JSONObject> collect = files.stream().map(file -> {
|
||||
//
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("name", StringUtil.delStartPath(file, resultFileParent, true));
|
||||
jsonObject.put("sha1", SecureUtil.sha1(file));
|
||||
return jsonObject;
|
||||
}).collect(Collectors.toList());
|
||||
//
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("id", projectId);
|
||||
jsonObject.put("data", collect);
|
||||
JsonMessage<JSONObject> requestBody = NodeForward.requestBody(nodeModel, NodeUrl.MANAGE_FILE_DIFF_FILE, this.userModel, jsonObject);
|
||||
if (requestBody.getCode() != HttpStatus.HTTP_OK) {
|
||||
throw new JpomRuntimeException("对比项目文件失败:" + requestBody);
|
||||
}
|
||||
JSONObject data = requestBody.getData();
|
||||
JSONArray diff = data.getJSONArray("diff");
|
||||
JSONArray del = data.getJSONArray("del");
|
||||
int delSize = CollUtil.size(del);
|
||||
int diffSize = CollUtil.size(diff);
|
||||
if (clearOld) {
|
||||
logRecorder.info(StrUtil.format("对比文件结果,产物文件 {} 个、需要上传 {} 个、需要删除 {} 个", CollUtil.size(collect), CollUtil.size(diff), delSize));
|
||||
} else {
|
||||
logRecorder.info(StrUtil.format("对比文件结果,产物文件 {} 个、需要上传 {} 个", CollUtil.size(collect), CollUtil.size(diff)));
|
||||
}
|
||||
// 清空发布才先执行删除
|
||||
if (delSize > 0 && clearOld) {
|
||||
jsonObject.put("data", del);
|
||||
requestBody = NodeForward.requestBody(nodeModel, NodeUrl.MANAGE_FILE_BATCH_DELETE, this.userModel, jsonObject);
|
||||
if (requestBody.getCode() != HttpStatus.HTTP_OK) {
|
||||
throw new JpomRuntimeException("删除项目文件失败:" + requestBody);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < diffSize; i++) {
|
||||
boolean last = (i == diffSize - 1);
|
||||
JSONObject diffData = (JSONObject) diff.get(i);
|
||||
String name = diffData.getString("name");
|
||||
File file = FileUtil.file(resultFileParent, name);
|
||||
//
|
||||
String startPath = StringUtil.delStartPath(file, resultFileParent, false);
|
||||
//
|
||||
JsonMessage<String> jsonMessage = OutGivingRun.fileUpload(file, startPath,
|
||||
projectId, false, last ? afterOpt : AfterOpt.No, nodeModel, this.userModel, false);
|
||||
if (jsonMessage.getCode() != HttpStatus.HTTP_OK) {
|
||||
throw new JpomRuntimeException("同步项目文件失败:" + jsonMessage);
|
||||
}
|
||||
if (last) {
|
||||
// 最后一个
|
||||
logRecorder.info("发布项目包成功:" + jsonMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布项目
|
||||
*/
|
||||
private void doProject() {
|
||||
/**
|
||||
* 发布项目
|
||||
*/
|
||||
private void doProject() {
|
||||
// AfterOpt afterOpt, boolean clearOld, boolean diffSync
|
||||
AfterOpt afterOpt = BaseEnum.getEnum(AfterOpt.class, this.buildExtraModule.getAfterOpt(), AfterOpt.No);
|
||||
boolean clearOld = this.buildExtraModule.isClearOld();
|
||||
boolean diffSync = this.buildExtraModule.isDiffSync();
|
||||
String releaseMethodDataId = this.buildExtraModule.getReleaseMethodDataId();
|
||||
String[] strings = StrUtil.splitToArray(releaseMethodDataId, CharPool.COLON);
|
||||
if (ArrayUtil.length(strings) != 2) {
|
||||
throw new IllegalArgumentException(releaseMethodDataId + " error");
|
||||
}
|
||||
NodeService nodeService = SpringUtil.getBean(NodeService.class);
|
||||
NodeModel nodeModel = nodeService.getByKey(strings[0]);
|
||||
Objects.requireNonNull(nodeModel, "节点不存在");
|
||||
String projectId = strings[1];
|
||||
if (diffSync) {
|
||||
this.diffSyncProject(nodeModel, projectId, afterOpt, clearOld);
|
||||
return;
|
||||
}
|
||||
File zipFile = BuildUtil.isDirPackage(this.resultFile);
|
||||
boolean unZip = true;
|
||||
if (zipFile == null) {
|
||||
zipFile = this.resultFile;
|
||||
unZip = false;
|
||||
}
|
||||
JsonMessage<String> jsonMessage = OutGivingRun.fileUpload(zipFile, null,
|
||||
projectId,
|
||||
unZip,
|
||||
afterOpt,
|
||||
nodeModel, this.userModel, clearOld);
|
||||
if (jsonMessage.getCode() == HttpStatus.HTTP_OK) {
|
||||
logRecorder.info("发布项目包成功:" + jsonMessage);
|
||||
} else {
|
||||
throw new JpomRuntimeException("发布项目包失败:" + jsonMessage);
|
||||
}
|
||||
}
|
||||
AfterOpt afterOpt = BaseEnum.getEnum(AfterOpt.class, this.buildExtraModule.getAfterOpt(), AfterOpt.No);
|
||||
boolean clearOld = this.buildExtraModule.isClearOld();
|
||||
boolean diffSync = this.buildExtraModule.isDiffSync();
|
||||
String releaseMethodDataId = this.buildExtraModule.getReleaseMethodDataId();
|
||||
String[] strings = StrUtil.splitToArray(releaseMethodDataId, CharPool.COLON);
|
||||
if (ArrayUtil.length(strings) != 2) {
|
||||
throw new IllegalArgumentException(releaseMethodDataId + " error");
|
||||
}
|
||||
NodeService nodeService = SpringUtil.getBean(NodeService.class);
|
||||
NodeModel nodeModel = nodeService.getByKey(strings[0]);
|
||||
Objects.requireNonNull(nodeModel, "节点不存在");
|
||||
String projectId = strings[1];
|
||||
if (diffSync) {
|
||||
this.diffSyncProject(nodeModel, projectId, afterOpt, clearOld);
|
||||
return;
|
||||
}
|
||||
File zipFile = BuildUtil.isDirPackage(this.resultFile);
|
||||
boolean unZip = true;
|
||||
if (zipFile == null) {
|
||||
zipFile = this.resultFile;
|
||||
unZip = false;
|
||||
}
|
||||
JsonMessage<String> jsonMessage = OutGivingRun.fileUpload(zipFile, null,
|
||||
projectId,
|
||||
unZip,
|
||||
afterOpt,
|
||||
nodeModel, this.userModel, clearOld);
|
||||
if (jsonMessage.getCode() == HttpStatus.HTTP_OK) {
|
||||
logRecorder.info("发布项目包成功:" + jsonMessage);
|
||||
} else {
|
||||
throw new JpomRuntimeException("发布项目包失败:" + jsonMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 分发包
|
||||
*/
|
||||
private void doOutGiving() {
|
||||
String releaseMethodDataId = this.buildExtraModule.getReleaseMethodDataId();
|
||||
File zipFile = BuildUtil.isDirPackage(this.resultFile);
|
||||
boolean unZip = true;
|
||||
if (zipFile == null) {
|
||||
zipFile = this.resultFile;
|
||||
unZip = false;
|
||||
}
|
||||
OutGivingRun.startRun(releaseMethodDataId, zipFile, userModel, unZip);
|
||||
logRecorder.info("开始执行分发包啦,请到分发中查看当前状态");
|
||||
}
|
||||
/**
|
||||
* 分发包
|
||||
*/
|
||||
private void doOutGiving() {
|
||||
String releaseMethodDataId = this.buildExtraModule.getReleaseMethodDataId();
|
||||
File zipFile = BuildUtil.isDirPackage(this.resultFile);
|
||||
boolean unZip = true;
|
||||
if (zipFile == null) {
|
||||
zipFile = this.resultFile;
|
||||
unZip = false;
|
||||
}
|
||||
OutGivingRun.startRun(releaseMethodDataId, zipFile, userModel, unZip);
|
||||
logRecorder.info("开始执行分发包啦,请到分发中查看当前状态");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发布异常日志
|
||||
*
|
||||
* @param title 描述
|
||||
* @param throwable 异常
|
||||
*/
|
||||
private void pubLog(String title, Throwable throwable) {
|
||||
logRecorder.error(title, throwable);
|
||||
this.updateStatus(BuildStatus.PubError);
|
||||
}
|
||||
/**
|
||||
* 发布异常日志
|
||||
*
|
||||
* @param title 描述
|
||||
* @param throwable 异常
|
||||
*/
|
||||
private void pubLog(String title, Throwable throwable) {
|
||||
logRecorder.error(title, throwable);
|
||||
this.updateStatus(BuildStatus.PubError);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
this.start();
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
this.start();
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ import cn.hutool.core.io.LineHandler;
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.system.SystemUtil;
|
||||
import cn.jiangzeyin.common.DefaultSystemLog;
|
||||
import cn.jiangzeyin.common.JsonMessage;
|
||||
import cn.jiangzeyin.common.spring.SpringUtil;
|
||||
@ -55,177 +54,175 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* @date 2022/1/19
|
||||
*/
|
||||
public class ScriptProcessBuilder extends BaseRunScript implements Runnable {
|
||||
/**
|
||||
* 执行中的缓存
|
||||
*/
|
||||
private static final ConcurrentHashMap<String, ScriptProcessBuilder> FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* 执行中的缓存
|
||||
*/
|
||||
private static final ConcurrentHashMap<String, ScriptProcessBuilder> FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
private final ProcessBuilder processBuilder;
|
||||
private final Set<WebSocketSession> sessions = new HashSet<>();
|
||||
private final String executeId;
|
||||
private final ProcessBuilder processBuilder;
|
||||
private final Set<WebSocketSession> sessions = new HashSet<>();
|
||||
private final String executeId;
|
||||
|
||||
|
||||
private ScriptProcessBuilder(ScriptModel nodeScriptModel, String executeId, String args) {
|
||||
super(nodeScriptModel.logFile(executeId));
|
||||
this.executeId = executeId;
|
||||
//
|
||||
WorkspaceEnvVarService workspaceEnvVarService = SpringUtil.getBean(WorkspaceEnvVarService.class);
|
||||
Map<String, String> env = workspaceEnvVarService.getEnv(nodeScriptModel.getWorkspaceId());
|
||||
private ScriptProcessBuilder(ScriptModel nodeScriptModel, String executeId, String args) {
|
||||
super(nodeScriptModel.logFile(executeId));
|
||||
this.executeId = executeId;
|
||||
//
|
||||
WorkspaceEnvVarService workspaceEnvVarService = SpringUtil.getBean(WorkspaceEnvVarService.class);
|
||||
Map<String, String> env = workspaceEnvVarService.getEnv(nodeScriptModel.getWorkspaceId());
|
||||
|
||||
File scriptFile = nodeScriptModel.scriptFile();
|
||||
//
|
||||
String script = FileUtil.getAbsolutePath(scriptFile);
|
||||
processBuilder = new ProcessBuilder();
|
||||
List<String> command = StrUtil.splitTrim(args, StrUtil.SPACE);
|
||||
command.add(0, script);
|
||||
if (SystemUtil.getOsInfo().isLinux() || SystemUtil.getOsInfo().isMac()) {
|
||||
command.add(0, CommandUtil.SUFFIX);
|
||||
}
|
||||
DefaultSystemLog.getLog().debug(CollUtil.join(command, StrUtil.SPACE));
|
||||
processBuilder.redirectErrorStream(true);
|
||||
processBuilder.command(command);
|
||||
Map<String, String> environment = processBuilder.environment();
|
||||
environment.putAll(env);
|
||||
processBuilder.directory(scriptFile.getParentFile());
|
||||
}
|
||||
File scriptFile = nodeScriptModel.scriptFile();
|
||||
//
|
||||
String script = FileUtil.getAbsolutePath(scriptFile);
|
||||
processBuilder = new ProcessBuilder();
|
||||
List<String> command = StrUtil.splitTrim(args, StrUtil.SPACE);
|
||||
command.add(0, script);
|
||||
command.add(0, CommandUtil.EXECUTE_PREFIX);
|
||||
DefaultSystemLog.getLog().debug(CollUtil.join(command, StrUtil.SPACE));
|
||||
processBuilder.redirectErrorStream(true);
|
||||
processBuilder.command(command);
|
||||
Map<String, String> environment = processBuilder.environment();
|
||||
environment.putAll(env);
|
||||
processBuilder.directory(scriptFile.getParentFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建执行 并监听
|
||||
*
|
||||
* @param nodeScriptModel 脚本模版
|
||||
* @param executeId 执行ID
|
||||
* @param args 参数
|
||||
*/
|
||||
public static ScriptProcessBuilder create(ScriptModel nodeScriptModel, String executeId, String args) {
|
||||
return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.computeIfAbsent(executeId, file1 -> {
|
||||
ScriptProcessBuilder scriptProcessBuilder1 = new ScriptProcessBuilder(nodeScriptModel, executeId, args);
|
||||
ThreadUtil.execute(scriptProcessBuilder1);
|
||||
return scriptProcessBuilder1;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 创建执行 并监听
|
||||
*
|
||||
* @param nodeScriptModel 脚本模版
|
||||
* @param executeId 执行ID
|
||||
* @param args 参数
|
||||
*/
|
||||
public static ScriptProcessBuilder create(ScriptModel nodeScriptModel, String executeId, String args) {
|
||||
return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.computeIfAbsent(executeId, file1 -> {
|
||||
ScriptProcessBuilder scriptProcessBuilder1 = new ScriptProcessBuilder(nodeScriptModel, executeId, args);
|
||||
ThreadUtil.execute(scriptProcessBuilder1);
|
||||
return scriptProcessBuilder1;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建执行 并监听
|
||||
*
|
||||
* @param nodeScriptModel 脚本模版
|
||||
* @param executeId 执行ID
|
||||
* @param args 参数
|
||||
* @param session 会话
|
||||
*/
|
||||
public static void addWatcher(ScriptModel nodeScriptModel, String executeId, String args, WebSocketSession session) {
|
||||
ScriptProcessBuilder scriptProcessBuilder = create(nodeScriptModel, executeId, args);
|
||||
//
|
||||
if (scriptProcessBuilder.sessions.add(session)) {
|
||||
if (FileUtil.exist(scriptProcessBuilder.logFile)) {
|
||||
// 读取之前的信息并发送
|
||||
FileUtil.readLines(scriptProcessBuilder.logFile, CharsetUtil.CHARSET_UTF_8, (LineHandler) line -> {
|
||||
try {
|
||||
SocketSessionUtil.send(session, line);
|
||||
} catch (IOException e) {
|
||||
DefaultSystemLog.getLog().error("发送消息失败", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 创建执行 并监听
|
||||
*
|
||||
* @param nodeScriptModel 脚本模版
|
||||
* @param executeId 执行ID
|
||||
* @param args 参数
|
||||
* @param session 会话
|
||||
*/
|
||||
public static void addWatcher(ScriptModel nodeScriptModel, String executeId, String args, WebSocketSession session) {
|
||||
ScriptProcessBuilder scriptProcessBuilder = create(nodeScriptModel, executeId, args);
|
||||
//
|
||||
if (scriptProcessBuilder.sessions.add(session)) {
|
||||
if (FileUtil.exist(scriptProcessBuilder.logFile)) {
|
||||
// 读取之前的信息并发送
|
||||
FileUtil.readLines(scriptProcessBuilder.logFile, CharsetUtil.CHARSET_UTF_8, (LineHandler) line -> {
|
||||
try {
|
||||
SocketSessionUtil.send(session, line);
|
||||
} catch (IOException e) {
|
||||
DefaultSystemLog.getLog().error("发送消息失败", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否还在执行中
|
||||
*
|
||||
* @param executeId 执行id
|
||||
* @return true 还在执行
|
||||
*/
|
||||
public static boolean isRun(String executeId) {
|
||||
return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.containsKey(executeId);
|
||||
}
|
||||
/**
|
||||
* 判断是否还在执行中
|
||||
*
|
||||
* @param executeId 执行id
|
||||
* @return true 还在执行
|
||||
*/
|
||||
public static boolean isRun(String executeId) {
|
||||
return FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.containsKey(executeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭会话
|
||||
*
|
||||
* @param session 会话
|
||||
*/
|
||||
public static void stopWatcher(WebSocketSession session) {
|
||||
Collection<ScriptProcessBuilder> scriptProcessBuilders = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.values();
|
||||
for (ScriptProcessBuilder scriptProcessBuilder : scriptProcessBuilders) {
|
||||
Set<WebSocketSession> sessions = scriptProcessBuilder.sessions;
|
||||
sessions.removeIf(session1 -> session1.getId().equals(session.getId()));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 关闭会话
|
||||
*
|
||||
* @param session 会话
|
||||
*/
|
||||
public static void stopWatcher(WebSocketSession session) {
|
||||
Collection<ScriptProcessBuilder> scriptProcessBuilders = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.values();
|
||||
for (ScriptProcessBuilder scriptProcessBuilder : scriptProcessBuilders) {
|
||||
Set<WebSocketSession> sessions = scriptProcessBuilder.sessions;
|
||||
sessions.removeIf(session1 -> session1.getId().equals(session.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止脚本命令
|
||||
*
|
||||
* @param executeId 执行ID
|
||||
*/
|
||||
public static void stopRun(String executeId) {
|
||||
ScriptProcessBuilder scriptProcessBuilder = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.get(executeId);
|
||||
if (scriptProcessBuilder != null) {
|
||||
scriptProcessBuilder.end("停止运行");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 停止脚本命令
|
||||
*
|
||||
* @param executeId 执行ID
|
||||
*/
|
||||
public static void stopRun(String executeId) {
|
||||
ScriptProcessBuilder scriptProcessBuilder = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.get(executeId);
|
||||
if (scriptProcessBuilder != null) {
|
||||
scriptProcessBuilder.end("停止运行");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
//初始化ProcessBuilder对象
|
||||
try {
|
||||
this.handle("start execute:" + DateUtil.now());
|
||||
process = processBuilder.start();
|
||||
{
|
||||
inputStream = process.getInputStream();
|
||||
IoUtil.readLines(inputStream, ExtConfigBean.getInstance().getConsoleLogCharset(), (LineHandler) ScriptProcessBuilder.this::handle);
|
||||
}
|
||||
int waitFor = process.waitFor();
|
||||
JsonMessage<String> jsonMessage = new JsonMessage<>(200, "执行完毕:" + waitFor);
|
||||
JSONObject jsonObject = jsonMessage.toJson();
|
||||
jsonObject.put("op", ConsoleCommandOp.stop.name());
|
||||
this.end(jsonObject.toString());
|
||||
this.handle("execute done:" + waitFor + " time:" + DateUtil.now());
|
||||
} catch (Exception e) {
|
||||
DefaultSystemLog.getLog().error("执行异常", e);
|
||||
this.end("执行异常:" + e.getMessage());
|
||||
} finally {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
//初始化ProcessBuilder对象
|
||||
try {
|
||||
this.handle("start execute:" + DateUtil.now());
|
||||
process = processBuilder.start();
|
||||
{
|
||||
inputStream = process.getInputStream();
|
||||
IoUtil.readLines(inputStream, ExtConfigBean.getInstance().getConsoleLogCharset(), (LineHandler) ScriptProcessBuilder.this::handle);
|
||||
}
|
||||
int waitFor = process.waitFor();
|
||||
JsonMessage<String> jsonMessage = new JsonMessage<>(200, "执行完毕:" + waitFor);
|
||||
JSONObject jsonObject = jsonMessage.toJson();
|
||||
jsonObject.put("op", ConsoleCommandOp.stop.name());
|
||||
this.end(jsonObject.toString());
|
||||
this.handle("execute done:" + waitFor + " time:" + DateUtil.now());
|
||||
} catch (Exception e) {
|
||||
DefaultSystemLog.getLog().error("执行异常", e);
|
||||
this.end("执行异常:" + e.getMessage());
|
||||
} finally {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束执行
|
||||
*
|
||||
* @param msg 响应的消息
|
||||
*/
|
||||
@Override
|
||||
protected void end(String msg) {
|
||||
Iterator<WebSocketSession> iterator = sessions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
WebSocketSession session = iterator.next();
|
||||
try {
|
||||
SocketSessionUtil.send(session, msg);
|
||||
} catch (IOException e) {
|
||||
DefaultSystemLog.getLog().error("发送消息失败", e);
|
||||
}
|
||||
iterator.remove();
|
||||
}
|
||||
FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.remove(this.executeId);
|
||||
}
|
||||
/**
|
||||
* 结束执行
|
||||
*
|
||||
* @param msg 响应的消息
|
||||
*/
|
||||
@Override
|
||||
protected void end(String msg) {
|
||||
Iterator<WebSocketSession> iterator = sessions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
WebSocketSession session = iterator.next();
|
||||
try {
|
||||
SocketSessionUtil.send(session, msg);
|
||||
} catch (IOException e) {
|
||||
DefaultSystemLog.getLog().error("发送消息失败", e);
|
||||
}
|
||||
iterator.remove();
|
||||
}
|
||||
FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.remove(this.executeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应
|
||||
*
|
||||
* @param line 信息
|
||||
*/
|
||||
@Override
|
||||
protected void handle(String line) {
|
||||
super.handle(line);
|
||||
//
|
||||
Iterator<WebSocketSession> iterator = sessions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
WebSocketSession session = iterator.next();
|
||||
try {
|
||||
SocketSessionUtil.send(session, line);
|
||||
} catch (IOException e) {
|
||||
DefaultSystemLog.getLog().error("发送消息失败", e);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 响应
|
||||
*
|
||||
* @param line 信息
|
||||
*/
|
||||
@Override
|
||||
protected void handle(String line) {
|
||||
super.handle(line);
|
||||
//
|
||||
Iterator<WebSocketSession> iterator = sessions.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
WebSocketSession session = iterator.next();
|
||||
try {
|
||||
SocketSessionUtil.send(session, line);
|
||||
} catch (IOException e) {
|
||||
DefaultSystemLog.getLog().error("发送消息失败", e);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="full-content">
|
||||
<!-- 数据表格 -->
|
||||
<a-table :data-source="list" :columns="columns" @change="changePage" :pagination="this.listQuery.total / this.listQuery.limit > 1 ? (this, pagination) : false" bordered rowKey="id">
|
||||
<a-table :data-source="list" size="middle" :columns="columns" @change="changePage" :pagination="this.listQuery.total / this.listQuery.limit > 1 ? (this, pagination) : false" bordered rowKey="id">
|
||||
<template slot="title">
|
||||
<a-space>
|
||||
<a-input v-model="listQuery['%name%']" placeholder="名称" @pressEnter="loadData" allowClear class="search-input-item" />
|
||||
@ -46,9 +46,9 @@
|
||||
</a-tooltip>
|
||||
<template slot="operation" slot-scope="text, record">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="handleExec(record)">执行</a-button>
|
||||
<a-button type="primary" @click="handleEdit(record)">编辑</a-button>
|
||||
<a-button type="danger" @click="handleDelete(record)">删除</a-button>
|
||||
<a-button size="small" type="primary" @click="handleExec(record)">执行</a-button>
|
||||
<a-button size="small" type="primary" @click="handleEdit(record)">编辑</a-button>
|
||||
<a-button size="small" type="danger" @click="handleDelete(record)">删除</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-table>
|
||||
@ -137,7 +137,7 @@ export default {
|
||||
{ title: "修改时间", dataIndex: "modifyTimeMillis", sorter: true, width: 170, ellipsis: true, scopedSlots: { customRender: "modifyTimeMillis" } },
|
||||
{ title: "修改人", dataIndex: "modifyUser", ellipsis: true, scopedSlots: { customRender: "modifyUser" }, width: 120 },
|
||||
{ title: "最后操作人", dataIndex: "lastRunUser", ellipsis: true, scopedSlots: { customRender: "lastRunUser" } },
|
||||
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: 260 },
|
||||
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: 180 },
|
||||
],
|
||||
rules: {
|
||||
name: [{ required: true, message: "Please input Script name", trigger: "blur" }],
|
||||
|
@ -3,6 +3,7 @@
|
||||
<a-table
|
||||
:data-source="commandList"
|
||||
:columns="columns"
|
||||
size="middle"
|
||||
bordered
|
||||
:pagination="this.listQuery.total / this.listQuery.limit > 1 ? (this, pagination) : false"
|
||||
@change="changePage"
|
||||
@ -43,9 +44,9 @@
|
||||
|
||||
<template slot="operation" slot-scope="text, record">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="handleEdit(record)">编辑</a-button>
|
||||
<a-button type="primary" @click="handleExecute(record)">执行</a-button>
|
||||
<a-button type="danger" @click="handleDelete(record)">删除</a-button>
|
||||
<a-button size="small" type="primary" @click="handleEdit(record)">编辑</a-button>
|
||||
<a-button size="small" type="primary" @click="handleExecute(record)">执行</a-button>
|
||||
<a-button size="small" type="danger" @click="handleDelete(record)">删除</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-table>
|
||||
@ -204,7 +205,7 @@ export default {
|
||||
ellipsis: true,
|
||||
scopedSlots: { customRender: "modifyUser" },
|
||||
},
|
||||
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: 250 },
|
||||
{ title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: 180 },
|
||||
],
|
||||
};
|
||||
},
|
||||
|
@ -7,6 +7,7 @@
|
||||
<a-table
|
||||
:data-source="list"
|
||||
:columns="columns"
|
||||
size="middle"
|
||||
:pagination="this.listQuery.total / this.listQuery.limit > 1 ? (this, pagination) : false"
|
||||
@change="changePage"
|
||||
bordered
|
||||
@ -42,7 +43,7 @@
|
||||
<div v-if="sshAgentInfo[record.id]">
|
||||
<div v-if="sshAgentInfo[record.id].javaVersion">
|
||||
<a-tooltip v-if="sshAgentInfo[record.id].nodeId" placement="topLeft" :title="`节点名称:${sshAgentInfo[record.id].nodeName}`">
|
||||
<a-button style="width: 90px; padding: 0 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis" type="" @click="toNode(sshAgentInfo[record.id].nodeId)">
|
||||
<a-button size="small" style="width: 90px; padding: 0 10px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis" type="" @click="toNode(sshAgentInfo[record.id].nodeId)">
|
||||
{{ sshAgentInfo[record.id].nodeName }}
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
@ -54,7 +55,7 @@
|
||||
placement="topLeft"
|
||||
:title="`${sshAgentInfo[record.id].pid > 0 ? 'ssh 中已经运行了插件端进程ID:' + sshAgentInfo[record.id].pid : '点击快速安装插件端,java :' + sshAgentInfo[record.id].javaVersion}`"
|
||||
>
|
||||
<a-button type="primary" @click="install(record)" :disabled="sshAgentInfo[record.id].pid > 0">安装节点</a-button>
|
||||
<a-button size="small" type="primary" @click="install(record)" :disabled="sshAgentInfo[record.id].pid > 0">安装节点</a-button>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<div v-else><a-tag>没有Java环境</a-tag></div>
|
||||
@ -63,9 +64,9 @@
|
||||
</template>
|
||||
<template slot="operation" slot-scope="text, record">
|
||||
<a-space>
|
||||
<a-button type="primary" @click="handleTerminal(record)">终端</a-button>
|
||||
<a-button size="small" type="primary" @click="handleTerminal(record)">终端</a-button>
|
||||
<a-tooltip placement="topLeft" title="如果按钮不可用,请去 ssh 编辑中添加允许管理的授权文件夹">
|
||||
<a-button type="primary" :disabled="!record.fileDirs" @click="handleFile(record)">文件</a-button>
|
||||
<a-button size="small" type="primary" :disabled="!record.fileDirs" @click="handleFile(record)">文件</a-button>
|
||||
</a-tooltip>
|
||||
<a-dropdown>
|
||||
<a class="ant-dropdown-link" @click="(e) => e.preventDefault()">
|
||||
@ -412,8 +413,8 @@ export default {
|
||||
title: "操作",
|
||||
dataIndex: "operation",
|
||||
scopedSlots: { customRender: "operation" },
|
||||
width: 230,
|
||||
fixed: "right",
|
||||
width: 180,
|
||||
align: "center",
|
||||
// ellipsis: true,
|
||||
},
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user