mirror of
https://gitee.com/dromara/Jpom.git
synced 2024-11-30 02:48:17 +08:00
fix SH配置和节点配置新增跨工作空间同步功能,方便快速同步信息 #I56YTU
This commit is contained in:
parent
79a311afce
commit
4e3dd39528
@ -7,7 +7,8 @@
|
||||
|
||||
1. 【server】节点新增代理配置,实现使用代理访问插件端(感谢@背着砍刀的诗人)
|
||||
2. 【server】构建新增差异构建配置选择(如果仓库代码未变动则不执行构建)
|
||||
3. 项目管理文件新增备份,自动备份变动的文件(感谢[@少爷123](https://gitee.com/58753101) [Gitee issues I54ZFM](https://gitee.com/dromara/Jpom/issues/I54ZFM))
|
||||
3. 项目管理文件新增备份,自动备份变动的文件(感谢[@少爷123](https://gitee.com/58753101) [Gitee issues I54ZFM](https://gitee.com/dromara/Jpom/issues/I54ZFM) )
|
||||
4. 【server】SH配置和节点配置新增跨工作空间同步功能,方便快速同步信息(感谢[@陈旭](https://gitee.com/chenxu8989) ) [Gitee issues I56YTU](https://gitee.com/dromara/Jpom/issues/I56YTU)
|
||||
|
||||
### 🐞 解决BUG、优化功能
|
||||
|
||||
@ -18,6 +19,7 @@
|
||||
5. 【server】调整 docker-compose 使用卷方式存储数据,避免在部分环境中出现无法正常使用情况 (感谢 [@💎ℳ๓₯㎕斌💎💘](https://gitee.com/weihongbin) 贡献解决方案)(感谢[@笨笨巫师](https://gitee.com/zhangxin_gitosc) [Gitee issues I52OAV](https://gitee.com/dromara/Jpom/issues/I52OAV) )
|
||||
6. 【server】调整节点里面在部分情况下会出现空白行 (感谢[@💎ℳ๓₯㎕斌💎💘](https://gitee.com/weihongbin) )
|
||||
7. 【server】前端部分输入框添加`maxLength` 限制避免出现数据库字段长度不足问题(感谢@ccx2480 )
|
||||
8. 【agent】修复项目下载远程文件解压方法错误(感谢@背着砍刀的诗人 )
|
||||
|
||||
> 使用项目文件备份说明:
|
||||
>
|
||||
|
@ -217,11 +217,37 @@ public class NodeEditController extends BaseServerController {
|
||||
return JsonMessage.getString(200, "操作成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 解锁节点,通过插件端自动注册的节点默认未分配工作空间
|
||||
*
|
||||
* @param id 节点ID
|
||||
* @param workspaceId 分配到到工作空间ID
|
||||
* @return msg
|
||||
*/
|
||||
@GetMapping(value = "un_lock_workspace", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.EDIT)
|
||||
@SystemPermission(superUser = true)
|
||||
@SystemPermission()
|
||||
public String unLockWorkspace(@ValidatorItem String id, @ValidatorItem String workspaceId) {
|
||||
nodeService.checkUserWorkspace(workspaceId);
|
||||
nodeService.unLock(id, workspaceId);
|
||||
return JsonMessage.getString(200, "操作成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步到指定工作空间
|
||||
*
|
||||
* @param ids 节点ID
|
||||
* @param workspaceId 分配到到工作空间ID
|
||||
* @return msg
|
||||
*/
|
||||
@GetMapping(value = "sync-to-workspace", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.EDIT)
|
||||
@SystemPermission()
|
||||
public String syncToWorkspace(@ValidatorItem String ids, @ValidatorItem String workspaceId) {
|
||||
String nowWorkspaceId = nodeService.getCheckUserWorkspace(getRequest());
|
||||
//
|
||||
nodeService.checkUserWorkspace(workspaceId);
|
||||
nodeService.syncToWorkspace(ids, nowWorkspaceId, workspaceId);
|
||||
return JsonMessage.getString(200, "操作成功");
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ import io.jpom.model.log.SshTerminalExecuteLog;
|
||||
import io.jpom.permission.ClassFeature;
|
||||
import io.jpom.permission.Feature;
|
||||
import io.jpom.permission.MethodFeature;
|
||||
import io.jpom.permission.SystemPermission;
|
||||
import io.jpom.service.dblog.BuildInfoService;
|
||||
import io.jpom.service.dblog.SshTerminalExecuteLogService;
|
||||
import io.jpom.service.node.ssh.SshService;
|
||||
@ -72,214 +73,231 @@ import java.util.List;
|
||||
@Feature(cls = ClassFeature.SSH)
|
||||
public class SshController extends BaseServerController {
|
||||
|
||||
private final SshService sshService;
|
||||
private final SshTerminalExecuteLogService sshTerminalExecuteLogService;
|
||||
private final BuildInfoService buildInfoService;
|
||||
private final SshService sshService;
|
||||
private final SshTerminalExecuteLogService sshTerminalExecuteLogService;
|
||||
private final BuildInfoService buildInfoService;
|
||||
|
||||
public SshController(SshService sshService,
|
||||
SshTerminalExecuteLogService sshTerminalExecuteLogService,
|
||||
BuildInfoService buildInfoService) {
|
||||
this.sshService = sshService;
|
||||
this.sshTerminalExecuteLogService = sshTerminalExecuteLogService;
|
||||
this.buildInfoService = buildInfoService;
|
||||
}
|
||||
public SshController(SshService sshService,
|
||||
SshTerminalExecuteLogService sshTerminalExecuteLogService,
|
||||
BuildInfoService buildInfoService) {
|
||||
this.sshService = sshService;
|
||||
this.sshTerminalExecuteLogService = sshTerminalExecuteLogService;
|
||||
this.buildInfoService = buildInfoService;
|
||||
}
|
||||
|
||||
|
||||
@PostMapping(value = "list_data.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public JsonMessage<PageResultDto<SshModel>> listData() {
|
||||
PageResultDto<SshModel> pageResultDto = sshService.listPage(getRequest());
|
||||
return new JsonMessage<>(200, "", pageResultDto);
|
||||
}
|
||||
@PostMapping(value = "list_data.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public JsonMessage<PageResultDto<SshModel>> listData() {
|
||||
PageResultDto<SshModel> pageResultDto = sshService.listPage(getRequest());
|
||||
return new JsonMessage<>(200, "", pageResultDto);
|
||||
}
|
||||
|
||||
@GetMapping(value = "list_data_all.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public JsonMessage<List<SshModel>> listDataAll() {
|
||||
List<SshModel> list = sshService.listByWorkspace(getRequest());
|
||||
return new JsonMessage<>(200, "", list);
|
||||
}
|
||||
@GetMapping(value = "list_data_all.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public JsonMessage<List<SshModel>> listDataAll() {
|
||||
List<SshModel> list = sshService.listByWorkspace(getRequest());
|
||||
return new JsonMessage<>(200, "", list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
*
|
||||
* @param name 名称
|
||||
* @param host 端口
|
||||
* @param user 用户名
|
||||
* @param password 密码
|
||||
* @param connectType 连接方式
|
||||
* @param privateKey 私钥
|
||||
* @param port 端口
|
||||
* @param charset 编码格式
|
||||
* @param fileDirs 文件夹
|
||||
* @param id ID
|
||||
* @param notAllowedCommand 禁止输入的命令
|
||||
* @return json
|
||||
*/
|
||||
@PostMapping(value = "save.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.EDIT)
|
||||
public String save(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "ssh名称不能为空") String name,
|
||||
@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "host不能为空") String host,
|
||||
@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "user不能为空") String user,
|
||||
String password,
|
||||
SshModel.ConnectType connectType,
|
||||
String privateKey,
|
||||
@ValidatorItem(value = ValidatorRule.POSITIVE_INTEGER, msg = "port错误") int port,
|
||||
String charset, String fileDirs,
|
||||
String id, String notAllowedCommand) {
|
||||
SshModel sshModel;
|
||||
boolean add = StrUtil.isEmpty(getParameter("id"));
|
||||
if (add) {
|
||||
// 优先判断参数 如果是 password 在修改时可以不填写
|
||||
if (connectType == SshModel.ConnectType.PASS) {
|
||||
Assert.hasText(password, "请填写登录密码");
|
||||
} else if (connectType == SshModel.ConnectType.PUBKEY) {
|
||||
//Assert.hasText(privateKey, "请填写证书内容");
|
||||
}
|
||||
sshModel = new SshModel();
|
||||
} else {
|
||||
sshModel = sshService.getByKey(id);
|
||||
Assert.notNull(sshModel, "不存在对应ssh");
|
||||
}
|
||||
// 目录
|
||||
if (StrUtil.isEmpty(fileDirs)) {
|
||||
sshModel.fileDirs(null);
|
||||
} else {
|
||||
List<String> list = StrSplitter.splitTrim(fileDirs, StrUtil.LF, true);
|
||||
for (String s : list) {
|
||||
String normalize = FileUtil.normalize(s + StrUtil.SLASH);
|
||||
int count = StrUtil.count(normalize, StrUtil.SLASH);
|
||||
Assert.state(count >= 2, "ssh 授权目录不能是根目录");
|
||||
}
|
||||
//
|
||||
UserModel userModel = getUser();
|
||||
Assert.state(!userModel.isDemoUser(), PermissionInterceptor.DEMO_TIP);
|
||||
sshModel.fileDirs(list);
|
||||
}
|
||||
sshModel.setHost(host);
|
||||
// 如果密码传递不为空就设置值 因为上面已经判断了只有修改的情况下 password 才可能为空
|
||||
if (StrUtil.isNotEmpty(password)) {
|
||||
sshModel.setPassword(password);
|
||||
}
|
||||
if (StrUtil.startWith(privateKey, URLUtil.FILE_URL_PREFIX)) {
|
||||
String rsaPath = StrUtil.removePrefix(privateKey, URLUtil.FILE_URL_PREFIX);
|
||||
Assert.state(FileUtil.isFile(rsaPath), "配置的私钥文件不存在");
|
||||
}
|
||||
if (StrUtil.isNotEmpty(privateKey)) {
|
||||
sshModel.setPrivateKey(privateKey);
|
||||
}
|
||||
/**
|
||||
* 编辑
|
||||
*
|
||||
* @param name 名称
|
||||
* @param host 端口
|
||||
* @param user 用户名
|
||||
* @param password 密码
|
||||
* @param connectType 连接方式
|
||||
* @param privateKey 私钥
|
||||
* @param port 端口
|
||||
* @param charset 编码格式
|
||||
* @param fileDirs 文件夹
|
||||
* @param id ID
|
||||
* @param notAllowedCommand 禁止输入的命令
|
||||
* @return json
|
||||
*/
|
||||
@PostMapping(value = "save.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.EDIT)
|
||||
public String save(@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "ssh名称不能为空") String name,
|
||||
@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "host不能为空") String host,
|
||||
@ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "user不能为空") String user,
|
||||
String password,
|
||||
SshModel.ConnectType connectType,
|
||||
String privateKey,
|
||||
@ValidatorItem(value = ValidatorRule.POSITIVE_INTEGER, msg = "port错误") int port,
|
||||
String charset, String fileDirs,
|
||||
String id, String notAllowedCommand) {
|
||||
SshModel sshModel;
|
||||
boolean add = StrUtil.isEmpty(getParameter("id"));
|
||||
if (add) {
|
||||
// 优先判断参数 如果是 password 在修改时可以不填写
|
||||
if (connectType == SshModel.ConnectType.PASS) {
|
||||
Assert.hasText(password, "请填写登录密码");
|
||||
} else if (connectType == SshModel.ConnectType.PUBKEY) {
|
||||
//Assert.hasText(privateKey, "请填写证书内容");
|
||||
}
|
||||
sshModel = new SshModel();
|
||||
} else {
|
||||
sshModel = sshService.getByKey(id);
|
||||
Assert.notNull(sshModel, "不存在对应ssh");
|
||||
}
|
||||
// 目录
|
||||
if (StrUtil.isEmpty(fileDirs)) {
|
||||
sshModel.fileDirs(null);
|
||||
} else {
|
||||
List<String> list = StrSplitter.splitTrim(fileDirs, StrUtil.LF, true);
|
||||
for (String s : list) {
|
||||
String normalize = FileUtil.normalize(s + StrUtil.SLASH);
|
||||
int count = StrUtil.count(normalize, StrUtil.SLASH);
|
||||
Assert.state(count >= 2, "ssh 授权目录不能是根目录");
|
||||
}
|
||||
//
|
||||
UserModel userModel = getUser();
|
||||
Assert.state(!userModel.isDemoUser(), PermissionInterceptor.DEMO_TIP);
|
||||
sshModel.fileDirs(list);
|
||||
}
|
||||
sshModel.setHost(host);
|
||||
// 如果密码传递不为空就设置值 因为上面已经判断了只有修改的情况下 password 才可能为空
|
||||
if (StrUtil.isNotEmpty(password)) {
|
||||
sshModel.setPassword(password);
|
||||
}
|
||||
if (StrUtil.startWith(privateKey, URLUtil.FILE_URL_PREFIX)) {
|
||||
String rsaPath = StrUtil.removePrefix(privateKey, URLUtil.FILE_URL_PREFIX);
|
||||
Assert.state(FileUtil.isFile(rsaPath), "配置的私钥文件不存在");
|
||||
}
|
||||
if (StrUtil.isNotEmpty(privateKey)) {
|
||||
sshModel.setPrivateKey(privateKey);
|
||||
}
|
||||
|
||||
sshModel.setPort(port);
|
||||
sshModel.setUser(user);
|
||||
sshModel.setName(name);
|
||||
sshModel.setNotAllowedCommand(notAllowedCommand);
|
||||
sshModel.setConnectType(connectType.name());
|
||||
// 获取允许编辑的后缀
|
||||
String allowEditSuffix = getParameter("allowEditSuffix");
|
||||
List<String> allowEditSuffixList = AgentWhitelist.parseToList(allowEditSuffix, "允许编辑的文件后缀不能为空");
|
||||
sshModel.allowEditSuffix(allowEditSuffixList);
|
||||
try {
|
||||
Charset.forName(charset);
|
||||
sshModel.setCharset(charset);
|
||||
} catch (Exception e) {
|
||||
return JsonMessage.getString(405, "请填写正确的编码格式");
|
||||
}
|
||||
// 判断重复
|
||||
HttpServletRequest request = getRequest();
|
||||
String workspaceId = sshService.getCheckUserWorkspace(request);
|
||||
Entity entity = Entity.create();
|
||||
entity.set("host", sshModel.getHost());
|
||||
entity.set("port", sshModel.getPort());
|
||||
entity.set("workspaceId", workspaceId);
|
||||
if (StrUtil.isNotEmpty(id)) {
|
||||
entity.set("id", StrUtil.format(" <> {}", id));
|
||||
}
|
||||
boolean exists = sshService.exists(entity);
|
||||
Assert.state(!exists, "对应的SSH已经存在啦");
|
||||
try {
|
||||
SshModel model = sshService.getByKey(id, false);
|
||||
if (model != null) {
|
||||
sshModel.setPassword(StrUtil.emptyToDefault(sshModel.getPassword(), model.getPassword()));
|
||||
sshModel.setPrivateKey(StrUtil.emptyToDefault(sshModel.getPrivateKey(), model.getPrivateKey()));
|
||||
}
|
||||
Session session = SshService.getSessionByModel(sshModel);
|
||||
JschUtil.close(session);
|
||||
} catch (Exception e) {
|
||||
return JsonMessage.getString(505, "ssh连接失败:" + e.getMessage());
|
||||
}
|
||||
if (add) {
|
||||
sshService.insert(sshModel);
|
||||
} else {
|
||||
sshService.update(sshModel);
|
||||
}
|
||||
return JsonMessage.getString(200, "操作成功");
|
||||
}
|
||||
sshModel.setPort(port);
|
||||
sshModel.setUser(user);
|
||||
sshModel.setName(name);
|
||||
sshModel.setNotAllowedCommand(notAllowedCommand);
|
||||
sshModel.setConnectType(connectType.name());
|
||||
// 获取允许编辑的后缀
|
||||
String allowEditSuffix = getParameter("allowEditSuffix");
|
||||
List<String> allowEditSuffixList = AgentWhitelist.parseToList(allowEditSuffix, "允许编辑的文件后缀不能为空");
|
||||
sshModel.allowEditSuffix(allowEditSuffixList);
|
||||
try {
|
||||
Charset.forName(charset);
|
||||
sshModel.setCharset(charset);
|
||||
} catch (Exception e) {
|
||||
return JsonMessage.getString(405, "请填写正确的编码格式");
|
||||
}
|
||||
// 判断重复
|
||||
HttpServletRequest request = getRequest();
|
||||
String workspaceId = sshService.getCheckUserWorkspace(request);
|
||||
Entity entity = Entity.create();
|
||||
entity.set("host", sshModel.getHost());
|
||||
entity.set("port", sshModel.getPort());
|
||||
entity.set("workspaceId", workspaceId);
|
||||
if (StrUtil.isNotEmpty(id)) {
|
||||
entity.set("id", StrUtil.format(" <> {}", id));
|
||||
}
|
||||
boolean exists = sshService.exists(entity);
|
||||
Assert.state(!exists, "对应的SSH已经存在啦");
|
||||
try {
|
||||
SshModel model = sshService.getByKey(id, false);
|
||||
if (model != null) {
|
||||
sshModel.setPassword(StrUtil.emptyToDefault(sshModel.getPassword(), model.getPassword()));
|
||||
sshModel.setPrivateKey(StrUtil.emptyToDefault(sshModel.getPrivateKey(), model.getPrivateKey()));
|
||||
}
|
||||
Session session = SshService.getSessionByModel(sshModel);
|
||||
JschUtil.close(session);
|
||||
} catch (Exception e) {
|
||||
return JsonMessage.getString(505, "ssh连接失败:" + e.getMessage());
|
||||
}
|
||||
if (add) {
|
||||
sshService.insert(sshModel);
|
||||
} else {
|
||||
sshService.update(sshModel);
|
||||
}
|
||||
return JsonMessage.getString(200, "操作成功");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查 ssh 是否安装插件端
|
||||
*
|
||||
* @param ids ids
|
||||
* @return json
|
||||
*/
|
||||
@GetMapping(value = "check_agent.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public String checkAgent(String ids) {
|
||||
List<SshModel> sshModels = sshService.listById(StrUtil.split(ids, StrUtil.COMMA), getRequest());
|
||||
Assert.notEmpty(sshModels, "没有任何节点信息");
|
||||
/**
|
||||
* 检查 ssh 是否安装插件端
|
||||
*
|
||||
* @param ids ids
|
||||
* @return json
|
||||
*/
|
||||
@GetMapping(value = "check_agent.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.LIST)
|
||||
public String checkAgent(String ids) {
|
||||
List<SshModel> sshModels = sshService.listById(StrUtil.split(ids, StrUtil.COMMA), getRequest());
|
||||
Assert.notEmpty(sshModels, "没有任何节点信息");
|
||||
|
||||
JSONObject result = new JSONObject();
|
||||
for (SshModel sshModel : sshModels) {
|
||||
List<NodeModel> nodeBySshId = nodeService.getNodeBySshId(sshModel.getId());
|
||||
JSONObject data = new JSONObject();
|
||||
NodeModel nodeModel = CollUtil.getFirst(nodeBySshId);
|
||||
SshModel model = sshService.getByKey(sshModel.getId(), false);
|
||||
try {
|
||||
if (nodeModel == null) {
|
||||
Integer pid = sshService.checkSshRunPid(model, Type.Agent.getTag());
|
||||
data.put("pid", ObjectUtil.defaultIfNull(pid, 0));
|
||||
data.put("ok", true);
|
||||
} else {
|
||||
data.put("nodeId", nodeModel.getId());
|
||||
data.put("nodeName", nodeModel.getName());
|
||||
}
|
||||
//
|
||||
String javaVersion = sshService.checkCommand(model, "java");
|
||||
data.put("javaVersion", javaVersion);
|
||||
} catch (Exception e) {
|
||||
DefaultSystemLog.getLog().error("检查运行状态异常:{}", e.getMessage());
|
||||
data.put("error", e.getMessage());
|
||||
}
|
||||
result.put(sshModel.getId(), data);
|
||||
}
|
||||
return JsonMessage.getString(200, "", result);
|
||||
}
|
||||
JSONObject result = new JSONObject();
|
||||
for (SshModel sshModel : sshModels) {
|
||||
List<NodeModel> nodeBySshId = nodeService.getNodeBySshId(sshModel.getId());
|
||||
JSONObject data = new JSONObject();
|
||||
NodeModel nodeModel = CollUtil.getFirst(nodeBySshId);
|
||||
SshModel model = sshService.getByKey(sshModel.getId(), false);
|
||||
try {
|
||||
if (nodeModel == null) {
|
||||
Integer pid = sshService.checkSshRunPid(model, Type.Agent.getTag());
|
||||
data.put("pid", ObjectUtil.defaultIfNull(pid, 0));
|
||||
data.put("ok", true);
|
||||
} else {
|
||||
data.put("nodeId", nodeModel.getId());
|
||||
data.put("nodeName", nodeModel.getName());
|
||||
}
|
||||
//
|
||||
String javaVersion = sshService.checkCommand(model, "java");
|
||||
data.put("javaVersion", javaVersion);
|
||||
} catch (Exception e) {
|
||||
DefaultSystemLog.getLog().error("检查运行状态异常:{}", e.getMessage());
|
||||
data.put("error", e.getMessage());
|
||||
}
|
||||
result.put(sshModel.getId(), data);
|
||||
}
|
||||
return JsonMessage.getString(200, "", result);
|
||||
}
|
||||
|
||||
@PostMapping(value = "del.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.DEL)
|
||||
public String del(@ValidatorItem(value = ValidatorRule.NOT_BLANK) String id) {
|
||||
HttpServletRequest request = getRequest();
|
||||
boolean checkSsh = buildInfoService.checkReleaseMethodByLike(id, request, BuildReleaseMethod.Ssh);
|
||||
Assert.state(!checkSsh, "当前ssh存在构建项,不能删除");
|
||||
// 判断是否绑定节点
|
||||
List<NodeModel> nodeBySshId = nodeService.getNodeBySshId(id);
|
||||
Assert.state(CollUtil.isEmpty(nodeBySshId), "当前ssh被节点绑定,不能删除");
|
||||
@PostMapping(value = "del.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.DEL)
|
||||
public String del(@ValidatorItem(value = ValidatorRule.NOT_BLANK) String id) {
|
||||
HttpServletRequest request = getRequest();
|
||||
boolean checkSsh = buildInfoService.checkReleaseMethodByLike(id, request, BuildReleaseMethod.Ssh);
|
||||
Assert.state(!checkSsh, "当前ssh存在构建项,不能删除");
|
||||
// 判断是否绑定节点
|
||||
List<NodeModel> nodeBySshId = nodeService.getNodeBySshId(id);
|
||||
Assert.state(CollUtil.isEmpty(nodeBySshId), "当前ssh被节点绑定,不能删除");
|
||||
|
||||
sshService.delByKey(id, request);
|
||||
//
|
||||
int logCount = sshTerminalExecuteLogService.delByWorkspace(request, entity -> entity.set("sshId", id));
|
||||
return JsonMessage.getString(200, "操作成功");
|
||||
}
|
||||
sshService.delByKey(id, request);
|
||||
//
|
||||
int logCount = sshTerminalExecuteLogService.delByWorkspace(request, entity -> entity.set("sshId", id));
|
||||
return JsonMessage.getString(200, "操作成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行记录
|
||||
*
|
||||
* @return json
|
||||
*/
|
||||
@PostMapping(value = "log_list_data.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(cls = ClassFeature.SSH_TERMINAL_LOG, method = MethodFeature.LIST)
|
||||
public String logListData() {
|
||||
PageResultDto<SshTerminalExecuteLog> pageResult = sshTerminalExecuteLogService.listPage(getRequest());
|
||||
return JsonMessage.getString(200, "获取成功", pageResult);
|
||||
}
|
||||
/**
|
||||
* 执行记录
|
||||
*
|
||||
* @return json
|
||||
*/
|
||||
@PostMapping(value = "log_list_data.json", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(cls = ClassFeature.SSH_TERMINAL_LOG, method = MethodFeature.LIST)
|
||||
public String logListData() {
|
||||
PageResultDto<SshTerminalExecuteLog> pageResult = sshTerminalExecuteLogService.listPage(getRequest());
|
||||
return JsonMessage.getString(200, "获取成功", pageResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步到指定工作空间
|
||||
*
|
||||
* @param ids 节点ID
|
||||
* @param workspaceId 分配到到工作空间ID
|
||||
* @return msg
|
||||
*/
|
||||
@GetMapping(value = "sync-to-workspace", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@Feature(method = MethodFeature.EDIT)
|
||||
@SystemPermission()
|
||||
public String syncToWorkspace(@ValidatorItem String ids, @ValidatorItem String workspaceId) {
|
||||
String nowWorkspaceId = nodeService.getCheckUserWorkspace(getRequest());
|
||||
//
|
||||
sshService.checkUserWorkspace(workspaceId);
|
||||
sshService.syncToWorkspace(ids, nowWorkspaceId, workspaceId);
|
||||
return JsonMessage.getString(200, "操作成功");
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +99,11 @@ public class NodeModel extends BaseGroupModel {
|
||||
this.setId(id);
|
||||
}
|
||||
|
||||
public NodeModel(String id, String workspaceId) {
|
||||
this.setId(id);
|
||||
this.setWorkspaceId(workspaceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 授权的信息
|
||||
*
|
||||
|
@ -31,6 +31,8 @@ import io.jpom.model.BaseWorkspaceModel;
|
||||
import io.jpom.service.h2db.TableName;
|
||||
import io.jpom.util.StringUtil;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
@ -43,6 +45,8 @@ import java.util.List;
|
||||
*/
|
||||
@TableName(value = "SSH_INFO", name = "SSH 信息")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@NoArgsConstructor
|
||||
public class SshModel extends BaseWorkspaceModel {
|
||||
|
||||
private String name;
|
||||
@ -77,6 +81,14 @@ public class SshModel extends BaseWorkspaceModel {
|
||||
*/
|
||||
private String allowEditSuffix;
|
||||
|
||||
public SshModel(String id) {
|
||||
this.setId(id);
|
||||
}
|
||||
|
||||
public SshModel(String id, String workspaceId) {
|
||||
this.setId(id);
|
||||
this.setWorkspaceId(workspaceId);
|
||||
}
|
||||
|
||||
public ConnectType connectType() {
|
||||
return EnumUtil.fromString(ConnectType.class, this.connectType, ConnectType.PASS);
|
||||
|
@ -247,6 +247,8 @@ public abstract class BaseDbCommonService<T> {
|
||||
* 根据主键查询实体
|
||||
*
|
||||
* @param keyValue 主键值
|
||||
* @param fill 是否执行填充逻辑
|
||||
* @param consumer 参数回调
|
||||
* @return 数据
|
||||
*/
|
||||
public T getByKey(String keyValue, boolean fill, Consumer<Entity> consumer) {
|
||||
|
@ -53,6 +53,8 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -242,6 +244,49 @@ public class NodeService extends BaseGroupService<NodeModel> {
|
||||
super.update(nodeModel1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将节点信息同步到其他工作空间
|
||||
*
|
||||
* @param ids 多给节点ID
|
||||
* @param nowWorkspaceId 当前的工作空间ID
|
||||
* @param workspaceId 同步到哪个工作空间
|
||||
*/
|
||||
public void syncToWorkspace(String ids, String nowWorkspaceId, String workspaceId) {
|
||||
StrUtil.splitTrim(ids, StrUtil.COMMA)
|
||||
.forEach(id -> {
|
||||
NodeModel data = super.getByKey(id, false, entity -> entity.set("workspaceId", nowWorkspaceId));
|
||||
Assert.notNull(data, "没有对应到节点信息");
|
||||
//
|
||||
NodeModel where = new NodeModel();
|
||||
where.setWorkspaceId(workspaceId);
|
||||
where.setUrl(data.getUrl());
|
||||
NodeModel nodeModel = NodeService.super.queryByBean(where);
|
||||
if (nodeModel == null) {
|
||||
// 不存在则添加节点
|
||||
data.setId(null);
|
||||
data.setWorkspaceId(workspaceId);
|
||||
data.setCreateTimeMillis(null);
|
||||
data.setModifyTimeMillis(null);
|
||||
data.setModifyUser(null);
|
||||
NodeService.super.insert(data);
|
||||
} else {
|
||||
// 修改信息
|
||||
NodeModel update = new NodeModel(nodeModel.getId());
|
||||
update.setLoginName(data.getLoginName());
|
||||
update.setLoginPwd(data.getLoginPwd());
|
||||
update.setProtocol(data.getProtocol());
|
||||
update.setHttpProxy(data.getHttpProxy());
|
||||
update.setHttpProxyType(data.getHttpProxyType());
|
||||
NodeService.super.updateById(update);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断节点是否锁定中
|
||||
*
|
||||
* @param nodeModel 节点
|
||||
*/
|
||||
private void checkLockType(NodeModel nodeModel) {
|
||||
if (nodeModel == null) {
|
||||
return;
|
||||
@ -304,19 +349,19 @@ public class NodeService extends BaseGroupService<NodeModel> {
|
||||
* @param info 节点信息
|
||||
*/
|
||||
private void updateDuplicateNode(NodeModel info) {
|
||||
if (StrUtil.hasEmpty(info.getUrl(), info.getLoginName(), info.getLoginPwd())) {
|
||||
return;
|
||||
}
|
||||
NodeModel update = new NodeModel();
|
||||
update.setLoginName(info.getLoginName());
|
||||
update.setLoginPwd(info.getLoginPwd());
|
||||
//
|
||||
NodeModel where = new NodeModel();
|
||||
where.setUrl(info.getUrl());
|
||||
int updateCount = super.update(super.dataBeanToEntity(update), super.dataBeanToEntity(where));
|
||||
if (updateCount > 1) {
|
||||
DefaultSystemLog.getLog().debug("update duplicate node {} {}", info.getUrl(), updateCount);
|
||||
}
|
||||
// if (StrUtil.hasEmpty(info.getUrl(), info.getLoginName(), info.getLoginPwd())) {
|
||||
// return;
|
||||
// }
|
||||
// NodeModel update = new NodeModel();
|
||||
// update.setLoginName(info.getLoginName());
|
||||
// update.setLoginPwd(info.getLoginPwd());
|
||||
// //
|
||||
// NodeModel where = new NodeModel();
|
||||
// where.setUrl(info.getUrl());
|
||||
// int updateCount = super.update(super.dataBeanToEntity(update), super.dataBeanToEntity(where));
|
||||
// if (updateCount > 1) {
|
||||
// DefaultSystemLog.getLog().debug("update duplicate node {} {}", info.getUrl(), updateCount);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,8 +37,10 @@ import com.jcraft.jsch.ChannelSftp;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.jcraft.jsch.Session;
|
||||
import com.jcraft.jsch.SftpException;
|
||||
import io.jpom.model.data.NodeModel;
|
||||
import io.jpom.model.data.SshModel;
|
||||
import io.jpom.service.h2db.BaseWorkspaceService;
|
||||
import io.jpom.service.node.NodeService;
|
||||
import io.jpom.system.ConfigBean;
|
||||
import io.jpom.util.JschUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -99,10 +101,10 @@ public class SshService extends BaseWorkspaceService<SshModel> {
|
||||
} else if (StrUtil.startWith(privateKey, JschUtils.HEADER)) {
|
||||
// 直接采用 private key content 登录,无需写入文件
|
||||
session = JschUtils.createSession(sshModel.getHost(),
|
||||
sshModel.getPort(),
|
||||
sshModel.getUser(),
|
||||
StrUtil.trim(privateKey),
|
||||
sshModel.password());
|
||||
sshModel.getPort(),
|
||||
sshModel.getUser(),
|
||||
StrUtil.trim(privateKey),
|
||||
sshModel.password());
|
||||
} else if (StrUtil.isEmpty(privateKey)) {
|
||||
File home = FileUtil.getUserHomeDir();
|
||||
Assert.notNull(home, "用户目录没有找到");
|
||||
@ -125,7 +127,7 @@ public class SshService extends BaseWorkspaceService<SshModel> {
|
||||
// 简要私钥文件是否存在
|
||||
Assert.state(FileUtil.isFile(rsaFile), "私钥文件不存在:" + FileUtil.getAbsolutePath(rsaFile));
|
||||
session = JschUtil.openSession(sshModel.getHost(),
|
||||
sshModel.getPort(), sshModel.getUser(), FileUtil.getAbsolutePath(rsaFile), sshModel.password());
|
||||
sshModel.getPort(), sshModel.getUser(), FileUtil.getAbsolutePath(rsaFile), sshModel.password());
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("不支持的模式");
|
||||
@ -375,4 +377,42 @@ public class SshService extends BaseWorkspaceService<SshModel> {
|
||||
JschUtil.close(session);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将节点信息同步到其他工作空间
|
||||
*
|
||||
* @param ids 多给节点ID
|
||||
* @param nowWorkspaceId 当前的工作空间ID
|
||||
* @param workspaceId 同步到哪个工作空间
|
||||
*/
|
||||
public void syncToWorkspace(String ids, String nowWorkspaceId, String workspaceId) {
|
||||
StrUtil.splitTrim(ids, StrUtil.COMMA)
|
||||
.forEach(id -> {
|
||||
SshModel data = super.getByKey(id, false, entity -> entity.set("workspaceId", nowWorkspaceId));
|
||||
Assert.notNull(data, "没有对应到节点信息");
|
||||
//
|
||||
SshModel where = new SshModel();
|
||||
where.setWorkspaceId(workspaceId);
|
||||
where.setHost(data.getHost());
|
||||
where.setPort(data.getPort());
|
||||
where.setConnectType(data.getConnectType());
|
||||
SshModel sshModel = super.queryByBean(where);
|
||||
if (sshModel == null) {
|
||||
// 不存在则添加 信息
|
||||
data.setId(null);
|
||||
data.setWorkspaceId(workspaceId);
|
||||
data.setCreateTimeMillis(null);
|
||||
data.setModifyTimeMillis(null);
|
||||
data.setModifyUser(null);
|
||||
super.insert(data);
|
||||
} else {
|
||||
// 修改信息
|
||||
SshModel update = new SshModel(data.getId());
|
||||
update.setUser(data.getUser());
|
||||
update.setPassword(data.getPassword());
|
||||
update.setPrivateKey(data.getPrivateKey());
|
||||
super.updateById(update);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -96,6 +96,14 @@ export function unLockWorkspace(params) {
|
||||
});
|
||||
}
|
||||
|
||||
export function syncToWorkspace(params) {
|
||||
return axios({
|
||||
url: "/node/sync-to-workspace",
|
||||
method: "get",
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
|
||||
// 删除节点项目缓存
|
||||
export function delAllProjectCache() {
|
||||
return axios({
|
||||
|
@ -238,3 +238,11 @@ export function newFileFolder(params) {
|
||||
data: params,
|
||||
});
|
||||
}
|
||||
|
||||
export function syncToWorkspace(params) {
|
||||
return axios({
|
||||
url: "/node/ssh/sync-to-workspace",
|
||||
method: "get",
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
@expand="expand"
|
||||
:pagination="this.listQuery.total / this.listQuery.limit > 1 ? (this, pagination) : false"
|
||||
@change="changePage"
|
||||
:row-selection="rowSelection"
|
||||
>
|
||||
<template slot="title">
|
||||
<a-space>
|
||||
@ -30,20 +31,20 @@
|
||||
<a-menu-item>
|
||||
<a-button type="primary" @click="fastInstall">快速安装</a-button>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-button type="primary" :disabled="!tableSelections || !tableSelections.length" @click="syncToWorkspaceShow">工作空间同步</a-button>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
<div>点击节点管理进入节点管理页面</div>
|
||||
|
||||
<div>
|
||||
<ul>
|
||||
<li>节点账号密码为插件端的账号密码,并非用户账号(管理员)密码</li>
|
||||
<li>节点账号密码默认由系统生成:可以通过插件端数据目录下 agent_authorize.json 文件查看(如果自定义配置了账号密码将没有此文件)</li>
|
||||
<li>节点地址为插件端的 IP:PORT 插件端端口默认为:2123</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ul>
|
||||
<li>点击节点管理进入节点管理页面</li>
|
||||
<li>节点账号密码为插件端的账号密码,并非用户账号(管理员)密码</li>
|
||||
<li>节点账号密码默认由系统生成:可以通过插件端数据目录下 agent_authorize.json 文件查看(如果自定义配置了账号密码将没有此文件)</li>
|
||||
<li>节点地址为插件端的 IP:PORT 插件端端口默认为:2123</li>
|
||||
</ul>
|
||||
</template>
|
||||
<a-icon type="question-circle" theme="filled" />
|
||||
</a-tooltip>
|
||||
@ -384,11 +385,44 @@
|
||||
</div>
|
||||
<div v-else>loading....</div>
|
||||
</a-modal>
|
||||
<!-- 同步到其他工作空间 -->
|
||||
<a-modal v-model="syncToWorkspaceVisible" title="同步到其他工作空间" @ok="handleSyncToWorkspace" :maskClosable="false">
|
||||
<a-alert message="温馨提示" type="warning">
|
||||
<template slot="description">
|
||||
<ul>
|
||||
<li>同步机制采用节点地址确定为是同一个服务器(节点)</li>
|
||||
<li>当目标工作空间不存在对应的节点时候将自动创建一个新的节点(逻辑节点)</li>
|
||||
<li>当目标工作空间已经存在节点时候将自动同步节点授权信息、代理配置信息</li>
|
||||
</ul>
|
||||
</template>
|
||||
</a-alert>
|
||||
<a-form-model :model="temp" :label-col="{ span: 6 }" :wrapper-col="{ span: 14 }">
|
||||
<a-form-model-item> </a-form-model-item>
|
||||
<a-form-model-item label="选择工作空间" prop="workspaceId">
|
||||
<a-select show-search option-filter-prop="children" v-model="temp.workspaceId" placeholder="请选择工作空间">
|
||||
<a-select-option :disabled="getWorkspaceId === item.id" v-for="item in workspaceList" :key="item.id">{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapGetters } from "vuex";
|
||||
import { getNodeList, getNodeStatus, editNode, unbind, deleteNode, syncProject, unLockWorkspace, getNodeGroupAll, fastInstall, pullFastInstallResult, confirmFastInstall } from "@/api/node";
|
||||
import {
|
||||
getNodeList,
|
||||
getNodeStatus,
|
||||
editNode,
|
||||
unbind,
|
||||
deleteNode,
|
||||
syncProject,
|
||||
unLockWorkspace,
|
||||
getNodeGroupAll,
|
||||
fastInstall,
|
||||
pullFastInstallResult,
|
||||
confirmFastInstall,
|
||||
syncToWorkspace,
|
||||
} from "@/api/node";
|
||||
import { getSshListAll } from "@/api/ssh";
|
||||
import { syncScript } from "@/api/node-other";
|
||||
import NodeLayout from "./node-layout";
|
||||
@ -416,9 +450,7 @@ export default {
|
||||
nodeStatusData: {},
|
||||
groupList: [],
|
||||
showOptVisible: {},
|
||||
temp: {
|
||||
timeOut: 0,
|
||||
},
|
||||
temp: {},
|
||||
fastInstallActiveKey: ["1", "2", "4"],
|
||||
fastInstallInfo: null,
|
||||
tempVue: null,
|
||||
@ -429,6 +461,7 @@ export default {
|
||||
terminalVisible: false,
|
||||
unlockNode: false,
|
||||
fastInstallNode: false,
|
||||
syncToWorkspaceVisible: false,
|
||||
drawerTitle: "",
|
||||
columns: [
|
||||
// { title: "节点 ID", dataIndex: "id", sorter: true, key: "id", ellipsis: true, scopedSlots: { customRender: "id" } },
|
||||
@ -473,6 +506,7 @@ export default {
|
||||
timeOut: [{ required: true, message: "Please input timeout", trigger: "blur" }],
|
||||
},
|
||||
workspaceList: [],
|
||||
tableSelections: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -490,6 +524,14 @@ export default {
|
||||
},
|
||||
};
|
||||
},
|
||||
rowSelection() {
|
||||
return {
|
||||
onChange: (selectedRowKeys) => {
|
||||
this.tableSelections = selectedRowKeys;
|
||||
},
|
||||
selectedRowKeys: this.tableSelections,
|
||||
};
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
@ -789,7 +831,7 @@ export default {
|
||||
okText: "确认",
|
||||
cancelText: "取消",
|
||||
onOk: () => {
|
||||
// 删除
|
||||
// 解锁
|
||||
unLockWorkspace({
|
||||
id: this.temp.id,
|
||||
workspaceId: this.temp.workspaceId,
|
||||
@ -862,6 +904,37 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
// 同步到其他工作情况
|
||||
syncToWorkspaceShow() {
|
||||
this.syncToWorkspaceVisible = true;
|
||||
this.loadWorkSpaceListAll();
|
||||
this.temp = {
|
||||
workspaceId: undefined,
|
||||
};
|
||||
},
|
||||
//
|
||||
handleSyncToWorkspace() {
|
||||
if (!this.temp.workspaceId) {
|
||||
this.$notification.warn({
|
||||
message: "请选择工作空间",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// 同步
|
||||
syncToWorkspace({
|
||||
ids: this.tableSelections.join(","),
|
||||
workspaceId: this.temp.workspaceId,
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
this.$notification.success({
|
||||
message: res.msg,
|
||||
});
|
||||
this.tableSelections = [];
|
||||
this.syncToWorkspaceVisible = false;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -83,10 +83,10 @@
|
||||
<a-button size="small" type="primary" @click="handleEdit(record)">编辑</a-button>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-button size="small" type="primary" @click="handleMonitor(record)" v-show="javaModes.includes(record.runMode)" :disabled="!record.status">监控 </a-button>
|
||||
<a-button size="small" type="primary" @click="handleMonitor(record)" v-if="javaModes.includes(record.runMode)" :disabled="!record.status">监控 </a-button>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-button size="small" type="primary" @click="handleReplica(record)" v-show="javaModes.includes(record.runMode)" :disabled="!record.javaCopyItemList">副本集 </a-button>
|
||||
<a-button size="small" type="primary" @click="handleReplica(record)" v-if="javaModes.includes(record.runMode)" :disabled="!record.javaCopyItemList">副本集 </a-button>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a-tooltip v-if="record.outGivingProject" title="节点分发项目需要到节点分发中去删除">
|
||||
|
@ -11,7 +11,8 @@
|
||||
:pagination="this.listQuery.total / this.listQuery.limit > 1 ? (this, pagination) : false"
|
||||
@change="changePage"
|
||||
bordered
|
||||
:rowKey="(record, index) => index"
|
||||
rowKey="id"
|
||||
:row-selection="rowSelection"
|
||||
>
|
||||
<template slot="title">
|
||||
<a-space>
|
||||
@ -22,7 +23,14 @@
|
||||
<a-button type="primary" :loading="loading" @click="loadData">搜索</a-button>
|
||||
</a-tooltip>
|
||||
<a-button type="primary" @click="handleAdd">新增</a-button>
|
||||
|
||||
<a-dropdown>
|
||||
<a class="ant-dropdown-link" @click="(e) => e.preventDefault()"> 更多 <a-icon type="down" /> </a>
|
||||
<a-menu slot="overlay">
|
||||
<a-menu-item>
|
||||
<a-button type="primary" :disabled="!tableSelections || !tableSelections.length" @click="syncToWorkspaceShow">工作空间同步</a-button>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</a-dropdown>
|
||||
<a-tooltip>
|
||||
<template slot="title">
|
||||
<div>
|
||||
@ -58,7 +66,12 @@
|
||||
<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>
|
||||
<div v-else>
|
||||
<a-tooltip v-if="sshAgentInfo[record.id].error" :title="sshAgentInfo[record.id].error">
|
||||
<a-tag>连接异常</a-tag>
|
||||
</a-tooltip>
|
||||
<a-tag v-else>没有Java环境</a-tag>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>-</div>
|
||||
</template>
|
||||
@ -309,15 +322,37 @@
|
||||
</template>
|
||||
</a-table>
|
||||
</a-modal>
|
||||
<!-- 同步到其他工作空间 -->
|
||||
<a-modal v-model="syncToWorkspaceVisible" title="同步到其他工作空间" @ok="handleSyncToWorkspace" :maskClosable="false">
|
||||
<a-alert message="温馨提示" type="warning">
|
||||
<template slot="description">
|
||||
<ul>
|
||||
<li>同步机制采用 IP+PORT+连接方式 确定为是同一个服务器</li>
|
||||
<li>当目标工作空间不存在对应的 SSH 时候将自动创建一个新的 SSH</li>
|
||||
<li>当目标工作空间已经存在 SSH 时候将自动同步 SSH 账号、密码、私钥信息</li>
|
||||
</ul>
|
||||
</template>
|
||||
</a-alert>
|
||||
<a-form-model :model="temp" :label-col="{ span: 6 }" :wrapper-col="{ span: 14 }">
|
||||
<a-form-model-item> </a-form-model-item>
|
||||
<a-form-model-item label="选择工作空间" prop="workspaceId">
|
||||
<a-select show-search option-filter-prop="children" v-model="temp.workspaceId" placeholder="请选择工作空间">
|
||||
<a-select-option :disabled="getWorkspaceId === item.id" v-for="item in workspaceList" :key="item.id">{{ item.name }}</a-select-option>
|
||||
</a-select>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { deleteSsh, editSsh, getSshList, getSshCheckAgent, getSshOperationLogList, installAgentNode, getAgent, uploadAgent } from "@/api/ssh";
|
||||
import { deleteSsh, editSsh, getSshList, getSshCheckAgent, getSshOperationLogList, installAgentNode, getAgent, uploadAgent, syncToWorkspace } from "@/api/ssh";
|
||||
import SshFile from "@/pages/ssh/ssh-file";
|
||||
import Terminal from "@/pages/ssh/terminal";
|
||||
import { parseTime } from "@/utils/time";
|
||||
import { PAGE_DEFAULT_LIMIT, PAGE_DEFAULT_SIZW_OPTIONS, PAGE_DEFAULT_SHOW_TOTAL, PAGE_DEFAULT_LIST_QUERY } from "@/utils/const";
|
||||
import { getWorkSpaceListAll } from "@/api/workspace";
|
||||
import Vue from "vue";
|
||||
import { mapGetters } from "vuex";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -332,6 +367,9 @@ export default {
|
||||
listQuery: Object.assign({}, PAGE_DEFAULT_LIST_QUERY),
|
||||
editSshVisible: false,
|
||||
nodeVisible: false,
|
||||
syncToWorkspaceVisible: false,
|
||||
tableSelections: [],
|
||||
workspaceList: [],
|
||||
tempNode: {},
|
||||
fileList: [],
|
||||
sshAgentInfo: {},
|
||||
@ -397,7 +435,7 @@ export default {
|
||||
dataIndex: "nodeId",
|
||||
scopedSlots: { customRender: "nodeId" },
|
||||
width: 120,
|
||||
// ellipsis: true,
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: "修改时间",
|
||||
@ -446,6 +484,7 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["getWorkspaceId"]),
|
||||
viewOperationLogPagination() {
|
||||
return {
|
||||
total: this.viewOperationLogListQuery.total || 0,
|
||||
@ -472,6 +511,14 @@ export default {
|
||||
},
|
||||
};
|
||||
},
|
||||
rowSelection() {
|
||||
return {
|
||||
onChange: (selectedRowKeys) => {
|
||||
this.tableSelections = selectedRowKeys;
|
||||
},
|
||||
selectedRowKeys: this.tableSelections,
|
||||
};
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.loadData();
|
||||
@ -731,6 +778,45 @@ export default {
|
||||
onClose() {
|
||||
this.drawerVisible = false;
|
||||
},
|
||||
// 加载工作空间数据
|
||||
loadWorkSpaceListAll() {
|
||||
getWorkSpaceListAll().then((res) => {
|
||||
if (res.code === 200) {
|
||||
this.workspaceList = res.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
// 同步到其他工作情况
|
||||
syncToWorkspaceShow() {
|
||||
this.syncToWorkspaceVisible = true;
|
||||
this.loadWorkSpaceListAll();
|
||||
this.temp = {
|
||||
workspaceId: undefined,
|
||||
};
|
||||
},
|
||||
//
|
||||
handleSyncToWorkspace() {
|
||||
if (!this.temp.workspaceId) {
|
||||
this.$notification.warn({
|
||||
message: "请选择工作空间",
|
||||
});
|
||||
return false;
|
||||
}
|
||||
// 同步
|
||||
syncToWorkspace({
|
||||
ids: this.tableSelections.join(","),
|
||||
workspaceId: this.temp.workspaceId,
|
||||
}).then((res) => {
|
||||
if (res.code == 200) {
|
||||
this.$notification.success({
|
||||
message: res.msg,
|
||||
});
|
||||
this.tableSelections = [];
|
||||
this.syncToWorkspaceVisible = false;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user