fix 节点脚本支持全局共享同步节点、节点管理查看脚本重复问题

This commit is contained in:
bwcx_jzy 2023-03-30 18:45:48 +08:00
parent 5f7caf6684
commit d5bbe166aa
No known key found for this signature in database
GPG Key ID: 5E48E9372088B9E5
9 changed files with 161 additions and 82 deletions

View File

@ -1,6 +1,15 @@
# 🚀 版本日志
### 2.10.38.9-beta
### 2.10.38.10-beta (2023-03-30)
### 🐞 解决BUG、优化功能
1. 【server】修复 节点脚本支持全局共享同步节点、节点管理查看脚本重复问题(感谢@奇奇)
------
### 2.10.38.9-beta (2023-03-30)
### 🐣 新增功能

View File

@ -31,6 +31,7 @@ import io.jpom.common.forward.NodeForward;
import io.jpom.common.forward.NodeUrl;
import io.jpom.common.validator.ValidatorItem;
import io.jpom.model.data.NodeModel;
import io.jpom.model.data.WorkspaceModel;
import io.jpom.model.script.ScriptModel;
import io.jpom.model.user.UserModel;
import io.jpom.permission.ClassFeature;
@ -41,6 +42,7 @@ import io.jpom.script.CommandParam;
import io.jpom.service.node.script.NodeScriptServer;
import io.jpom.service.script.ScriptExecuteLogServer;
import io.jpom.service.script.ScriptServer;
import io.jpom.service.system.WorkspaceService;
import io.jpom.service.user.TriggerTokenLogServer;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
@ -52,10 +54,8 @@ import top.jpom.model.PageResultDto;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author bwcx_jzy
@ -70,15 +70,18 @@ public class ScriptController extends BaseServerController {
private final NodeScriptServer nodeScriptServer;
private final ScriptExecuteLogServer scriptExecuteLogServer;
private final TriggerTokenLogServer triggerTokenLogServer;
private final WorkspaceService workspaceService;
public ScriptController(ScriptServer scriptServer,
NodeScriptServer nodeScriptServer,
ScriptExecuteLogServer scriptExecuteLogServer,
TriggerTokenLogServer triggerTokenLogServer) {
TriggerTokenLogServer triggerTokenLogServer,
WorkspaceService workspaceService) {
this.scriptServer = scriptServer;
this.nodeScriptServer = nodeScriptServer;
this.scriptExecuteLogServer = scriptExecuteLogServer;
this.triggerTokenLogServer = triggerTokenLogServer;
this.workspaceService = workspaceService;
}
/**
@ -100,8 +103,8 @@ public class ScriptController extends BaseServerController {
*/
@GetMapping(value = "list-all", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public JsonMessage<List<ScriptModel>> scriptListAll() {
List<ScriptModel> pageResultDto = scriptServer.listByWorkspace(getRequest());
public JsonMessage<List<ScriptModel>> scriptListAll(HttpServletRequest request) {
List<ScriptModel> pageResultDto = scriptServer.listByWorkspace(request);
return JsonMessage.success("success", pageResultDto);
}
@ -142,8 +145,8 @@ public class ScriptController extends BaseServerController {
}
private void syncDelNodeScript(ScriptModel scriptModel, Collection<String> delNode) {
for (String s : delNode) {
NodeModel byKey = nodeService.getByKey(s, getRequest());
for (String nodeId : delNode) {
NodeModel byKey = nodeService.getByKey(nodeId);
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", scriptModel.getId());
JsonMessage<String> request = NodeForward.request(byKey, NodeUrl.Script_Del, jsonObject);
@ -160,7 +163,7 @@ public class ScriptController extends BaseServerController {
this.syncDelNodeScript(scriptModel, delNode);
// 更新
for (String newNodeId : newNodeIds) {
NodeModel byKey = nodeService.getByKey(newNodeId, request);
NodeModel byKey = nodeService.getByKey(newNodeId);
Assert.notNull(byKey, "没有找到对应的节点");
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", scriptModel.getId());
@ -170,7 +173,7 @@ public class ScriptController extends BaseServerController {
jsonObject.put("defArgs", scriptModel.getDefArgs());
jsonObject.put("description", scriptModel.getDescription());
jsonObject.put("name", scriptModel.getName());
jsonObject.put("workspaceId", scriptModel.getWorkspaceId());
jsonObject.put("workspaceId", byKey.getWorkspaceId());
jsonObject.put("global", scriptModel.global());
jsonObject.put("nodeId", byKey.getId());
JsonMessage<String> jsonMessage = NodeForward.request(byKey, NodeUrl.Script_Save, jsonObject);
@ -198,6 +201,42 @@ public class ScriptController extends BaseServerController {
return JsonMessage.success("删除成功");
}
@GetMapping(value = "get", produces = MediaType.APPLICATION_JSON_VALUE)
@Feature(method = MethodFeature.LIST)
public JsonMessage<JSONObject> get(String id, HttpServletRequest request) {
String workspaceId = scriptServer.getCheckUserWorkspace(request);
ScriptModel server = scriptServer.getByKeyAndGlobal(id, request);
Assert.notNull(server, "没有对应的脚本");
String nodeIds = server.getNodeIds();
List<String> newNodeIds = StrUtil.splitTrim(nodeIds, StrUtil.COMMA);
List<JSONObject> nodeList = newNodeIds.stream()
.map(s -> {
JSONObject jsonObject = new JSONObject();
NodeModel nodeModel = nodeService.getByKey(s);
if (nodeModel == null) {
jsonObject.put("nodeName", "未知(数据丢失)");
} else {
jsonObject.put("nodeName", nodeModel.getName());
jsonObject.put("nodeId", nodeModel.getId());
jsonObject.put("workspaceId", nodeModel.getWorkspaceId());
WorkspaceModel workspaceModel = workspaceService.getByKey(nodeModel.getWorkspaceId());
jsonObject.put("workspaceName", Optional.ofNullable(workspaceModel).map(WorkspaceModel::getName).orElse("未知(数据丢失)"));
}
return jsonObject;
})
.collect(Collectors.toList());
// 判断是否可以编辑节点
boolean prohibitSync = nodeList.stream().anyMatch(jsonObject -> {
String workspaceId11 = (String) jsonObject.get("workspaceId");
return !StrUtil.equals(workspaceId11, workspaceId);
});
JSONObject jsonObject = new JSONObject();
jsonObject.put("data", server);
jsonObject.put("nodeList", nodeList);
jsonObject.put("prohibitSync", prohibitSync);
return JsonMessage.success("", jsonObject);
}
/**
* 释放脚本关联的节点
*

View File

@ -37,49 +37,57 @@ import org.springframework.util.Assert;
@Data
public abstract class BaseNodeModel extends BaseWorkspaceModel {
/**
* 节点Id
*
* @see io.jpom.model.data.NodeModel
*/
private String nodeId;
/**
* 节点Id
*
* @see io.jpom.model.data.NodeModel
*/
private String nodeId;
/**
* 节点名称
*/
private String nodeName;
/**
* 工作空间名称
*/
private String workspaceName;
@Override
public String toString() {
return super.toString();
}
@Override
public String toString() {
return super.toString();
}
public String fullId() {
String workspaceId = this.getWorkspaceId();
public String fullId() {
String workspaceId = this.getWorkspaceId();
String nodeId = this.getNodeId();
String nodeId = this.getNodeId();
String dataId = this.dataId();
String dataId = this.dataId();
return BaseNodeModel.fullId(workspaceId, nodeId, dataId);
}
return BaseNodeModel.fullId(workspaceId, nodeId, dataId);
}
public static String fullId(String workspaceId, String nodeId, String dataId) {
public static String fullId(String workspaceId, String nodeId, String dataId) {
Assert.hasText(workspaceId, "workspaceId");
Assert.hasText(workspaceId, "workspaceId");
Assert.hasText(workspaceId, "nodeId");
Assert.hasText(workspaceId, "nodeId");
Assert.hasText(workspaceId, "dataId");
return SecureUtil.sha1(workspaceId + nodeId + dataId);
}
Assert.hasText(workspaceId, "dataId");
return SecureUtil.sha1(workspaceId + nodeId + dataId);
}
/**
* 获取数据ID
*
* @return 数据ID
*/
public abstract String dataId();
/**
* 获取数据ID
*
* @return 数据ID
*/
public abstract String dataId();
/**
* 设置数据ID
*
* @param id 数据ID
*/
public abstract void dataId(String id);
/**
* 设置数据ID
*
* @param id 数据ID
*/
public abstract void dataId(String id);
}

View File

@ -84,7 +84,7 @@ public abstract class BaseNodeService<T extends BaseNodeModel> extends BaseGloba
Assert.notNull(nodeModel, "不存在对应的节点");
Assert.state(StrUtil.equals(workspaceId, nodeModel.getWorkspaceId()), "节点的工作空间和操作的工作空间补一致");
paramMap.remove("workspaceId");
paramMap.remove("nodeId");
paramMap.put("nodeId", nodeId);
paramMap.put("workspaceId:in", workspaceId + StrUtil.COMMA + ServerConst.WORKSPACE_GLOBAL);
return super.listPage(paramMap);
@ -180,6 +180,9 @@ public abstract class BaseNodeService<T extends BaseNodeModel> extends BaseGloba
return StrUtil.equals(nodeModel.getWorkspaceId(), item.getWorkspaceId());
})
.peek(item -> {
item.setNodeName(nodeModel.getName());
WorkspaceModel workspaceModel = workspaceService.getByKey(nodeModel.getWorkspaceId());
item.setWorkspaceName(Optional.ofNullable(workspaceModel).map(WorkspaceModel::getName).orElse("数据不存在"));
cacheIds.remove(item.dataId());
// 需要删除相反的工作空间的数据避免出现一个脚本同步出2条数据的问题
if (StrUtil.equals(item.getWorkspaceId(), ServerConst.WORKSPACE_GLOBAL)) {

View File

@ -49,3 +49,9 @@ ADD,SERVER_SCRIPT_INFO,createUser,String,50,,创建人,false
ADD,BUILD_INFO,statusMsg,TEXT,,,状态信息
ADD,BUILDHISTORYLOG,statusMsg,TEXT,,,状态信息
ADD,SCRIPT_INFO,createUser,String,50,,创建人,false
ADD,SCRIPT_INFO,nodeName,String,50,,节点名称,false
ADD,PROJECT_INFO,nodeName,String,50,,节点名称,false
ADD,SCRIPT_EXECUTE_LOG,nodeName,String,50,,节点名称,false
ADD,SCRIPT_INFO,workspaceName,String,50,,工作空间名称,false
ADD,PROJECT_INFO,workspaceName,String,50,,工作空间名称,false
ADD,SCRIPT_EXECUTE_LOG,workspaceName,String,50,,工作空间名称,false

1 alterType,tableName,name,type,len,defaultValue,comment,notNull
49 ADD,BUILD_INFO,statusMsg,TEXT,,,状态信息
50 ADD,BUILDHISTORYLOG,statusMsg,TEXT,,,状态信息
51 ADD,SCRIPT_INFO,createUser,String,50,,创建人,false
52 ADD,SCRIPT_INFO,nodeName,String,50,,节点名称,false
53 ADD,PROJECT_INFO,nodeName,String,50,,节点名称,false
54 ADD,SCRIPT_EXECUTE_LOG,nodeName,String,50,,节点名称,false
55 ADD,SCRIPT_INFO,workspaceName,String,50,,工作空间名称,false
56 ADD,PROJECT_INFO,workspaceName,String,50,,工作空间名称,false
57 ADD,SCRIPT_EXECUTE_LOG,workspaceName,String,50,,工作空间名称,false

View File

@ -11,17 +11,6 @@ export function getScriptList(params) {
});
}
/**
* script 服务端中的所有列表
*/
export function getScriptListAll(params) {
return axios({
url: "/script/list-all",
method: "get",
params: params,
});
}
/**
* 保存脚本
* @param {Json} params
@ -101,6 +90,14 @@ export function syncToWorkspace(params) {
});
}
export function getScriptItem(params) {
return axios({
url: "/script/get",
method: "get",
params: params,
});
}
/**
* 获取触发器地址
* @param {*} id

View File

@ -835,7 +835,7 @@ import { getBuildGroupAll, editBuild, getBranchList, buildModeMap, releaseMethod
import { getSshListAll } from "@/api/ssh";
import { getRepositoryInfo } from "@/api/repository";
import { getNodeListAll, getProjectListAll } from "@/api/node";
import { getScriptListAll } from "@/api/server-script";
// import { getScriptListAll } from "@/api/server-script";
import { getDishPatchListAll } from "@/api/dispatch";
import { itemGroupBy, CRON_DATA_SOURCE, randomStr } from "@/utils/const";
import { mapGetters } from "vuex";
@ -930,7 +930,7 @@ export default {
dockerSwarmList: [],
//
swarmServiceListOptions: [],
scriptList: [],
// scriptList: [],
groupList: [],
temp: {},
rules: {
@ -1046,7 +1046,7 @@ export default {
this.loadNodeProjectList();
this.loadSshList();
this.loadDockerSwarmListAll();
this.loadScriptListList();
// this.loadScriptListList();
this.tempExtraData = {
cacheBuild: true,
@ -1092,7 +1092,7 @@ export default {
this.loadDispatchList();
this.loadDockerSwarmListAll();
this.loadNodeProjectList();
this.loadScriptListList();
// this.loadScriptListList();
this.loadSshList().then(() => {
if (this.tempExtraData.releaseMethodDataId_3) {
//
@ -1108,14 +1108,14 @@ export default {
}
});
},
//
loadScriptListList() {
getScriptListAll().then((res) => {
if (res.code === 200) {
this.scriptList = res.data;
}
});
},
// //
// loadScriptListList() {
// getScriptListAll().then((res) => {
// if (res.code === 200) {
// this.scriptList = res.data;
// }
// });
// },
//
loadDispatchList() {
this.dispatchList = [];

View File

@ -36,9 +36,7 @@
<a-tooltip slot="tooltip" slot-scope="text" placement="topLeft" :title="text">
<span>{{ text }}</span>
</a-tooltip>
<a-tooltip slot="nodeId" slot-scope="text" placement="topLeft" :title="`${nodeMap[text]} 节点ID ${text}`">
<span>{{ nodeMap[text] }}</span>
</a-tooltip>
<a-tooltip slot="name" @click="handleEdit(record)" slot-scope="text, record" placement="topLeft" :title="text">
<!-- <span>{{ text }}</span> -->
<a-button type="link" style="padding: 0px" size="small">{{ text }}</a-button>
@ -252,7 +250,8 @@ export default {
columns: [
{ title: "scriptId", dataIndex: "scriptId", ellipsis: true, width: 150, scopedSlots: { customRender: "tooltip" } },
{ title: "名称", dataIndex: "name", ellipsis: true, width: 200, scopedSlots: { customRender: "name" } },
{ title: "节点名称", dataIndex: "nodeId", ellipsis: true, width: 150, scopedSlots: { customRender: "nodeId" } },
{ title: "节点名称", dataIndex: "nodeName", ellipsis: true, width: 150, scopedSlots: { customRender: "tooltip" } },
{ title: "工作空间名称", dataIndex: "workspaceName", ellipsis: true, width: 150, scopedSlots: { customRender: "tooltip" } },
{ title: "类型", dataIndex: "scriptType", width: 70, align: "center", ellipsis: true, scopedSlots: { customRender: "scriptType" } },
{ title: "共享", dataIndex: "workspaceId", ellipsis: true, scopedSlots: { customRender: "global" }, width: "90px" },
{ title: "定时执行", dataIndex: "autoExecCron", ellipsis: true, width: 120, scopedSlots: { customRender: "autoExecCron" } },

View File

@ -129,7 +129,10 @@
<a-radio :value="false"> 当前工作空间</a-radio>
</a-radio-group>
</a-form-model-item>
<a-form-model-item>
<a-form-model-item v-if="temp.prohibitSync" label="禁用分发节点">
<a-tag v-for="(item, index) in temp.nodeList" :key="index">节点名称{{ item.nodeName }} 工作空间{{ item.workspaceName }}</a-tag>
</a-form-model-item>
<a-form-model-item v-else>
<template slot="label">
分发节点
<a-tooltip v-show="!temp.id">
@ -279,7 +282,7 @@
</div>
</template>
<script>
import { deleteScript, editScript, getScriptList, syncToWorkspace, unbindScript, getTriggerUrl } from "@/api/server-script";
import { deleteScript, editScript, getScriptList, syncToWorkspace, unbindScript, getTriggerUrl, getScriptItem } from "@/api/server-script";
import codeEditor from "@/components/codeEditor";
import { getNodeListAll } from "@/api/node";
import ScriptConsole from "@/pages/script/script-console";
@ -316,7 +319,7 @@ export default {
columns: [
{ title: "id", dataIndex: "id", ellipsis: true, width: 150, scopedSlots: { customRender: "tooltip" } },
{ title: "名称", dataIndex: "name", ellipsis: true, width: 150, scopedSlots: { customRender: "tooltip" } },
{ title: "共享", dataIndex: "workspaceId", ellipsis: true, scopedSlots: { customRender: "global" }, width: "80px" },
{ title: "共享", dataIndex: "workspaceId", ellipsis: true, scopedSlots: { customRender: "global" }, width: "90px" },
{ title: "描述", dataIndex: "description", ellipsis: true, width: 300, scopedSlots: { customRender: "tooltip" } },
{ title: "定时执行", dataIndex: "autoExecCron", ellipsis: true, width: "100px", scopedSlots: { customRender: "tooltip" } },
{
@ -406,13 +409,27 @@ export default {
},
//
handleEdit(record) {
this.temp = Object.assign({}, record);
getScriptItem({
id: record.id,
}).then((res) => {
if (res.code === 200) {
const data = res.data.data;
this.temp = Object.assign({}, data);
this.commandParams = record.defArgs ? JSON.parse(record.defArgs) : [];
this.commandParams = data?.defArgs ? JSON.parse(data.defArgs) : [];
this.temp = { ...this.temp, chooseNode: record.nodeIds ? record.nodeIds.split(",") : [], global: record.workspaceId === "GLOBAL", workspaceId: "" };
this.editScriptVisible = true;
this.getAllNodeList();
this.temp = {
...this.temp,
prohibitSync: res.data.prohibitSync,
nodeList: res.data.nodeList,
chooseNode: data?.nodeIds ? data.nodeIds.split(",") : [],
global: data.workspaceId === "GLOBAL",
workspaceId: "",
};
this.editScriptVisible = true;
this.getAllNodeList();
}
});
},
// Script
handleEditScriptOk() {
@ -436,6 +453,7 @@ export default {
}
//
this.temp.nodeIds = this.temp?.chooseNode?.join(",");
delete this.temp.nodeList;
editScript(this.temp).then((res) => {
if (res.code === 200) {
//