diff --git a/.gitee/ISSUE_TEMPLATE.zh-CN.md b/.gitee/ISSUE_TEMPLATE.zh-CN.md new file mode 100644 index 000000000..1637a6f7b --- /dev/null +++ b/.gitee/ISSUE_TEMPLATE.zh-CN.md @@ -0,0 +1,5 @@ +### 使用的JDK版本、Jpom版本、操作系统及系统版本 + +### 问题描述(包括截图) + +### 报错信息 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e9e289592..0ed9c6d7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,12 @@ ### 新增功能 +1. 新增线程列表监控(感谢@其锋) +2. 新增节点脚本模板(感谢@其锋) + ### 解决BUG、优化功能 - 1. 【Server】节点首页,右上角管理路径错误(感谢@其锋) +1. 【Server】节点首页,右上角管理路径错误(感谢@其锋) ----------------------------------------------------------- diff --git a/FQA.md b/FQA.md index 728c000af..297875939 100644 --- a/FQA.md +++ b/FQA.md @@ -82,6 +82,8 @@ https://github.com/alibaba/arthas/issues/347 + https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4770092 + ### windows 环境项目在运行中不能删除文件 > 由于系统原因,暂时还没有找到解决办法 \ No newline at end of file diff --git a/PLANS.md b/PLANS.md index 2564fd733..d35124fee 100644 --- a/PLANS.md +++ b/PLANS.md @@ -7,4 +7,4 @@ ### 待优化解决 1. 支持更多压缩包 - 2. 项目监控完善 \ No newline at end of file + 2. war包管理 \ No newline at end of file diff --git a/README.md b/README.md index ccfa20fa5..3018715ae 100644 --- a/README.md +++ b/README.md @@ -147,13 +147,15 @@ Agent.sh status 查看Jpom插件端运行状态 ### 常见问题、操作说明 -| 说明1 | 说明2 | +| 必看 | 选看 | | -- | -- | -| [安装文档>>](/doc/install.md) | [用户角色说明>>](/doc/userRole.md) | -| [常见问题>>](/FQA.md) | [阿里云Oss配置>>](/doc/CodePipeline-Oss.md) | -| [启动失败问题>>](/doc/startFail.md) | [更新日志>>](/CHANGELOG.md) | -| | [开发计划>>](/PLANS.md) | -| [项目属性说明>>](/doc/project.md) | [删除项目说明>>](/doc/deleteProject.md) | +| [安装文档>>](/doc/install.md) | [常见问题>>](/FQA.md) | +| [启动失败问题>>](/doc/startFail.md) | [阿里云Oss配置>>](/doc/CodePipeline-Oss.md)| +| [项目属性说明>>](/doc/project.md) | [删除项目说明>>](/doc/deleteProject.md) | +| [白名单规则>>](/doc/whitelist.md) | [Nginx管理规则>>](/doc/nginx-manager.md) | +| [用户角色说明>>](/doc/userRole.md) | [推荐Nginx配置>>](/doc/nginx-config.md) | +| [更新日志>>](/CHANGELOG.md) | [开发计划>>](/PLANS.md) | + ### 交流讨论 、提供bug反馈或建议 diff --git a/doc/install.md b/doc/install.md index fd8991964..5434631b7 100644 --- a/doc/install.md +++ b/doc/install.md @@ -27,6 +27,8 @@ 3. 默认密码为:随机生成的10个字符串 4. 自动生成的授权账号要写入文件中方便后期查看 5. 文件具体位置请注意控制台日志 + + 【注意请牢记插件端的授权账号,如果拥有授权端账号信息将可以越过Server用户权限操作节点数据】 7. 如果顺利启动那么Jpom的插件端(agent)算安装成功 ----------------------------------------------------------------------------------- diff --git a/doc/nginx-manager.md b/doc/nginx-manager.md new file mode 100644 index 000000000..6a22dcfb2 --- /dev/null +++ b/doc/nginx-manager.md @@ -0,0 +1,14 @@ +## Jpom 中对nginx 管理 + +> 为了方便运维日志简单的对项目上线,Jpom可以对nginx的配置进行管理 + +#### 管理规则如下 + +1. 系统根据配置的nginx白名单去扫描路径的*.conf 文件展示 +2. 提供给用户进行在线编辑、保存 +3. 保存后系统自动执行`nginx -s reload` +4. 只有节点管理员可以编辑保存nginx配置文件 + +#### 如果需要配置ssl 请配合Jpom 中的证书管理一起使用 + +## 为了系统安全只用系统管理员可以配置nginx的静态资源路径:【root、alias】 diff --git a/doc/whitelist.md b/doc/whitelist.md new file mode 100644 index 000000000..007551185 --- /dev/null +++ b/doc/whitelist.md @@ -0,0 +1,62 @@ +# Jpom 中的白名单说明 + +> Jpom 中的白名单的由来,由于项目管理都需要对项目的文件进行管理。在创建项目的时候需要确定项目的相关文件存放的路径。 +> 那么此时由用户决定存放到哪里,现在有点冒然。因为服务器中有些路径已经存放重要配置文件,此时项目路径相同那么必然没有任何安全性 + +##### 假设设置黑名单 + +> 如果设置黑名单那么没有办法最快速收集用户不同服务器中重要文件路径,此方法也显得不合适 + + +### 综上Jpom 就使用白名单来管理项目相关的文件 + +> 那么在Jpom 中有那些地方需要用到白名单呢 + +## 1. 项目路径 + +> 项目路径白名单主要是决定不同项目存放的位置,【但是项目路径选择的白名单不是项目文件存放的实际位置】 + +> 项目文件存放是实际路径是由【选择的项目路径白名单+项目Jar包】 组合而成的 + +``` +# 举例说明项目白名单如何使用 + +如果有4个项目需要部署到服务器中,但是4个项目又可以分为两大类型 + +项目1、项目2、项目3、项目4 + +可以分为:后台、接口 + +【后台】:项目1、项目3 + +【接口】:项目2、项目4 + +那么推荐配置白名单: + +/project/admin/ +/project/api/ + +那么在创建项目1、项目3的时候选择路径:/project/admin/ + +那么在创建项目2、项目4的时候选择路径:/project/api/ + +``` + +## 2. 证书路径 + +> 证书路径白名单是决定用户上次的ssl 证书存放的路径 + +> 证书文件实际存放的路径是由【选择的证书路径白名单+证书id+id.key(id.pem)】 组合而成的 + +## 3. Nginx路径 + +> Nginx路径白名单是决定Jpom 程序会自动扫描对应目录下的 *.conf 文件还展示配置文件 + +## 4. 节点分发 + +> 节点分发白名单是决定创建节点分发项目时候,项目的白名单路径(此处规则和项目路径白名单一致) + +> 单独管理节点分发白名单的目的是为了多节点的白名单信息同步 + + +# 注意:为了系统安全白名单只允许系统管理配置,在节点第一次使用时候为了系统能正常使用需要添加一个项目的白名单路径 \ No newline at end of file diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/common/BaseAgentController.java b/modules/agent/src/main/java/cn/keepbx/jpom/common/BaseAgentController.java index 49835f36d..d54537091 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/common/BaseAgentController.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/common/BaseAgentController.java @@ -3,6 +3,7 @@ package cn.keepbx.jpom.common; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.servlet.ServletUtil; +import cn.jiangzeyin.controller.base.AbstractController; import cn.keepbx.jpom.model.Role; import cn.keepbx.jpom.model.data.ProjectInfoModel; import cn.keepbx.jpom.service.manage.ProjectInfoService; @@ -32,12 +33,25 @@ public abstract class BaseAgentController extends BaseJpomController { * @param request req * @return name */ - public static String getUserName(HttpServletRequest request) { + private static String getUserName(HttpServletRequest request) { String name = ServletUtil.getHeaderIgnoreCase(request, ConfigBean.JPOM_SERVER_USER_NAME); name = CharsetUtil.convert(name, CharsetUtil.CHARSET_ISO_8859_1, CharsetUtil.CHARSET_UTF_8); return StrUtil.emptyToDefault(name, StrUtil.DASHED); } + /** + * 获取server 端操作人 + * + * @return name + */ + public static String getNowUserName() { + HttpServletRequest request = AbstractController.getRequestAttributes().getRequest(); + if (request == null) { + return StrUtil.DASHED; + } + return getUserName(request); + } + /** * 操作的人员是否为系统管理员 * diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/controller/IndexController.java b/modules/agent/src/main/java/cn/keepbx/jpom/controller/IndexController.java index 597e623d5..e8f6ddf83 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/controller/IndexController.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/controller/IndexController.java @@ -1,5 +1,6 @@ package cn.keepbx.jpom.controller; +import cn.hutool.system.SystemUtil; import cn.jiangzeyin.common.JsonMessage; import cn.keepbx.jpom.BaseJpomApplication; import cn.keepbx.jpom.common.BaseAgentController; @@ -61,6 +62,8 @@ public class IndexController extends BaseAgentController { jsonObject.put("javaVirtualCount", JvmUtil.getJavaVirtualCount()); jsonObject.put("osName", BaseJpomApplication.OS_INFO.getName()); jsonObject.put("jpomVersion", JpomManifest.getInstance().getVersion()); + jsonObject.put("javaVersion", SystemUtil.getJavaRuntimeInfo().getVersion()); + if (projectInfoModels == null) { jsonObject.put("count", 0); jsonObject.put("runCount", 0); diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/BuildController.java b/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/BuildController.java index 75755f04d..5715b5657 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/BuildController.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/BuildController.java @@ -9,7 +9,7 @@ import cn.keepbx.jpom.common.BaseAgentController; import cn.keepbx.jpom.model.data.ProjectInfoModel; import cn.keepbx.jpom.service.manage.ConsoleService; import cn.keepbx.jpom.service.oss.OssManagerService; -import cn.keepbx.jpom.socket.CommandOp; +import cn.keepbx.jpom.socket.ConsoleCommandOp; import com.alibaba.fastjson.JSONArray; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestMapping; @@ -79,7 +79,7 @@ public class BuildController extends BaseAgentController { // 修改使用状态 projectInfoModel.setUseLibDesc("build"); projectInfoService.updateItem(projectInfoModel); - String result = consoleService.execCommand(CommandOp.restart, projectInfoModel); + String result = consoleService.execCommand(ConsoleCommandOp.restart, projectInfoModel); return JsonMessage.getString(200, "安装成功,已自动重启,当前状态是:" + result); } } diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/EditProjectController.java b/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/EditProjectController.java index 84e0549f9..30d4249b9 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/EditProjectController.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/EditProjectController.java @@ -9,13 +9,13 @@ import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.StrUtil; import cn.jiangzeyin.common.DefaultSystemLog; import cn.jiangzeyin.common.JsonMessage; +import cn.keepbx.jpom.BaseJpomApplication; import cn.keepbx.jpom.common.BaseAgentController; import cn.keepbx.jpom.common.commander.AbstractProjectCommander; import cn.keepbx.jpom.model.Role; import cn.keepbx.jpom.model.RunMode; import cn.keepbx.jpom.model.data.ProjectInfoModel; import cn.keepbx.jpom.service.WhitelistDirectoryService; -import cn.keepbx.jpom.socket.CommonSocketConfig; import cn.keepbx.jpom.system.ConfigBean; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestMapping; @@ -55,8 +55,8 @@ public class EditProjectController extends BaseAgentController { if (!Validator.isGeneral(id, 2, 20)) { return JsonMessage.getString(401, "项目id 长度范围2-20(英文字母 、数字和下划线)"); } - if (CommonSocketConfig.SYSTEM_ID.equals(id)) { - return JsonMessage.getString(401, "项目id " + CommonSocketConfig.SYSTEM_ID + " 关键词被系统占用"); + if (BaseJpomApplication.SYSTEM_ID.equals(id)) { + return JsonMessage.getString(401, "项目id " + BaseJpomApplication.SYSTEM_ID + " 关键词被系统占用"); } // 防止和Jpom冲突 if (StrUtil.isNotEmpty(ConfigBean.getInstance().applicationTag) && ConfigBean.getInstance().applicationTag.equalsIgnoreCase(id)) { @@ -288,7 +288,11 @@ public class EditProjectController extends BaseAgentController { return null; } - + /** + * 删除项目 + * + * @return json + */ @RequestMapping(value = "deleteProject", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public String deleteProject() { ProjectInfoModel projectInfoModel = tryGetProjectInfoModel(); @@ -300,8 +304,7 @@ public class EditProjectController extends BaseAgentController { if (projectInfoModel.isStatus(true)) { return JsonMessage.getString(401, "不能删除正在运行的项目"); } - String userId = getUserName(); - projectInfoService.deleteProject(projectInfoModel, userId); + projectInfoService.deleteItem(projectInfoModel.getId()); return JsonMessage.getString(200, "删除成功!"); } catch (Exception e) { DefaultSystemLog.ERROR().error(e.getMessage(), e); @@ -309,6 +312,13 @@ public class EditProjectController extends BaseAgentController { } } + /** + * 检查项目lib 情况 + * + * @param id 项目id + * @param newLib 新路径 + * @return 状态码,400是一定不能操作的,401 是提醒 + */ @RequestMapping(value = "judge_lib.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public String saveProject(String id, String newLib) { File file = new File(newLib); diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/ProjectFileControl.java b/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/ProjectFileControl.java index 7d9ef6499..fd68d7c5a 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/ProjectFileControl.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/ProjectFileControl.java @@ -11,7 +11,7 @@ import cn.jiangzeyin.controller.multipart.MultipartFileBuilder; import cn.keepbx.jpom.common.BaseAgentController; import cn.keepbx.jpom.model.data.ProjectInfoModel; import cn.keepbx.jpom.service.manage.ConsoleService; -import cn.keepbx.jpom.socket.CommandOp; +import cn.keepbx.jpom.socket.ConsoleCommandOp; import cn.keepbx.jpom.system.AgentConfigBean; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; @@ -120,7 +120,7 @@ public class ProjectFileControl extends BaseAgentController { // String after = getParameter("after"); if ("restart".equalsIgnoreCase(after)) { - String result = consoleService.execCommand(CommandOp.restart, pim); + String result = consoleService.execCommand(ConsoleCommandOp.restart, pim); return JsonMessage.getString(200, "上传成功并重启:" + result); } diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/ProjectListController.java b/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/ProjectListController.java index 1fc31529b..2b64b7bc2 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/ProjectListController.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/controller/manage/ProjectListController.java @@ -120,7 +120,7 @@ public class ProjectListController extends BaseAgentController { * @return obj */ @RequestMapping(value = "getProjectPort", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) - public String getProjectGroup(String ids) { + public String getProjectPort(String ids) { if (StrUtil.isEmpty(ids)) { return JsonMessage.getString(400, ""); } @@ -147,15 +147,4 @@ public class ProjectListController extends BaseAgentController { } return JsonMessage.getString(200, "", jsonObject); } - -// /** -// * 获取运行方式 -// * -// * @return array -// */ -// @RequestMapping(value = "getRunModes", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) -// public String getRunModes() { -// ProjectInfoModel.RunMode[] runModes = ProjectInfoModel.RunMode.values(); -// return JsonMessage.getString(200, "", runModes); -// } } diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/controller/script/ScriptController.java b/modules/agent/src/main/java/cn/keepbx/jpom/controller/script/ScriptController.java new file mode 100644 index 000000000..952697ca8 --- /dev/null +++ b/modules/agent/src/main/java/cn/keepbx/jpom/controller/script/ScriptController.java @@ -0,0 +1,113 @@ +package cn.keepbx.jpom.controller.script; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import cn.jiangzeyin.common.JsonMessage; +import cn.jiangzeyin.controller.multipart.MultipartFileBuilder; +import cn.keepbx.jpom.common.BaseAgentController; +import cn.keepbx.jpom.model.data.ScriptModel; +import cn.keepbx.jpom.service.script.ScriptServer; +import cn.keepbx.jpom.system.AgentConfigBean; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.io.File; +import java.io.IOException; + +/** + * 脚本管理 + * + * @author jiangzeyin + * @date 2019/4/24 + */ +@RestController +@RequestMapping(value = "/script") +public class ScriptController extends BaseAgentController { + @Resource + private ScriptServer scriptServer; + + @RequestMapping(value = "list.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public String list() throws IOException { + return JsonMessage.getString(200, "", scriptServer.list()); + } + + @RequestMapping(value = "item.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public String item(String id) throws IOException { + return JsonMessage.getString(200, "", scriptServer.getItem(id)); + } + + @RequestMapping(value = "save.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public String save(ScriptModel scriptModel, String type) throws IOException { + if (scriptModel == null) { + return JsonMessage.getString(405, "没有数据"); + } + boolean safe = checkPathSafe(scriptModel.getId()); + if (!safe) { + return JsonMessage.getString(405, "id规则不合法"); + } + if (StrUtil.isEmpty(scriptModel.getContext())) { + return JsonMessage.getString(405, "内容为空"); + } + ScriptModel eModel = scriptServer.getItem(scriptModel.getId()); + if ("add".equalsIgnoreCase(type)) { + if (eModel != null) { + return JsonMessage.getString(405, "id已经存在啦"); + } + File file = scriptModel.getFile(true); + if (file.exists() || file.isDirectory()) { + return JsonMessage.getString(405, "当地id路径文件已经存在来,请修改"); + } + scriptServer.addItem(scriptModel); + return JsonMessage.getString(200, "添加成功"); + } + if (eModel == null) { + return JsonMessage.getString(405, "对应数据不存在"); + } + eModel.setName(scriptModel.getName()); + eModel.setContext(scriptModel.getContext()); + boolean b = scriptServer.updateItem(eModel); + if (b) { + return JsonMessage.getString(200, "修改成功"); + } + return JsonMessage.getString(500, "修改失败"); + } + + @RequestMapping(value = "del.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public String del(String id) throws IOException { + scriptServer.deleteItem(id); + return JsonMessage.getString(200, "删除成功"); + } + + @RequestMapping(value = "upload.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public String upload() throws IOException { + MultipartFileBuilder multipartFileBuilder = createMultipart() + .addFieldName("file").setFileExt("bat", "sh"); + multipartFileBuilder.setSavePath(AgentConfigBean.getInstance().getTempPathName()); + multipartFileBuilder.setUseOriginalFilename(true); + String path = multipartFileBuilder.save(); + File file = FileUtil.file(path); + String context = FileUtil.readString(path, CharsetUtil.CHARSET_UTF_8); + if (StrUtil.isEmpty(context)) { + return JsonMessage.getString(405, "脚本内容为空"); + } + String id = file.getName(); + ScriptModel eModel = scriptServer.getItem(id); + if (eModel != null) { + return JsonMessage.getString(405, "对应脚本模板已经存在啦"); + } + eModel = new ScriptModel(); + eModel.setId(id); + eModel.setName(id); + eModel.setContext(context); + file = eModel.getFile(true); + if (file.exists() || file.isDirectory()) { + return JsonMessage.getString(405, "当地id路径文件已经存在来,请修改"); + } + scriptServer.addItem(eModel); + return JsonMessage.getString(200, "导入成功"); + } +} diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/controller/system/CertificateController.java b/modules/agent/src/main/java/cn/keepbx/jpom/controller/system/CertificateController.java index 19b831cf2..e3da3f677 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/controller/system/CertificateController.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/controller/system/CertificateController.java @@ -145,6 +145,7 @@ public class CertificateController extends BaseAgentController { String filePathItem = String.format("%s/%s/%s", path, certModel.getId(), keyName); InputStream inputStream = zipFile.getInputStream(zipEntry); FileUtil.writeFromStream(inputStream, filePathItem); + certModel.setType(CertModel.Type.pem); pemPath = filePathItem; } // cer 文件 @@ -152,6 +153,7 @@ public class CertificateController extends BaseAgentController { String filePathItem = String.format("%s/%s/%s", path, certModel.getId(), keyName); InputStream inputStream = zipFile.getInputStream(zipEntry); FileUtil.writeFromStream(inputStream, filePathItem); + certModel.setType(CertModel.Type.cer); pemPath = filePathItem; } // @@ -204,7 +206,7 @@ public class CertificateController extends BaseAgentController { } // 移动位置 String temporary = certModel.getWhitePath() + "/" + certModel.getId() + "/"; - File pemFile = FileUtil.file(temporary + certModel.getId() + ".pem"); + File pemFile = FileUtil.file(temporary + certModel.getId() + "." + certModel.getType().name()); File keyFile = FileUtil.file(temporary + certModel.getId() + ".key"); if (add) { if (pemFile.exists()) { @@ -256,10 +258,7 @@ public class CertificateController extends BaseAgentController { if (!isSystemUser()) { return JsonMessage.getString(400, "你没有操作权限"); } - boolean b = certService.delete(id); - if (!b) { - return JsonMessage.getString(400, "删除失败"); - } + certService.deleteItem(id); return JsonMessage.getString(200, "删除成功"); } diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/model/data/CertModel.java b/modules/agent/src/main/java/cn/keepbx/jpom/model/data/CertModel.java index 675d1e3f5..fe8242314 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/model/data/CertModel.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/model/data/CertModel.java @@ -53,7 +53,15 @@ public class CertModel extends BaseModel { * 白名单路径 */ private String whitePath; + private Type type; + public Type getType() { + return type; + } + + public void setType(Type type) { + this.type = type; + } public String getWhitePath() { return whitePath; @@ -181,4 +189,12 @@ public class CertModel extends BaseModel { } return null; } + + public enum Type { + /** + * + */ + pem, + cer + } } diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/model/data/ProjectInfoModel.java b/modules/agent/src/main/java/cn/keepbx/jpom/model/data/ProjectInfoModel.java index 5a69e912b..734767c78 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/model/data/ProjectInfoModel.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/model/data/ProjectInfoModel.java @@ -89,13 +89,10 @@ public class ProjectInfoModel extends BaseModel { /** * 项目是否正在运行 * - * @param get 防止并发获取 + * @param get 防止自动获取 * @return true 正在运行 */ public boolean isStatus(boolean get) { - if (!get) { - return false; - } try { status = AbstractProjectCommander.getInstance().isRun(getId()); } catch (Exception e) { diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/model/data/ScriptModel.java b/modules/agent/src/main/java/cn/keepbx/jpom/model/data/ScriptModel.java new file mode 100644 index 000000000..8eb98540c --- /dev/null +++ b/modules/agent/src/main/java/cn/keepbx/jpom/model/data/ScriptModel.java @@ -0,0 +1,123 @@ +package cn.keepbx.jpom.model.data; + +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.StrUtil; +import cn.keepbx.jpom.BaseJpomApplication; +import cn.keepbx.jpom.model.BaseModel; +import cn.keepbx.jpom.system.AgentConfigBean; +import cn.keepbx.jpom.util.CommandUtil; + +import java.io.File; + +/** + * 脚本模板 + * + * @author jiangzeyin + * @date 2019/4/24 + */ +public class ScriptModel extends BaseModel { + /** + * 文件后缀 + */ + private static final String SUFFIX; + + static { + if (BaseJpomApplication.OS_INFO.isWindows()) { + SUFFIX = "bat"; + } else { + SUFFIX = "sh"; + } + } + + /** + * 最后执行人员 + */ + private String lastRunUser; + /** + * 最后修改时间 + */ + private String modifyTime; + /** + * 脚本内容 + */ + private String context; + + public String getLastRunUser() { + return StrUtil.emptyToDefault(lastRunUser, StrUtil.DASHED); + } + + public void setLastRunUser(String lastRunUser) { + this.lastRunUser = lastRunUser; + } + + public String getModifyTime() { + return modifyTime; + } + + public void setModifyTime(String modifyTime) { + this.modifyTime = modifyTime; + } + + public String getContext() { + return context; + } + + public void setContext(String context) { + this.context = context; + } + + public File getFile(boolean get) { + if (StrUtil.isEmpty(getId())) { + throw new IllegalArgumentException("id 为空"); + } + File path = AgentConfigBean.getInstance().getScriptPath(); + return FileUtil.file(path, getId(), "script." + SUFFIX); + } + + public File getLogFile(boolean get) { + if (StrUtil.isEmpty(getId())) { + throw new IllegalArgumentException("id 为空"); + } + File path = AgentConfigBean.getInstance().getScriptPath(); + File logFile; + int count = 0; + do { + String now = DateTime.now().toString(DatePattern.PURE_DATETIME_PATTERN); + logFile = FileUtil.file(path, getId(), "log", now + count + ".log"); + count++; + } while (FileUtil.exist(logFile)); + return logFile; + } + + public void saveFile() { + File file = getFile(true); + FileUtil.writeString(getContext(), file, CharsetUtil.CHARSET_UTF_8); + // 添加权限 + if (BaseJpomApplication.OS_INFO.isLinux()) { + CommandUtil.execCommand("chmod 755 " + FileUtil.getAbsolutePath(file)); + } + } + + /** + * 读取文件信息 + */ + public void readFileTime() { + File file = getFile(true); + long lastModified = file.lastModified(); + setModifyTime(DateUtil.date(lastModified).toString()); + + } + + public void readFileContext() { + File file = getFile(true); + if (FileUtil.exist(file)) { + // + String context = FileUtil.readString(file, CharsetUtil.CHARSET_UTF_8); + setContext(context); + } + } +} diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/ConsoleService.java b/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/ConsoleService.java index aee8ae95b..fb24611b9 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/ConsoleService.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/ConsoleService.java @@ -2,7 +2,7 @@ package cn.keepbx.jpom.service.manage; import cn.keepbx.jpom.common.commander.AbstractProjectCommander; import cn.keepbx.jpom.model.data.ProjectInfoModel; -import cn.keepbx.jpom.socket.CommandOp; +import cn.keepbx.jpom.socket.ConsoleCommandOp; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -21,14 +21,14 @@ public class ConsoleService { /** * 执行shell命令 * - * @param commandOp 执行的操作 + * @param consoleCommandOp 执行的操作 * @param projectInfoModel 项目信息 */ - public String execCommand(CommandOp commandOp, ProjectInfoModel projectInfoModel) throws Exception { + public String execCommand(ConsoleCommandOp consoleCommandOp, ProjectInfoModel projectInfoModel) throws Exception { String result; AbstractProjectCommander abstractProjectCommander = AbstractProjectCommander.getInstance(); // 执行命令 - switch (commandOp) { + switch (consoleCommandOp) { case restart: result = abstractProjectCommander.restart(projectInfoModel); break; @@ -46,10 +46,10 @@ public class ConsoleService { case top: case showlog: default: - throw new IllegalArgumentException(commandOp + " error"); + throw new IllegalArgumentException(consoleCommandOp + " error"); } // 通知日志刷新 - if (commandOp == CommandOp.start || commandOp == CommandOp.restart) { + if (consoleCommandOp == ConsoleCommandOp.start || consoleCommandOp == ConsoleCommandOp.restart) { // 修改 run lib 使用情况 ProjectInfoModel modify = projectInfoService.getItem(projectInfoModel.getId()); modify.setRunLibDesc(projectInfoModel.getUseLibDesc()); diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/ProjectInfoService.java b/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/ProjectInfoService.java index d13fc459e..ebeea9e50 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/ProjectInfoService.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/ProjectInfoService.java @@ -2,6 +2,7 @@ package cn.keepbx.jpom.service.manage; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; +import cn.keepbx.jpom.common.BaseAgentController; import cn.keepbx.jpom.common.BaseOperService; import cn.keepbx.jpom.model.data.ProjectInfoModel; import cn.keepbx.jpom.model.data.ProjectRecoverModel; @@ -62,9 +63,12 @@ public class ProjectInfoService extends BaseOperService { /** * 删除项目 * - * @param projectInfo 项目 + * @param id 项目 */ - public void deleteProject(ProjectInfoModel projectInfo, String userId) throws Exception { + @Override + public void deleteItem(String id) { + ProjectInfoModel projectInfo = getItem(id); + String userId = BaseAgentController.getNowUserName(); deleteJson(AgentConfigBean.PROJECT, projectInfo.getId()); // 添加回收记录 ProjectRecoverModel projectRecoverModel = new ProjectRecoverModel(projectInfo); diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/ProjectRecoverService.java b/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/ProjectRecoverService.java index 6f5abdf1f..c5f33e571 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/ProjectRecoverService.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/ProjectRecoverService.java @@ -59,4 +59,9 @@ public class ProjectRecoverService extends BaseOperService public boolean updateItem(ProjectRecoverModel projectRecoverModel) throws Exception { return false; } + + @Override + public void deleteItem(String id) { + + } } diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/package-info.java b/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/package-info.java new file mode 100644 index 000000000..cffd75970 --- /dev/null +++ b/modules/agent/src/main/java/cn/keepbx/jpom/service/manage/package-info.java @@ -0,0 +1,28 @@ +/** + * 节点项目管理 + *

+ * The MIT License(MIT) + *

+ * Copyright(c) 2019 码之科技工作室 + *

+ * Permission is hereby granted,free of charge,to any person obtaining a copy of + * this software and associated documentation files(the"Software"),to deal in + * the Software without restriction,including without limitation the rights to + * use,copy,modify,merge,publish,distribute,sublicense,and/or sell copies of + * the Software,and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + *

+ * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + *

+ * THE SOFTWARE IS PROVIDED"AS IS",WITHOUT WARRANTY OF ANY KIND,EXPRESS OR + * IMPLIED,INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER LIABILITY,WHETHER + * IN AN ACTION OF CONTRACT,TORT OR OTHERWISE,ARISING FROM,OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *

+ * + * @author jiangzeyin + */ +package cn.keepbx.jpom.service.manage; \ No newline at end of file diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/service/script/ScriptServer.java b/modules/agent/src/main/java/cn/keepbx/jpom/service/script/ScriptServer.java new file mode 100644 index 000000000..145f7db8d --- /dev/null +++ b/modules/agent/src/main/java/cn/keepbx/jpom/service/script/ScriptServer.java @@ -0,0 +1,75 @@ +package cn.keepbx.jpom.service.script; + +import cn.hutool.core.io.FileUtil; +import cn.jiangzeyin.common.DefaultSystemLog; +import cn.keepbx.jpom.common.BaseOperService; +import cn.keepbx.jpom.model.data.ScriptModel; +import cn.keepbx.jpom.system.AgentConfigBean; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.List; + +/** + * 脚本模板管理 + * + * @author jiangzeyin + * @date 2019/4/24 + */ +@Service +public class ScriptServer extends BaseOperService { + + @Override + public List list() throws IOException { + JSONObject jsonObject = getJSONObject(AgentConfigBean.SCRIPT); + if (jsonObject == null) { + return null; + } + JSONArray jsonArray = formatToArray(jsonObject); + List scriptModels = jsonArray.toJavaList(ScriptModel.class); + if (scriptModels == null) { + return null; + } + // 读取文件内容 + scriptModels.forEach(ScriptModel::readFileTime); + return scriptModels; + } + + @Override + public ScriptModel getItem(String id) { + ScriptModel scriptModel = getJsonObjectById(AgentConfigBean.SCRIPT, id, ScriptModel.class); + if (scriptModel != null) { + scriptModel.readFileContext(); + } + return scriptModel; + } + + @Override + public void addItem(ScriptModel scriptModel) { + saveJson(AgentConfigBean.SCRIPT, scriptModel.toJson()); + scriptModel.saveFile(); + } + + @Override + public boolean updateItem(ScriptModel scriptModel) { + try { + updateJson(AgentConfigBean.SCRIPT, scriptModel.toJson()); + scriptModel.saveFile(); + } catch (Exception e) { + DefaultSystemLog.ERROR().error(e.getMessage(), e); + return false; + } + return true; + } + + @Override + public void deleteItem(String id) { + ScriptModel scriptModel = getItem(id); + if (scriptModel != null) { + FileUtil.del(scriptModel.getFile(true).getParentFile()); + } + deleteJson(AgentConfigBean.SCRIPT, id); + } +} diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/service/system/CertService.java b/modules/agent/src/main/java/cn/keepbx/jpom/service/system/CertService.java index f054d9307..d02f13cfa 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/service/system/CertService.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/service/system/CertService.java @@ -56,24 +56,19 @@ public class CertService extends BaseOperService { * * @param id id */ - public boolean delete(String id) { - try { - CertModel certModel = getItem(id); - if (certModel == null) { - return true; - } - String keyPath = certModel.getCert(); - deleteJson(AgentConfigBean.CERT, id); - if (StrUtil.isNotEmpty(keyPath)) { - // 删除证书文件 - File parentFile = FileUtil.file(keyPath).getParentFile(); - FileUtil.del(parentFile); - } - } catch (Exception e) { - DefaultSystemLog.ERROR().error(e.getMessage(), e); - return false; + @Override + public void deleteItem(String id) { + CertModel certModel = getItem(id); + if (certModel == null) { + return; + } + String keyPath = certModel.getCert(); + deleteJson(AgentConfigBean.CERT, id); + if (StrUtil.isNotEmpty(keyPath)) { + // 删除证书文件 + File parentFile = FileUtil.file(keyPath).getParentFile(); + FileUtil.del(parentFile); } - return true; } /** diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/service/system/NginxService.java b/modules/agent/src/main/java/cn/keepbx/jpom/service/system/NginxService.java index ea62821f3..da29289ba 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/service/system/NginxService.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/service/system/NginxService.java @@ -105,6 +105,11 @@ public class NginxService extends BaseOperService { return false; } + @Override + public void deleteItem(String id) { + + } + /** * 获取域名 * diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/socket/AgentWebSocketConfig.java b/modules/agent/src/main/java/cn/keepbx/jpom/socket/AgentWebSocketConfig.java index feccf7645..9bf0c8d55 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/socket/AgentWebSocketConfig.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/socket/AgentWebSocketConfig.java @@ -5,6 +5,8 @@ import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; /** + * 插件端socket 配置 + * * @author jiangzeyin * @date 2019/4/19 */ diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/socket/AgentWebSocketHandle.java b/modules/agent/src/main/java/cn/keepbx/jpom/socket/AgentWebSocketConsoleHandle.java similarity index 77% rename from modules/agent/src/main/java/cn/keepbx/jpom/socket/AgentWebSocketHandle.java rename to modules/agent/src/main/java/cn/keepbx/jpom/socket/AgentWebSocketConsoleHandle.java index e5708155a..cf422f830 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/socket/AgentWebSocketHandle.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/socket/AgentWebSocketConsoleHandle.java @@ -1,11 +1,10 @@ package cn.keepbx.jpom.socket; import cn.hutool.core.exceptions.ExceptionUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.core.util.URLUtil; import cn.jiangzeyin.common.DefaultSystemLog; import cn.jiangzeyin.common.JsonMessage; import cn.jiangzeyin.common.spring.SpringUtil; +import cn.keepbx.jpom.BaseJpomApplication; import cn.keepbx.jpom.common.commander.AbstractProjectCommander; import cn.keepbx.jpom.model.data.ProjectInfoModel; import cn.keepbx.jpom.service.manage.ConsoleService; @@ -19,26 +18,25 @@ import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; -import java.util.concurrent.ConcurrentHashMap; /** - * 插件端socket + * 插件端,控制台socket * * @author jiangzeyin * @date 2019/4/16 */ @ServerEndpoint(value = "/console/{projectId}/{optUser}") @Component -public class AgentWebSocketHandle { +public class AgentWebSocketConsoleHandle extends BaseAgentWebSocketHandle { + - private static final ConcurrentHashMap USER = new ConcurrentHashMap<>(); private static ProjectInfoService projectInfoService; @OnOpen public void onOpen(@PathParam("projectId") String projectId, @PathParam("optUser") String urlOptUser, Session session) { try { // 判断项目 - if (!CommonSocketConfig.SYSTEM_ID.equals(projectId)) { + if (!BaseJpomApplication.SYSTEM_ID.equals(projectId)) { if (projectInfoService == null) { projectInfoService = SpringUtil.getBean(ProjectInfoService.class); } @@ -49,8 +47,7 @@ public class AgentWebSocketHandle { return; } } - String optUser = URLUtil.decode(urlOptUser); - USER.put(session.getId(), optUser); + this.addUser(session, urlOptUser); } catch (Exception e) { DefaultSystemLog.ERROR().error("socket 错误", e); try { @@ -62,16 +59,18 @@ public class AgentWebSocketHandle { } } - private String getOptUserName(Session session) { - String name = USER.get(session.getId()); - return StrUtil.emptyToDefault(name, StrUtil.DASHED); - } - - private boolean silentMsg(CommandOp commandOp, Session session) { - if (commandOp == CommandOp.heart) { + /** + * 静默消息不做过多处理 + * + * @param consoleCommandOp 操作 + * @param session 回话 + * @return true + */ + private boolean silentMsg(ConsoleCommandOp consoleCommandOp, Session session) { + if (consoleCommandOp == ConsoleCommandOp.heart) { return true; } - if (commandOp == CommandOp.top) { + if (consoleCommandOp == ConsoleCommandOp.top) { TopManager.addMonitor(session); return true; } @@ -82,32 +81,32 @@ public class AgentWebSocketHandle { public void onMessage(String message, Session session) throws Exception { JSONObject json = JSONObject.parseObject(message); String op = json.getString("op"); - CommandOp commandOp = CommandOp.valueOf(op); - if (silentMsg(commandOp, session)) { + ConsoleCommandOp consoleCommandOp = ConsoleCommandOp.valueOf(op); + if (silentMsg(consoleCommandOp, session)) { return; } String projectId = json.getString("projectId"); - projectInfoService = SpringUtil.getBean(ProjectInfoService.class); ProjectInfoModel projectInfoModel = projectInfoService.getItem(projectId); if (projectInfoModel == null) { SocketSessionUtil.send(session, "没有对应项目"); + session.close(); return; } - runMsg(commandOp, session, projectInfoModel, json); + runMsg(consoleCommandOp, session, projectInfoModel, json); } - private void runMsg(CommandOp commandOp, Session session, ProjectInfoModel projectInfoModel, JSONObject reqJson) throws Exception { + private void runMsg(ConsoleCommandOp consoleCommandOp, Session session, ProjectInfoModel projectInfoModel, JSONObject reqJson) throws Exception { ConsoleService consoleService = SpringUtil.getBean(ConsoleService.class); JSONObject resultData = null; String strResult; boolean logUser = false; try { // 执行相应命令 - switch (commandOp) { + switch (consoleCommandOp) { case start: case restart: logUser = true; - strResult = consoleService.execCommand(commandOp, projectInfoModel); + strResult = consoleService.execCommand(consoleCommandOp, projectInfoModel); if (strResult.contains(AbstractProjectCommander.RUNING_TAG)) { resultData = JsonMessage.toJson(200, "操作成功:" + strResult); } else { @@ -117,7 +116,7 @@ public class AgentWebSocketHandle { case stop: logUser = true; // 停止项目 - strResult = consoleService.execCommand(commandOp, projectInfoModel); + strResult = consoleService.execCommand(consoleCommandOp, projectInfoModel); if (strResult.contains(AbstractProjectCommander.STOP_TAG)) { resultData = JsonMessage.toJson(200, "操作成功"); } else { @@ -126,7 +125,7 @@ public class AgentWebSocketHandle { break; case status: // 获取项目状态 - strResult = consoleService.execCommand(commandOp, projectInfoModel); + strResult = consoleService.execCommand(consoleCommandOp, projectInfoModel); if (strResult.contains(AbstractProjectCommander.RUNING_TAG)) { resultData = JsonMessage.toJson(200, "运行中", strResult); } else { @@ -144,7 +143,7 @@ public class AgentWebSocketHandle { break; } default: - resultData = JsonMessage.toJson(404, "不支持的方式:" + commandOp.name()); + resultData = JsonMessage.toJson(404, "不支持的方式:" + consoleCommandOp.name()); break; } } catch (Exception e) { @@ -187,12 +186,8 @@ public class AgentWebSocketHandle { } @OnError + @Override public void onError(Session session, Throwable thr) { - // java.io.IOException: Broken pipe - try { - SocketSessionUtil.send(session, "服务端发生异常" + ExceptionUtil.stacktraceToString(thr)); - } catch (IOException ignored) { - } - DefaultSystemLog.ERROR().error(session.getId() + "socket 异常", thr); + super.onError(session, thr); } } diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/socket/AgentWebSocketScriptHandle.java b/modules/agent/src/main/java/cn/keepbx/jpom/socket/AgentWebSocketScriptHandle.java new file mode 100644 index 000000000..1b6371574 --- /dev/null +++ b/modules/agent/src/main/java/cn/keepbx/jpom/socket/AgentWebSocketScriptHandle.java @@ -0,0 +1,104 @@ +package cn.keepbx.jpom.socket; + +import cn.hutool.core.util.StrUtil; +import cn.jiangzeyin.common.DefaultSystemLog; +import cn.jiangzeyin.common.JsonMessage; +import cn.jiangzeyin.common.spring.SpringUtil; +import cn.keepbx.jpom.model.data.ScriptModel; +import cn.keepbx.jpom.service.script.ScriptServer; +import cn.keepbx.jpom.util.SocketSessionUtil; +import com.alibaba.fastjson.JSONObject; +import org.springframework.stereotype.Component; + +import javax.websocket.*; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; + +/** + * 脚本模板socket + * + * @author jiangzeyin + * @date 2019/4/24 + */ +@ServerEndpoint(value = "/script_run/{id}/{optUser}") +@Component +public class AgentWebSocketScriptHandle extends BaseAgentWebSocketHandle { + + private ScriptServer scriptServer; + + @OnOpen + public void onOpen(@PathParam("id") String id, Session session, @PathParam("optUser") String urlOptUser) { + if (scriptServer == null) { + scriptServer = SpringUtil.getBean(ScriptServer.class); + } + try { + if (StrUtil.isEmpty(id)) { + SocketSessionUtil.send(session, "脚本模板未知"); + return; + } + ScriptModel scriptModel = scriptServer.getItem(id); + if (scriptModel == null) { + SocketSessionUtil.send(session, "没有找到对应的脚本模板"); + return; + } + SocketSessionUtil.send(session, "连接成功:" + scriptModel.getName()); + this.addUser(session, urlOptUser); + } catch (Exception e) { + DefaultSystemLog.ERROR().error("socket 错误", e); + try { + SocketSessionUtil.send(session, JsonMessage.getString(500, "系统错误!")); + session.close(); + } catch (IOException e1) { + DefaultSystemLog.ERROR().error(e1.getMessage(), e1); + } + } + } + + @OnMessage + public void onMessage(String message, Session session) throws Exception { + JSONObject json = JSONObject.parseObject(message); + String scriptId = json.getString("scriptId"); + ScriptModel scriptModel = scriptServer.getItem(scriptId); + if (scriptModel == null) { + SocketSessionUtil.send(session, "没有对应脚本模板:" + scriptId); + session.close(); + return; + } + String op = json.getString("op"); + ConsoleCommandOp consoleCommandOp = ConsoleCommandOp.valueOf(op); + switch (consoleCommandOp) { + case start: + String args = json.getString("args"); + ScriptProcessBuilder.addWatcher(scriptModel, args, session); + break; + case stop: + ScriptProcessBuilder.stopRun(scriptModel); + break; + case heart: + default: + return; + } + // 记录操作人 + scriptModel = scriptServer.getItem(scriptId); + String name = getOptUserName(session); + scriptModel.setLastRunUser(name); + scriptServer.updateItem(scriptModel); + json.put("code", 200); + json.put("msg", "执行成功"); + DefaultSystemLog.LOG().info(json.toString()); + SocketSessionUtil.send(session, json.toString()); + } + + + @OnClose + public void onClose(Session session) { + ScriptProcessBuilder.stopWatcher(session); + } + + @OnError + @Override + public void onError(Session session, Throwable thr) { + super.onError(session, thr); + } +} diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/socket/BaseAgentWebSocketHandle.java b/modules/agent/src/main/java/cn/keepbx/jpom/socket/BaseAgentWebSocketHandle.java new file mode 100644 index 000000000..b10d73927 --- /dev/null +++ b/modules/agent/src/main/java/cn/keepbx/jpom/socket/BaseAgentWebSocketHandle.java @@ -0,0 +1,41 @@ +package cn.keepbx.jpom.socket; + +import cn.hutool.core.exceptions.ExceptionUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.URLUtil; +import cn.jiangzeyin.common.DefaultSystemLog; +import cn.keepbx.jpom.util.SocketSessionUtil; + +import javax.websocket.Session; +import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 插件端socket 基类 + * + * @author jiangzeyin + * @date 2019/4/24 + */ +public abstract class BaseAgentWebSocketHandle { + + protected static final ConcurrentHashMap USER = new ConcurrentHashMap<>(); + + public void addUser(Session session, String name) { + String optUser = URLUtil.decode(name); + USER.put(session.getId(), optUser); + } + + public void onError(Session session, Throwable thr) { + // java.io.IOException: Broken pipe + try { + SocketSessionUtil.send(session, "服务端发生异常" + ExceptionUtil.stacktraceToString(thr)); + } catch (IOException ignored) { + } + DefaultSystemLog.ERROR().error(session.getId() + "socket 异常", thr); + } + + protected String getOptUserName(Session session) { + String name = USER.get(session.getId()); + return StrUtil.emptyToDefault(name, StrUtil.DASHED); + } +} diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/socket/ScriptProcessBuilder.java b/modules/agent/src/main/java/cn/keepbx/jpom/socket/ScriptProcessBuilder.java new file mode 100644 index 000000000..a0bdedbd8 --- /dev/null +++ b/modules/agent/src/main/java/cn/keepbx/jpom/socket/ScriptProcessBuilder.java @@ -0,0 +1,164 @@ +package cn.keepbx.jpom.socket; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IORuntimeException; +import cn.hutool.core.io.IoUtil; +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.jiangzeyin.common.DefaultSystemLog; +import cn.jiangzeyin.common.JsonMessage; +import cn.keepbx.jpom.BaseJpomApplication; +import cn.keepbx.jpom.model.data.ScriptModel; +import cn.keepbx.jpom.util.SocketSessionUtil; +import com.alibaba.fastjson.JSONObject; + +import javax.websocket.Session; +import java.io.*; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 脚本执行 + * + * @author jiangzeyin + * @date 2019/4/25 + */ +public class ScriptProcessBuilder implements Runnable { + private static final ConcurrentHashMap FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP = new ConcurrentHashMap<>(); + + private ProcessBuilder processBuilder; + private Set sessions = new HashSet<>(); + private File logFile; + private File scriptFile; + private Process process; + private InputStream inputStream; + private InputStream errorInputStream; + + private ScriptProcessBuilder(ScriptModel scriptModel, String args) { + this.logFile = scriptModel.getLogFile(true); + this.scriptFile = scriptModel.getFile(true); + // + String script = FileUtil.getAbsolutePath(scriptFile); + processBuilder = new ProcessBuilder(); + List command = StrUtil.splitTrim(args, StrUtil.SPACE); + command.add(0, script); + DefaultSystemLog.LOG().info(CollUtil.join(command, StrUtil.SPACE)); + processBuilder.command(command); + } + + public static void addWatcher(ScriptModel scriptModel, String args, Session session) { + File file = scriptModel.getFile(true); + ScriptProcessBuilder scriptProcessBuilder = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.computeIfAbsent(file, file1 -> { + ScriptProcessBuilder scriptProcessBuilder1 = new ScriptProcessBuilder(scriptModel, args); + ThreadUtil.execute(scriptProcessBuilder1); + return scriptProcessBuilder1; + }); + 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.ERROR().error("发送消息失败", e); + } + }); + } + } + } + + public static void stopWatcher(Session session) { + Collection scriptProcessBuilders = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.values(); + for (ScriptProcessBuilder scriptProcessBuilder : scriptProcessBuilders) { + Set sessions = scriptProcessBuilder.sessions; + sessions.removeIf(session1 -> session1.getId().equals(session.getId())); + } + } + + public static void stopRun(ScriptModel scriptModel) { + File file = scriptModel.getFile(true); + ScriptProcessBuilder scriptProcessBuilder = FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.get(file); + if (scriptProcessBuilder != null) { + scriptProcessBuilder.end("停止运行"); + } + } + + @Override + public void run() { + //初始化ProcessBuilder对象 + try { + process = processBuilder.start(); + { + inputStream = process.getInputStream(); + InputStreamReader inputStreamReader = new InputStreamReader(inputStream, BaseJpomApplication.getCharset()); + BufferedReader results = new BufferedReader(inputStreamReader); + IoUtil.readLines(results, (LineHandler) ScriptProcessBuilder.this::handle); + } + { + errorInputStream = process.getErrorStream(); + InputStreamReader inputStreamReader = new InputStreamReader(errorInputStream, BaseJpomApplication.getCharset()); + BufferedReader results = new BufferedReader(inputStreamReader); + IoUtil.readLines(results, (LineHandler) line -> ScriptProcessBuilder.this.handle("ERROR:" + line)); + } + JsonMessage jsonMessage = new JsonMessage(200, "执行完毕"); + JSONObject jsonObject = jsonMessage.toJson(); + jsonObject.put("op", ConsoleCommandOp.stop.name()); + this.end(jsonObject.toString()); + } catch (IORuntimeException ignored) { + + } catch (Exception e) { + DefaultSystemLog.ERROR().error("执行异常", e); + this.end("执行异常:" + e.getMessage()); + } + } + + /** + * 结束执行 + * + * @param msg 响应的消息 + */ + private void end(String msg) { + if (this.process != null) { + // windows 中不能正常关闭 + this.process.destroy(); + IoUtil.close(inputStream); + IoUtil.close(errorInputStream); + } + Iterator iterator = sessions.iterator(); + while (iterator.hasNext()) { + Session session = iterator.next(); + try { + SocketSessionUtil.send(session, msg); + } catch (IOException e) { + DefaultSystemLog.ERROR().error("发送消息失败", e); + } + iterator.remove(); + } + FILE_SCRIPT_PROCESS_BUILDER_CONCURRENT_HASH_MAP.remove(this.scriptFile); + } + + /** + * 响应 + * + * @param line 信息 + */ + private void handle(String line) { + // 写入文件 + List fileLine = new ArrayList<>(); + fileLine.add(line); + FileUtil.appendLines(fileLine, logFile, CharsetUtil.CHARSET_UTF_8); + Iterator iterator = sessions.iterator(); + while (iterator.hasNext()) { + Session session = iterator.next(); + try { + SocketSessionUtil.send(session, line); + } catch (IOException e) { + DefaultSystemLog.ERROR().error("发送消息失败", e); + iterator.remove(); + } + } + } +} diff --git a/modules/agent/src/main/java/cn/keepbx/jpom/system/AgentConfigBean.java b/modules/agent/src/main/java/cn/keepbx/jpom/system/AgentConfigBean.java index e2f680ce5..b60073fa5 100644 --- a/modules/agent/src/main/java/cn/keepbx/jpom/system/AgentConfigBean.java +++ b/modules/agent/src/main/java/cn/keepbx/jpom/system/AgentConfigBean.java @@ -3,11 +3,9 @@ package cn.keepbx.jpom.system; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import cn.jiangzeyin.common.spring.SpringUtil; -import cn.jiangzeyin.controller.base.AbstractController; import cn.keepbx.jpom.common.BaseAgentController; import org.springframework.context.annotation.Configuration; -import javax.servlet.http.HttpServletRequest; import java.io.File; /** @@ -22,26 +20,30 @@ public class AgentConfigBean { * 白名单文件 */ public static final String WHITELIST_DIRECTORY = "whitelistDirectory.json"; - /** * 项目数据文件 */ public static final String PROJECT = "project.json"; - /** * 项目回收文件 */ public static final String PROJECT_RECOVER = "project_recover.json"; - /** * 阿里oss 文件 */ public static final String ALI_OSS = "aliOss.json"; - /** * 证书文件 */ public static final String CERT = "cert.json"; + /** + * 脚本管理数据文件 + */ + public static final String SCRIPT = "script.json"; + /** + * 脚本模板存放路径 + */ + public static final String SCRIPT_DIRECTORY = "script"; private static AgentConfigBean agentConfigBean; @@ -74,8 +76,7 @@ public class AgentConfigBean { */ public File getTempPath() { File file = new File(ConfigBean.getInstance().getDataPath()); - HttpServletRequest request = AbstractController.getRequestAttributes().getRequest(); - String userName = BaseAgentController.getUserName(request); + String userName = BaseAgentController.getNowUserName(); if (StrUtil.isEmpty(userName)) { throw new JpomRuntimeException("没有登录"); } @@ -83,4 +84,13 @@ public class AgentConfigBean { FileUtil.mkdir(file); return file; } + + /** + * 获取脚本模板路径 + * + * @return file + */ + public File getScriptPath() { + return FileUtil.file(ExtConfigBean.getInstance().getPath(), SCRIPT_DIRECTORY); + } } diff --git a/modules/common/src/main/java/cn/keepbx/jpom/BaseJpomApplication.java b/modules/common/src/main/java/cn/keepbx/jpom/BaseJpomApplication.java index fcc95adda..2faec0112 100644 --- a/modules/common/src/main/java/cn/keepbx/jpom/BaseJpomApplication.java +++ b/modules/common/src/main/java/cn/keepbx/jpom/BaseJpomApplication.java @@ -14,7 +14,10 @@ import java.nio.charset.Charset; * @date 2019/4/16 */ public abstract class BaseJpomApplication { - + /** + * + */ + public static final String SYSTEM_ID = "system"; public static final OsInfo OS_INFO = SystemUtil.getOsInfo(); protected static String[] args; diff --git a/modules/common/src/main/java/cn/keepbx/jpom/common/BaseOperService.java b/modules/common/src/main/java/cn/keepbx/jpom/common/BaseOperService.java index 1c6903b4c..1400afba0 100644 --- a/modules/common/src/main/java/cn/keepbx/jpom/common/BaseOperService.java +++ b/modules/common/src/main/java/cn/keepbx/jpom/common/BaseOperService.java @@ -38,6 +38,13 @@ public abstract class BaseOperService extends BaseDataService { */ public abstract void addItem(T t); + /** + * 删除实体 + * + * @param id 数据id + */ + public abstract void deleteItem(String id); + /** * 修改实体 * diff --git a/modules/common/src/main/java/cn/keepbx/jpom/socket/CommonSocketConfig.java b/modules/common/src/main/java/cn/keepbx/jpom/socket/CommonSocketConfig.java deleted file mode 100644 index 64b181ebc..000000000 --- a/modules/common/src/main/java/cn/keepbx/jpom/socket/CommonSocketConfig.java +++ /dev/null @@ -1,11 +0,0 @@ -package cn.keepbx.jpom.socket; - -/** - * @author jiangzeyin - * @date 2019/4/19 - */ -public class CommonSocketConfig { - - - public static final String SYSTEM_ID = "system"; -} diff --git a/modules/common/src/main/java/cn/keepbx/jpom/socket/CommandOp.java b/modules/common/src/main/java/cn/keepbx/jpom/socket/ConsoleCommandOp.java similarity index 82% rename from modules/common/src/main/java/cn/keepbx/jpom/socket/CommandOp.java rename to modules/common/src/main/java/cn/keepbx/jpom/socket/ConsoleCommandOp.java index 5a6f8745e..1c2b182ba 100644 --- a/modules/common/src/main/java/cn/keepbx/jpom/socket/CommandOp.java +++ b/modules/common/src/main/java/cn/keepbx/jpom/socket/ConsoleCommandOp.java @@ -1,12 +1,12 @@ package cn.keepbx.jpom.socket; /** - * socket 操作枚举 + * 控制台socket 操作枚举 * * @author jiangzeyin * @date 2019/4/16 */ -public enum CommandOp { +public enum ConsoleCommandOp { /** * 启动 */ diff --git a/modules/server/src/main/java/cn/keepbx/jpom/common/forward/NodeUrl.java b/modules/server/src/main/java/cn/keepbx/jpom/common/forward/NodeUrl.java index d93965563..72d842300 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/common/forward/NodeUrl.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/common/forward/NodeUrl.java @@ -22,6 +22,10 @@ public enum NodeUrl { * socket 连接 ,第一节项目id 第二节用户信息 */ TopSocket("/console/{}/{}"), + /** + * 脚本模板 模板id + */ + Script_Run("/script_run/{}/{}"), WhitelistDirectory_Submit("/system/whitelistDirectory_submit"), @@ -93,13 +97,17 @@ public enum NodeUrl { System_Nginx_delete("/system/nginx/delete"), System_Certificate_saveCertificate("/system/certificate/saveCertificate"), - System_Certificate_getCertList("/system/certificate/getCertList"), - System_Certificate_delete("/system/certificate/delete"), - System_Certificate_export("/system/certificate/export"), + Script_List("/script/list.json"), + Script_Item("/script/item.json"), + Script_Save("/script/save.json"), + Script_Upload("/script/upload.json"), + Script_Del("/script/del.json"), + + ; /** * 相对请求地址 diff --git a/modules/server/src/main/java/cn/keepbx/jpom/controller/InstallController.java b/modules/server/src/main/java/cn/keepbx/jpom/controller/InstallController.java index 3eb032174..4dfab6d5f 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/controller/InstallController.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/controller/InstallController.java @@ -4,12 +4,12 @@ import cn.hutool.core.lang.Validator; import cn.hutool.core.util.StrUtil; import cn.jiangzeyin.common.DefaultSystemLog; import cn.jiangzeyin.common.JsonMessage; +import cn.keepbx.jpom.BaseJpomApplication; import cn.keepbx.jpom.common.BaseServerController; import cn.keepbx.jpom.common.interceptor.LoginInterceptor; import cn.keepbx.jpom.common.interceptor.NotLogin; import cn.keepbx.jpom.model.data.UserModel; import cn.keepbx.jpom.service.user.UserService; -import cn.keepbx.jpom.socket.CommonSocketConfig; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @@ -59,7 +59,7 @@ public class InstallController extends BaseServerController { if (userName.length() < UserModel.USER_NAME_MIN_LEN) { return JsonMessage.getString(400, "登录名长度必须不小于" + UserModel.USER_NAME_MIN_LEN); } - if (CommonSocketConfig.SYSTEM_ID.equalsIgnoreCase(userName)) { + if (BaseJpomApplication.SYSTEM_ID.equalsIgnoreCase(userName)) { return JsonMessage.getString(400, "当前登录名已经被系统占用啦"); } if (Validator.isChinese(userName) || !checkPathSafe(userName)) { diff --git a/modules/server/src/main/java/cn/keepbx/jpom/controller/node/NodeEditController.java b/modules/server/src/main/java/cn/keepbx/jpom/controller/node/NodeEditController.java index 34e82f489..1a4a4301f 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/controller/node/NodeEditController.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/controller/node/NodeEditController.java @@ -120,10 +120,7 @@ public class NodeEditController extends BaseServerController { @UrlPermission(value = Role.System, optType = UserOperateLogV1.OptType.DelNode) @ResponseBody public String save(String id) { - boolean flag = nodeService.deleteItem(id); - if (!flag) { - return JsonMessage.getString(405, "删除失败"); - } + nodeService.deleteItem(id); // 删除授权 List list = userService.list(); if (list != null) { diff --git a/modules/server/src/main/java/cn/keepbx/jpom/controller/node/script/ScriptController.java b/modules/server/src/main/java/cn/keepbx/jpom/controller/node/script/ScriptController.java new file mode 100644 index 000000000..8be253712 --- /dev/null +++ b/modules/server/src/main/java/cn/keepbx/jpom/controller/node/script/ScriptController.java @@ -0,0 +1,84 @@ +package cn.keepbx.jpom.controller.node.script; + +import cn.hutool.core.util.StrUtil; +import cn.keepbx.jpom.common.BaseServerController; +import cn.keepbx.jpom.common.forward.NodeForward; +import cn.keepbx.jpom.common.forward.NodeUrl; +import cn.keepbx.jpom.common.interceptor.UrlPermission; +import cn.keepbx.jpom.model.Role; +import cn.keepbx.jpom.model.data.UserOperateLogV1; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +/** + * 脚本管理 + * + * @author jiangzeyin + * @date 2019/4/24 + */ +@Controller +@RequestMapping(value = "/node/script") +public class ScriptController extends BaseServerController { + + @RequestMapping(value = "list.html", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE) + public String list() { + JSONArray jsonArray = NodeForward.requestData(getNode(), NodeUrl.Script_List, getRequest(), JSONArray.class); + setAttribute("array", jsonArray); + return "node/script/list"; + } + + + @RequestMapping(value = "item.html", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE) + public String item(String id) { + setAttribute("type", "add"); + if (StrUtil.isNotEmpty(id)) { + JSONObject jsonObject = NodeForward.requestData(getNode(), NodeUrl.Script_Item, getRequest(), JSONObject.class); + if (jsonObject != null) { + setAttribute("type", "edit"); + setAttribute("item", jsonObject); + } + } + return "node/script/edit"; + } + + /** + * 保存脚本 + * + * @return json + */ + @RequestMapping(value = "save.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @ResponseBody + @UrlPermission(value = Role.System, optType = UserOperateLogV1.OptType.Save_Script) + public String save() { + return NodeForward.request(getNode(), getRequest(), NodeUrl.Script_Save).toString(); + } + + @RequestMapping(value = "del.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @ResponseBody + @UrlPermission(value = Role.System, optType = UserOperateLogV1.OptType.Save_Del) + public String del() { + return NodeForward.request(getNode(), getRequest(), NodeUrl.Script_Del).toString(); + } + + /** + * 导入脚本 + * + * @return json + */ + @RequestMapping(value = "upload", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @ResponseBody + @UrlPermission(value = Role.System, optType = UserOperateLogV1.OptType.Save_Upload) + public String upload() { + return NodeForward.requestMultipart(getNode(), getMultiRequest(), NodeUrl.Script_Upload).toString(); + } + + @RequestMapping(value = "console.html", method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE) + public String console(String id) { + return "node/script/console"; + } +} diff --git a/modules/server/src/main/java/cn/keepbx/jpom/controller/outgiving/OutGivingController.java b/modules/server/src/main/java/cn/keepbx/jpom/controller/outgiving/OutGivingController.java index 6acae90d1..33a098127 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/controller/outgiving/OutGivingController.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/controller/outgiving/OutGivingController.java @@ -196,10 +196,7 @@ public class OutGivingController extends BaseServerController { @ResponseBody @UrlPermission(value = Role.ServerManager, optType = UserOperateLogV1.OptType.DelOutGiving) public String del(String id) { - boolean flag = outGivingServer.deleteItem(id); - if (!flag) { - return JsonMessage.getString(405, "删除失败"); - } + outGivingServer.deleteItem(id); return JsonMessage.getString(200, "操作成功"); } } diff --git a/modules/server/src/main/java/cn/keepbx/jpom/controller/user/UserInfoController.java b/modules/server/src/main/java/cn/keepbx/jpom/controller/user/UserInfoController.java index dd11ad08a..594ee2f77 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/controller/user/UserInfoController.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/controller/user/UserInfoController.java @@ -4,6 +4,7 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; import cn.jiangzeyin.common.DefaultSystemLog; import cn.jiangzeyin.common.JsonMessage; +import cn.keepbx.jpom.BaseJpomApplication; import cn.keepbx.jpom.common.BaseServerController; import cn.keepbx.jpom.common.interceptor.LoginInterceptor; import cn.keepbx.jpom.common.interceptor.UrlPermission; @@ -12,7 +13,6 @@ import cn.keepbx.jpom.model.data.NodeModel; import cn.keepbx.jpom.model.data.UserModel; import cn.keepbx.jpom.model.data.UserOperateLogV1; import cn.keepbx.jpom.service.user.UserService; -import cn.keepbx.jpom.socket.CommonSocketConfig; import cn.keepbx.jpom.system.ServerExtConfigBean; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; @@ -122,11 +122,8 @@ public class UserInfoController extends BaseServerController { if (userModel.isSystemUser()) { return JsonMessage.getString(400, "非法访问:-5"); } - boolean b = userService.deleteUser(id); - if (b) { - return JsonMessage.getString(200, "删除成功"); - } - return JsonMessage.getString(400, "删除失败"); + userService.deleteItem(id); + return JsonMessage.getString(200, "删除成功"); } /** @@ -138,7 +135,7 @@ public class UserInfoController extends BaseServerController { @RequestMapping(value = "addUser", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @UrlPermission(value = Role.ServerManager, optType = UserOperateLogV1.OptType.AddUer) public String addUser(String id) { - if (CommonSocketConfig.SYSTEM_ID.equalsIgnoreCase(id)) { + if (BaseJpomApplication.SYSTEM_ID.equalsIgnoreCase(id)) { return JsonMessage.getString(400, "当前登录名已经被系统占用啦"); } UserModel userName = getUser(); diff --git a/modules/server/src/main/java/cn/keepbx/jpom/controller/user/log/UserOptLogController.java b/modules/server/src/main/java/cn/keepbx/jpom/controller/user/log/UserOptLogController.java index 214f12edd..6ed2f8342 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/controller/user/log/UserOptLogController.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/controller/user/log/UserOptLogController.java @@ -15,8 +15,10 @@ import cn.hutool.db.sql.Order; import cn.jiangzeyin.common.JsonMessage; import cn.keepbx.jpom.common.BaseServerController; import cn.keepbx.jpom.model.data.NodeModel; +import cn.keepbx.jpom.model.data.UserModel; import cn.keepbx.jpom.model.data.UserOperateLogV1; import cn.keepbx.jpom.service.node.NodeService; +import cn.keepbx.jpom.service.user.UserService; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import org.springframework.http.MediaType; @@ -40,6 +42,8 @@ import java.util.List; public class UserOptLogController extends BaseServerController { @Resource private NodeService nodeService; + @Resource + private UserService userService; /** * 展示用户列表 @@ -49,6 +53,9 @@ public class UserOptLogController extends BaseServerController { // 所有节点 List nodeModels = nodeService.list(); setAttribute("nodeArray", nodeModels); + // 用户 + List userModels = userService.list(); + setAttribute("userArray", userModels); return "user/log/list"; } @@ -83,6 +90,11 @@ public class UserOptLogController extends BaseServerController { entity.set("nodeId".toUpperCase(), selectNode); } + String selectUser = getParameter("selectUser"); + if (StrUtil.isNotEmpty(selectUser)) { + entity.set("userId".toUpperCase(), selectUser); + } + PageResult pageResult = Db.use().page(entity, page); CopyOptions copyOptions = new CopyOptions(); copyOptions.setIgnoreError(true); diff --git a/modules/server/src/main/java/cn/keepbx/jpom/model/data/UserModel.java b/modules/server/src/main/java/cn/keepbx/jpom/model/data/UserModel.java index a25c2c8b6..8b8fdf43a 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/model/data/UserModel.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/model/data/UserModel.java @@ -3,10 +3,10 @@ package cn.keepbx.jpom.model.data; import cn.hutool.core.date.DateUtil; import cn.hutool.core.map.MapUtil; import cn.hutool.crypto.SecureUtil; +import cn.keepbx.jpom.BaseJpomApplication; import cn.keepbx.jpom.model.BaseJsonModel; import cn.keepbx.jpom.model.BaseModel; import cn.keepbx.jpom.model.Role; -import cn.keepbx.jpom.socket.CommonSocketConfig; import cn.keepbx.jpom.system.ServerExtConfigBean; import com.alibaba.fastjson.JSONArray; @@ -253,7 +253,7 @@ public class UserModel extends BaseModel { return true; } // 系统监控权限 - if (CommonSocketConfig.SYSTEM_ID.equals(id)) { + if (BaseJpomApplication.SYSTEM_ID.equals(id)) { return true; } NodeRole item = nodeRole.get(nodeId); @@ -420,7 +420,7 @@ public class UserModel extends BaseModel { public boolean isManage() { return manage; } - + public JSONArray getProjects() { return projects; } diff --git a/modules/server/src/main/java/cn/keepbx/jpom/model/data/UserOperateLogV1.java b/modules/server/src/main/java/cn/keepbx/jpom/model/data/UserOperateLogV1.java index 2cf65f7a7..56b5ac030 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/model/data/UserOperateLogV1.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/model/data/UserOperateLogV1.java @@ -2,6 +2,7 @@ package cn.keepbx.jpom.model.data; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; +import cn.keepbx.jpom.BaseJpomApplication; import cn.keepbx.jpom.model.BaseEnum; import cn.keepbx.jpom.model.BaseJsonModel; @@ -126,7 +127,11 @@ public class UserOperateLogV1 extends BaseJsonModel { } public void setUserId(String userId) { - this.userId = userId; + if (UserModel.SYSTEM_OCCUPY_NAME.equals(userId)) { + this.userId = BaseJpomApplication.SYSTEM_ID; + } else { + this.userId = userId; + } } public long getOptTime() { @@ -232,6 +237,13 @@ public class UserOperateLogV1 extends BaseJsonModel { SaveOutgivingWhitelist(36, "修改节点白名单"), SaveOutgivingProject(37, "保存节点分发项目"), DeleteOutgivingProject(38, "删除节点分发项目"), + + Save_Script(39, "保存脚本模板"), + Script_Start(40, "执行脚本"), + Script_Stop(41, "停止脚本"), + Save_Upload(34, "导入脚本模板"), + Save_Del(34, "删除脚本模板"), + ; private int code; private String desc; diff --git a/modules/server/src/main/java/cn/keepbx/jpom/service/node/NodeService.java b/modules/server/src/main/java/cn/keepbx/jpom/service/node/NodeService.java index eb7143203..789c57baa 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/service/node/NodeService.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/service/node/NodeService.java @@ -2,7 +2,6 @@ package cn.keepbx.jpom.service.node; import cn.hutool.cache.impl.TimedCache; import cn.hutool.core.util.IdUtil; -import cn.jiangzeyin.common.DefaultSystemLog; import cn.keepbx.jpom.common.BaseOperService; import cn.keepbx.jpom.common.forward.NodeForward; import cn.keepbx.jpom.common.forward.NodeUrl; @@ -96,13 +95,8 @@ public class NodeService extends BaseOperService { return true; } - public boolean deleteItem(String id) { - try { - deleteJson(ServerConfigBean.NODE, id); - return true; - } catch (Exception e) { - DefaultSystemLog.ERROR().error(e.getMessage(), e); - } - return false; + @Override + public void deleteItem(String id) { + deleteJson(ServerConfigBean.NODE, id); } } diff --git a/modules/server/src/main/java/cn/keepbx/jpom/service/node/OutGivingServer.java b/modules/server/src/main/java/cn/keepbx/jpom/service/node/OutGivingServer.java index b1d83b090..68af3bcf1 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/service/node/OutGivingServer.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/service/node/OutGivingServer.java @@ -1,6 +1,5 @@ package cn.keepbx.jpom.service.node; -import cn.jiangzeyin.common.DefaultSystemLog; import cn.keepbx.jpom.common.BaseOperService; import cn.keepbx.jpom.model.data.OutGivingModel; import cn.keepbx.jpom.system.ServerConfigBean; @@ -54,13 +53,8 @@ public class OutGivingServer extends BaseOperService { return true; } - public boolean deleteItem(String id) { - try { - deleteJson(ServerConfigBean.OUTGIVING, id); - return true; - } catch (Exception e) { - DefaultSystemLog.ERROR().error(e.getMessage(), e); - } - return false; + @Override + public void deleteItem(String id) { + deleteJson(ServerConfigBean.OUTGIVING, id); } } diff --git a/modules/server/src/main/java/cn/keepbx/jpom/service/user/UserService.java b/modules/server/src/main/java/cn/keepbx/jpom/service/user/UserService.java index 5a6265ff6..94e7c52b2 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/service/user/UserService.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/service/user/UserService.java @@ -128,16 +128,10 @@ public class UserService extends BaseOperService { * 删除用户 * * @param id 用户id - * @return String */ - public boolean deleteUser(String id) { - try { - deleteJson(ServerConfigBean.USER, id); - return true; - } catch (Exception e) { - DefaultSystemLog.ERROR().error(e.getMessage(), e); - } - return false; + @Override + public void deleteItem(String id) { + deleteJson(ServerConfigBean.USER, id); } /** diff --git a/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketHandler.java b/modules/server/src/main/java/cn/keepbx/jpom/socket/BaseServerWebSocketHandler.java similarity index 57% rename from modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketHandler.java rename to modules/server/src/main/java/cn/keepbx/jpom/socket/BaseServerWebSocketHandler.java index 0664850d6..5c2b0b81b 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketHandler.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/socket/BaseServerWebSocketHandler.java @@ -1,6 +1,5 @@ package cn.keepbx.jpom.socket; -import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.URLUtil; import cn.jiangzeyin.common.DefaultSystemLog; @@ -22,27 +21,32 @@ import java.io.IOException; import java.util.Map; /** - * 消息处理器 + * 服务端socket 基本类 * * @author jiangzeyin - * @date 2019/4/19 + * @date 2019/4/25 */ -public class ServerWebSocketHandler extends TextWebSocketHandler { - private OperateLogController operateLogController; +public abstract class BaseServerWebSocketHandler extends TextWebSocketHandler { + protected OperateLogController operateLogController; + + private NodeUrl nodeUrl; + private String dataParName; + + public BaseServerWebSocketHandler(NodeUrl nodeUrl, String dataParName) { + this.nodeUrl = nodeUrl; + this.dataParName = dataParName; + } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { - if (operateLogController == null) { - operateLogController = SpringUtil.getBean(OperateLogController.class); - } Map attributes = session.getAttributes(); NodeModel nodeModel = (NodeModel) attributes.get("nodeInfo"); - String projectId = (String) attributes.get("projectId"); UserModel userInfo = (UserModel) attributes.get("userInfo"); - String url = NodeForward.getSocketUrl(nodeModel, NodeUrl.TopSocket); + String dataValue = (String) attributes.get(dataParName); String userName = UserModel.getOptUserName(userInfo); userName = URLUtil.encode(userName); - url = StrUtil.format(url, projectId, userName); + String url = NodeForward.getSocketUrl(nodeModel, nodeUrl); + url = StrUtil.format(url, dataValue, userName); // 连接节点 ProxySession proxySession = new ProxySession(url, session); session.getAttributes().put("proxySession", proxySession); @@ -51,56 +55,44 @@ public class ServerWebSocketHandler extends TextWebSocketHandler { @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) { + if (operateLogController == null) { + operateLogController = SpringUtil.getBean(OperateLogController.class); + } String msg = message.getPayload(); Map attributes = session.getAttributes(); ProxySession proxySession = (ProxySession) attributes.get("proxySession"); JSONObject json = JSONObject.parseObject(msg); String op = json.getString("op"); - CommandOp commandOp = CommandOp.valueOf(op); - UserOperateLogV1.OptType type = null; - switch (commandOp) { - case stop: - type = UserOperateLogV1.OptType.Stop; - break; - case start: - type = UserOperateLogV1.OptType.Start; - break; - case restart: - type = UserOperateLogV1.OptType.Restart; - break; - default: - break; - } - if (type != null) { - // 记录操作日志 - UserModel userInfo = (UserModel) attributes.get("userInfo"); - String ip = (String) attributes.get("ip"); - NodeModel nodeModel = (NodeModel) attributes.get("nodeInfo"); - // - String projectId = (String) attributes.get("projectId"); + ConsoleCommandOp consoleCommandOp = ConsoleCommandOp.valueOf(op); + this.handleTextMessage(attributes, proxySession, json, consoleCommandOp); + } - String reqId = IdUtil.fastUUID(); - json.put("reqId", reqId); + /** + * 消息处理方法 + * + * @param attributes 属性 + * @param proxySession 代理回话 + * @param json 数据 + * @param consoleCommandOp 操作类型 + */ + protected abstract void handleTextMessage(Map attributes, + ProxySession proxySession, + JSONObject json, + ConsoleCommandOp consoleCommandOp); - try { - OperateLogController.CacheInfo cacheInfo = new OperateLogController.CacheInfo(); - cacheInfo.setIp(ip); - cacheInfo.setOptType(type); - cacheInfo.setNodeModel(nodeModel); - cacheInfo.setDataId(projectId); - String userAgent = (String) attributes.get(HttpHeaders.USER_AGENT); - cacheInfo.setUserAgent(userAgent); + protected OperateLogController.CacheInfo cacheInfo(Map attributes, JSONObject json, UserOperateLogV1.OptType optType, String dataId) { + String ip = (String) attributes.get("ip"); + NodeModel nodeModel = (NodeModel) attributes.get("nodeInfo"); + OperateLogController.CacheInfo cacheInfo = new OperateLogController.CacheInfo(); + cacheInfo.setIp(ip); + cacheInfo.setOptType(optType); + cacheInfo.setNodeModel(nodeModel); + cacheInfo.setDataId(dataId); + String userAgent = (String) attributes.get(HttpHeaders.USER_AGENT); + cacheInfo.setUserAgent(userAgent); - cacheInfo.setReqData(json.toString()); - - operateLogController.log(reqId, userInfo, "还没有响应", cacheInfo); - } catch (Exception e) { - DefaultSystemLog.ERROR().error("记录操作日志异常", e); - } - proxySession.send(json.toString()); - } else { - proxySession.send(msg); - } + cacheInfo.setReqData(json.toString()); + return cacheInfo; } @Override diff --git a/modules/server/src/main/java/cn/keepbx/jpom/socket/ProxySession.java b/modules/server/src/main/java/cn/keepbx/jpom/socket/ProxySession.java index cf431d5ca..ccdb09001 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/socket/ProxySession.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/socket/ProxySession.java @@ -93,4 +93,13 @@ public class ProxySession extends WebSocketClient { } DefaultSystemLog.ERROR().error("发生错误", ex); } + + @Override + public void send(String text) { + try { + super.send(text); + } catch (Exception e) { + DefaultSystemLog.ERROR().error("转发消息失败", e); + } + } } diff --git a/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketConfig.java b/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketConfig.java index 164bbc7e7..d36e2514a 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketConfig.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketConfig.java @@ -13,10 +13,15 @@ import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry @Configuration @EnableWebSocket public class ServerWebSocketConfig implements WebSocketConfigurer { + private final ServerWebSocketInterceptor serverWebSocketInterceptor = new ServerWebSocketInterceptor(); @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { - registry.addHandler(new ServerWebSocketHandler(), "/console") - .addInterceptors(new ServerWebSocketInterceptor()).setAllowedOrigins("*"); + // 控制台 + registry.addHandler(new ServerWebSocketConsoleHandler(), "/console") + .addInterceptors(serverWebSocketInterceptor).setAllowedOrigins("*"); + // 脚本模板 + registry.addHandler(new ServerWebSocketScriptHandler(), "/script_run") + .addInterceptors(serverWebSocketInterceptor).setAllowedOrigins("*"); } } diff --git a/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketConsoleHandler.java b/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketConsoleHandler.java new file mode 100644 index 000000000..d01b6c843 --- /dev/null +++ b/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketConsoleHandler.java @@ -0,0 +1,57 @@ +package cn.keepbx.jpom.socket; + +import cn.hutool.core.util.IdUtil; +import cn.jiangzeyin.common.DefaultSystemLog; +import cn.keepbx.jpom.common.forward.NodeUrl; +import cn.keepbx.jpom.model.data.UserModel; +import cn.keepbx.jpom.model.data.UserOperateLogV1; +import cn.keepbx.jpom.system.init.OperateLogController; +import com.alibaba.fastjson.JSONObject; + +import java.util.Map; + +/** + * 控制台消息处理器 + * + * @author jiangzeyin + * @date 2019/4/19 + */ +public class ServerWebSocketConsoleHandler extends BaseServerWebSocketHandler { + + public ServerWebSocketConsoleHandler() { + super(NodeUrl.TopSocket, "projectId"); + } + + @Override + protected void handleTextMessage(Map attributes, ProxySession proxySession, JSONObject json, ConsoleCommandOp consoleCommandOp) { + UserOperateLogV1.OptType type = null; + switch (consoleCommandOp) { + case stop: + type = UserOperateLogV1.OptType.Stop; + break; + case start: + type = UserOperateLogV1.OptType.Start; + break; + case restart: + type = UserOperateLogV1.OptType.Restart; + break; + default: + break; + } + if (type != null) { + // 记录操作日志 + UserModel userInfo = (UserModel) attributes.get("userInfo"); + String reqId = IdUtil.fastUUID(); + json.put("reqId", reqId); + // + String projectId = (String) attributes.get("projectId"); + OperateLogController.CacheInfo cacheInfo = cacheInfo(attributes, json, type, projectId); + try { + operateLogController.log(reqId, userInfo, "还没有响应", cacheInfo); + } catch (Exception e) { + DefaultSystemLog.ERROR().error("记录操作日志异常", e); + } + } + proxySession.send(json.toString()); + } +} diff --git a/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketInterceptor.java b/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketInterceptor.java index 8609c253f..0fcc725f0 100644 --- a/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketInterceptor.java +++ b/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketInterceptor.java @@ -37,22 +37,37 @@ public class ServerWebSocketInterceptor implements HandshakeInterceptor { return false; } String nodeId = httpServletRequest.getParameter("nodeId"); - String projectId = httpServletRequest.getParameter("projectId"); NodeService nodeService = SpringUtil.getBean(NodeService.class); NodeModel nodeModel = nodeService.getItem(nodeId); - // 判断权限 - if (!userModel.isProject(nodeModel.getId(), projectId)) { + if (nodeModel == null) { return false; } - attributes.put("userInfo", userModel); - attributes.put("nodeInfo", nodeModel); - attributes.put("projectId", projectId); + // 判断拦截类型 + String type = httpServletRequest.getParameter("type"); + if ("script".equalsIgnoreCase(type)) { + // 脚本模板 + String scriptId = httpServletRequest.getParameter("scriptId"); + if (!userModel.isManage(nodeId)) { + return false; + } + attributes.put("scriptId", scriptId); + } else { + //控制台 + String projectId = httpServletRequest.getParameter("projectId"); + // 判断权限 + if (!userModel.isProject(nodeModel.getId(), projectId)) { + return false; + } + attributes.put("projectId", projectId); + } // String ip = ServletUtil.getClientIP(httpServletRequest); attributes.put("ip", ip); // String userAgent = ServletUtil.getHeaderIgnoreCase(httpServletRequest, HttpHeaders.USER_AGENT); attributes.put(HttpHeaders.USER_AGENT, userAgent); + attributes.put("nodeInfo", nodeModel); + attributes.put("userInfo", userModel); return true; } return false; diff --git a/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketScriptHandler.java b/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketScriptHandler.java new file mode 100644 index 000000000..cdb83e712 --- /dev/null +++ b/modules/server/src/main/java/cn/keepbx/jpom/socket/ServerWebSocketScriptHandler.java @@ -0,0 +1,51 @@ +package cn.keepbx.jpom.socket; + +import cn.jiangzeyin.common.DefaultSystemLog; +import cn.keepbx.jpom.common.forward.NodeUrl; +import cn.keepbx.jpom.model.data.UserModel; +import cn.keepbx.jpom.model.data.UserOperateLogV1; +import cn.keepbx.jpom.system.init.OperateLogController; +import com.alibaba.fastjson.JSONObject; + +import java.util.Map; + +/** + * 脚本模板消息控制器 + * + * @author jiangzeyin + * @date 2019/4/24 + */ +public class ServerWebSocketScriptHandler extends BaseServerWebSocketHandler { + + public ServerWebSocketScriptHandler() { + super(NodeUrl.Script_Run, "scriptId"); + } + + @Override + protected void handleTextMessage(Map attributes, ProxySession proxySession, JSONObject json, ConsoleCommandOp consoleCommandOp) { + UserOperateLogV1.OptType type = null; + switch (consoleCommandOp) { + case stop: + type = UserOperateLogV1.OptType.Script_Stop; + break; + case start: + type = UserOperateLogV1.OptType.Script_Start; + break; + default: + break; + } + if (type != null) { + // 记录操作日志 + UserModel userInfo = (UserModel) attributes.get("userInfo"); + // + String scriptId = (String) attributes.get("scriptId"); + OperateLogController.CacheInfo cacheInfo = cacheInfo(attributes, json, type, scriptId); + try { + operateLogController.log(userInfo, "脚本模板执行...", cacheInfo); + } catch (Exception e) { + DefaultSystemLog.ERROR().error("记录操作日志异常", e); + } + } + proxySession.send(json.toString()); + } +} diff --git a/modules/server/src/main/resources/vm/index.vm b/modules/server/src/main/resources/vm/index.vm index 03353d9b5..d02e81144 100644 --- a/modules/server/src/main/resources/vm/index.vm +++ b/modules/server/src/main/resources/vm/index.vm @@ -63,14 +63,17 @@ 节点管理 +

  • 节点分发
  • -
  • - 用户管理 -
  • + #if($user.isServerManager()) +
  • + 用户管理 +
  • + #end
  • 操作日志 diff --git a/modules/server/src/main/resources/vm/node/index.vm b/modules/server/src/main/resources/vm/node/index.vm index 1811461bb..4fc50dffa 100644 --- a/modules/server/src/main/resources/vm/node/index.vm +++ b/modules/server/src/main/resources/vm/node/index.vm @@ -72,15 +72,20 @@ 项目管理
  • -##
  • -## 宕机计划 -##
  • + ##
  • + ## 宕机计划 + ##
  • #if($user.isManage($node.id))
  • nginx管理
  • + +
  • + 脚本模板 +
  • #end #if($user.isSystemUser())
  • diff --git a/modules/server/src/main/resources/vm/node/list.vm b/modules/server/src/main/resources/vm/node/list.vm index 812f6e398..11a89e16e 100644 --- a/modules/server/src/main/resources/vm/node/list.vm +++ b/modules/server/src/main/resources/vm/node/list.vm @@ -61,6 +61,7 @@ var config = { cols: [[ {field: 'osName', title: '系统名', width: "10%"}, + {field: 'javaVersion', title: 'Java版本', width: "10%"}, {field: 'jpomVersion', title: 'Jpom版本', width: "10%"}, {field: 'count', title: '项目个数', width: "10%"}, {field: 'runCount', title: '运行中个数', width: "10%"}, diff --git a/modules/server/src/main/resources/vm/node/script/console.vm b/modules/server/src/main/resources/vm/node/script/console.vm new file mode 100644 index 000000000..3f39d19c7 --- /dev/null +++ b/modules/server/src/main/resources/vm/node/script/console.vm @@ -0,0 +1,222 @@ + + + + + #parse("./common/head.vm") + 项目管理系统 + + + + +
    + + #if($user.isManage($node.id)) +
    + + 执行 + ## 重启 + + +
    +
    + +
    +
    + #end +
    +
    + + + \ No newline at end of file diff --git a/modules/server/src/main/resources/vm/node/script/edit.vm b/modules/server/src/main/resources/vm/node/script/edit.vm new file mode 100644 index 000000000..3f12b0c65 --- /dev/null +++ b/modules/server/src/main/resources/vm/node/script/edit.vm @@ -0,0 +1,103 @@ + + + + + #parse("./common/head.vm") + oss + + + + +
    +
    +
    + +
    + + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    + #if($user.isSystemUser()) +
    +
    + + + #if($item) + 删除 + #end +
    +
    + #end +
    +
    + + + + \ No newline at end of file diff --git a/modules/server/src/main/resources/vm/node/script/list.vm b/modules/server/src/main/resources/vm/node/script/list.vm new file mode 100644 index 000000000..2e6d39db1 --- /dev/null +++ b/modules/server/src/main/resources/vm/node/script/list.vm @@ -0,0 +1,107 @@ + + + + + #parse("./common/head.vm") + 项目管理系统 + + + + +
    + + #if($user.isSystemUser()) + + + #end + +
    +
    + + + + + + + + + + + + #foreach($item in $array) + + + + + + + + #end + #if(!$array || $array.size()<=0) + + + + #end + +
    模板ID模板名称修改时间最后执行人操作
    $item.id$item.name$item.modifyTime$item.lastRunUser + + + + +
    没有相关信息
    +
    + + + \ No newline at end of file diff --git a/modules/server/src/main/resources/vm/node/system/whitelistDirectory.vm b/modules/server/src/main/resources/vm/node/system/whitelistDirectory.vm index 483be5cf6..75df1da06 100644 --- a/modules/server/src/main/resources/vm/node/system/whitelistDirectory.vm +++ b/modules/server/src/main/resources/vm/node/system/whitelistDirectory.vm @@ -5,22 +5,27 @@ #parse("./common/head.vm") 白名单目录 -
    +
    -
    +