diff --git a/openGauss-datakit/datakit-agent/HELP.md b/openGauss-datakit/datakit-agent/HELP.md new file mode 100644 index 0000000000000000000000000000000000000000..962b649bda22ea7a9968f59176dc267d6ab87ee6 --- /dev/null +++ b/openGauss-datakit/datakit-agent/HELP.md @@ -0,0 +1,31 @@ +# Read Me First + +The following was discovered as part of building this project: + +* The JVM level was changed from '11' to '17', review + the [JDK Version Range](https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-Versions#jdk-version-range) + on the wiki for more details. + +# Getting Started + +### Reference Documentation + +For further reference, please consider the following sections: + +* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) +* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/3.1.4/maven-plugin/reference/html/) +* [Create an OCI image](https://docs.spring.io/spring-boot/docs/3.1.4/maven-plugin/reference/html/#build-image) +* [Spring Web](https://docs.spring.io/spring-boot/docs/3.1.4/reference/htmlsingle/index.html#web) +* [JDBC API](https://docs.spring.io/spring-boot/docs/3.1.4/reference/htmlsingle/index.html#data.sql) + +### Guides + +The following guides illustrate how to use some features concretely: + +* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/) +* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/) +* [Building REST services with Spring](https://spring.io/guides/tutorials/rest/) +* [Accessing Relational Data using JDBC with Spring](https://spring.io/guides/gs/relational-data-access/) +* [Managing Transactions](https://spring.io/guides/gs/managing-transactions/) +* [Accessing data with MySQL](https://spring.io/guides/gs/accessing-data-mysql/) + diff --git a/openGauss-datakit/datakit-agent/pom.xml b/openGauss-datakit/datakit-agent/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..8bc70530ac51ffa8273d12916d90ee254e5d6034 --- /dev/null +++ b/openGauss-datakit/datakit-agent/pom.xml @@ -0,0 +1,98 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.6 + + + com.openGauss.datakit + DataKit-platform-agent + 1.0.0 + datakit-agent + datakit-agent + + 11 + + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.springframework.boot + spring-boot-starter-web + + + + com.mysql + mysql-connector-j + 8.0.31 + runtime + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.apache.commons + commons-lang3 + 3.12.0 + + + com.github.mwiede + jsch + 0.2.9 + + + cn.hutool + hutool-all + 5.3.5 + + + commons-codec + commons-codec + 1.10 + + + org.opengauss + opengauss-jdbc + 3.0.0 + + + com.alibaba + fastjson + 1.2.57 + + + org.springframework.boot + spring-boot-starter-validation + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/AgentApplication.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/AgentApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..0a56c94a3b0cb471b0cf1ae69bc02d6f9dbc999c --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/AgentApplication.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.opengauss.admin.agent; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * Application Main + * + * @author zhaobeijuan + */ +@EnableScheduling +@SpringBootApplication +public class AgentApplication { + + public static void main(String[] args) { + SpringApplication.run(AgentApplication.class, args); + } + +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/controller/AgentController.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/controller/AgentController.java new file mode 100644 index 0000000000000000000000000000000000000000..420b4185e8ca5f5752f7641eb5ad6ec76b6d5718 --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/controller/AgentController.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.opengauss.admin.agent.controller; + +import org.opengauss.admin.agent.domain.AjaxResult; +import org.opengauss.admin.agent.domain.model.CfgData; +import org.opengauss.admin.agent.service.IAgentService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.Objects; + +@RestController +@RequestMapping("/agent") +public class AgentController { + @Autowired + private IAgentService agentService; + + /** + * agent ping 测试连通性 + * + */ + @PostMapping("/ping") + public AjaxResult ping(){ + return AjaxResult.success(); + } + + /** + * saveCfg 保存agent配置参数 + * + * @param cfgData cfgData接收的参数体 + * @return AjaxResult + */ + @PostMapping("/cfg") + public AjaxResult saveCfg(@Valid @RequestBody CfgData cfgData, BindingResult result){ + if (result.hasErrors()) { + return AjaxResult.error(Objects.requireNonNull(result.getFieldError()).getDefaultMessage()); + } + agentService.saveCfg(cfgData); + return AjaxResult.success(); + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/AjaxResult.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/AjaxResult.java new file mode 100644 index 0000000000000000000000000000000000000000..45af81b7cbea07788c90c5377383dd95957f47ac --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/AjaxResult.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * AjaxResult.java + * + * IDENTIFICATION + * openGauss-visualtool/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/AjaxResult.java + * + * ------------------------------------------------------------------------- + */ + + +package org.opengauss.admin.agent.domain; + +import org.opengauss.admin.agent.enums.ResponseCode; +import org.opengauss.admin.agent.util.StringUtils; + +import java.util.HashMap; + +/** + * Ajax Result Response + * + * @author xielibo + */ +public class AjaxResult extends HashMap { + private static final long serialVersionUID = 1L; + + /** + * code + */ + public static final String CODE_TAG = "code"; + + /** + * message + */ + public static final String MSG_TAG = "msg"; + + /** + * data + */ + public static final String DATA_TAG = "data"; + + public AjaxResult() { + } + public AjaxResult(int code, String msg) { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + } + + public AjaxResult(int code, String msg, Object data) { + super.put(CODE_TAG, code); + super.put(MSG_TAG, msg); + if (StringUtils.isNotNull(data)) { + super.put(DATA_TAG, data); + } + } + public static AjaxResult success() { + return AjaxResult.success("success"); + } + + public static AjaxResult success(Object data) { + return AjaxResult.success("success", data); + } + + public static AjaxResult success(String msg) { + return AjaxResult.success(msg, null); + } + + public static AjaxResult success(String msg, Object data) { + return new AjaxResult(ResponseCode.SUCCESS.code(), msg, data); + } + + public static AjaxResult error() { + return AjaxResult.error("fail"); + } + + public static AjaxResult error(String msg) { + return AjaxResult.error(msg, null); + } + + public static AjaxResult error(Integer code) { + return AjaxResult.error(code, ResponseCode.getInstance(code).msg()); + } + + /** + * error response encapsulation + * + * @param code error code + * @param msg error message + * @param data data + * @return Response Result + */ + public static AjaxResult errorAttachedData(Integer code, String msg, Object data) { + return new AjaxResult(code, msg, data); + } + + public static AjaxResult error(String msg, Object data) { + return new AjaxResult(ResponseCode.ERROR.code(), msg, data); + } + + public static AjaxResult error(int code, String msg) { + return new AjaxResult(code, msg, null); + } + + public boolean isOk() { + Object code = get(CODE_TAG); + return code != null && code.equals(ResponseCode.SUCCESS.code()); + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/CfgData.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/CfgData.java new file mode 100644 index 0000000000000000000000000000000000000000..2c05ccb26ab862d979ee1ddb542dcbaf6a8f2956 --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/CfgData.java @@ -0,0 +1,21 @@ +package org.opengauss.admin.agent.domain.model; + +import lombok.Data; + + +import javax.validation.constraints.NotEmpty; +import java.util.List; + +@Data +public class CfgData { + // agentId + @NotEmpty(message = "agentId cannot is empty!") + private String agentId; + + // serUrl(上报数据的url) + @NotEmpty(message = "serUrl cannot is empty!") + private String serUrl; + + // 接收到的agent配置列表 + private List cfgVOList; +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/CfgVO.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/CfgVO.java new file mode 100644 index 0000000000000000000000000000000000000000..248f81bd4b3b9be01a5da4b9fe5af8ded6932d5c --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/CfgVO.java @@ -0,0 +1,62 @@ +package org.opengauss.admin.agent.domain.model; + +import lombok.Data; + +import lombok.RequiredArgsConstructor; + +import javax.validation.constraints.NotEmpty; + +@Data +@RequiredArgsConstructor +public class CfgVO { + //对应hostId或者clusterNodeId + @NotEmpty(message = "nodeId cannot is empty!") + private String nodeId; + + //值为 host 或者 db + @NotEmpty(message = "type cannot is empty!") + private String type; + + //如果type为db,该字段有效:为集群名称 + private String clusterName; + + //如果type为db,该字段有效:MYSQL 或者 OPENGAUSS + private String dbType; + + //IP地址 + @NotEmpty(message = "ip cannot is empty!") + private String ip; + + //端口号 + @NotEmpty(message = "port cannot is empty!") + private Integer port; + + //用户名 + @NotEmpty(message = "user cannot is empty!") + private String user; + + //密码 + @NotEmpty(message = "pass cannot is empty!") + private String pass; + + //数据库url + private String url; + + + // 转换为子类 + public MonitorEntity toMonitorEntity () { + MonitorEntity monitorEntity = new MonitorEntity(); + monitorEntity.setNodeId(nodeId); + monitorEntity.setType(type); + monitorEntity.setClusterName(clusterName); + monitorEntity.setDbType(dbType); + monitorEntity.setIp(ip); + monitorEntity.setPort(port); + monitorEntity.setUser(user); + monitorEntity.setPass(pass); + monitorEntity.setUrl(url); + monitorEntity.setRootSession(null); + monitorEntity.setSqlConnection(null); + return monitorEntity; + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/MonitorEntity.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/MonitorEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..f4f0d7e11e86a65585c72d46723d95ee6814dc5d --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/MonitorEntity.java @@ -0,0 +1,56 @@ +package org.opengauss.admin.agent.domain.model; + +import com.jcraft.jsch.Session; +import lombok.*; +import lombok.extern.slf4j.Slf4j; + +import java.sql.Connection; +import java.sql.SQLException; + +@Slf4j +@Data +public class MonitorEntity extends CfgVO { + // 服务器连接 + private Session rootSession; + + // 数据库连接 + private Connection sqlConnection; + + /** + * 关闭数据库或主机连接 + */ + public void closeSession() { + if (getType().equals("db")) { + if (sqlConnection != null) { + try { + sqlConnection.close(); + } catch (SQLException e) { + log.error("sqlConnection close error: " + e.getMessage()); + } + } + } + + if (getType().equals("host")) { + if (rootSession != null) { + rootSession.disconnect(); + } + } + } + + @Override + public String toString() { + return "MonitorEntity{" + + "nodeId='" + getNodeId() + '\'' + + ", type='" + getType() + '\'' + + ", clusterName='" + getClusterName() + '\'' + + ", dbType='" + getDbType() + '\'' + + ", ip='" + getIp() + '\'' + + ", port=" + getPort() + + ", user='" + getUser() + '\'' + + ", pass='" + getPass() + '\'' + + ", url='" + getUrl() + '\'' + + ", rootSession='" + rootSession + '\'' + + ", sqlConnection='" + sqlConnection + '\'' + + '}'; + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/PerfData.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/PerfData.java new file mode 100644 index 0000000000000000000000000000000000000000..27c89816a5f94ec7c0933f139664f70e8dcfe254 --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/PerfData.java @@ -0,0 +1,11 @@ +package org.opengauss.admin.agent.domain.model; + +import lombok.Data; + +import java.util.List; + +@Data +public class PerfData { + private String agentId; + private List perfVOList; +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/PerfVO.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/PerfVO.java new file mode 100644 index 0000000000000000000000000000000000000000..f2a353851bd59783904c7be7df8381d1fbf22195 --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/PerfVO.java @@ -0,0 +1,39 @@ +package org.opengauss.admin.agent.domain.model; + +import lombok.Data; + +@Data +public class PerfVO { + // 对应hostId或者clusterNodeId + private String nodeId; + // 需要监控的对象类型,值为 host 或者 db + private String type; + // 如果type为db,该字段有效:MYSQL 或者 OPENGAUSS + private String dbType; + // 网卡流出量 + private String upSpeed; + // 网卡流入量 + private String downSpeed; + // cpu使用率 + private String cpu; + // 内存使用率 + private String memory; + // 磁盘使用率 + private String disk; + // 主备(MYSQL),值为:MASTER or SLAVE or CASCADE + private String role; + // 连接数(MYSQL, openGauss) + private String connNum; + // 每秒请求数,就是说服务器在一秒的时间内处理了多少个请求(MYSQL) + private String qps; + // 吞吐量,每秒处理事务数(MYSQL) + private String tps; + // 内存使用率(MYSQL) + private String memoryUsed; + // 表空间占用(MYSQL) + private String tableSpaceUsed; + // 锁数量(OPENGAUSS) + private String lockNum; + // 会话数(OPENGAUSS) + private String sessionNum; +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/ops/HostFile.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/ops/HostFile.java new file mode 100644 index 0000000000000000000000000000000000000000..cab1902cce3eecd9875d7f38bcebe840debe4618 --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/ops/HostFile.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * HostFile.java + * + * IDENTIFICATION + * openGauss-visualtool/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/HostFile.java + * + * ------------------------------------------------------------------------- + */ + + +package org.opengauss.admin.agent.domain.model.ops; + +import lombok.Data; +import org.opengauss.admin.agent.enums.ops.HostFileTypeEnum; + +import java.io.File; + +/** + * @author lhf + * @date 2022/8/7 22:37 + **/ +@Data +public class HostFile { + + private String name; + + private HostFileTypeEnum type; + /** + * size(byte) + */ + private Long size; + + public static HostFile build(File file) { + HostFile hostFile = new HostFile(); + String fileName = file.getName(); + HostFileTypeEnum fileType = file.isFile() ? HostFileTypeEnum.FILE : HostFileTypeEnum.DIRECTORY; + long length = file.length(); + + hostFile.setName(fileName); + hostFile.setType(fileType); + hostFile.setSize(length); + + return hostFile; + } + + public static HostFile of(String filename, HostFileTypeEnum hostFileTypeEnum, long size) { + HostFile hostFile = new HostFile(); + hostFile.setName(filename); + hostFile.setType(hostFileTypeEnum); + hostFile.setSize(size); + return hostFile; + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/ops/JschResult.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/ops/JschResult.java new file mode 100644 index 0000000000000000000000000000000000000000..637982e0a6669b720368db9f4105aa1e18f7499b --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/ops/JschResult.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * JschResult.java + * + * IDENTIFICATION + * openGauss-visualtool/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/JschResult.java + * + * ------------------------------------------------------------------------- + */ + + +package org.opengauss.admin.agent.domain.model.ops; + +import lombok.Data; + +/** + * @author lhf + * @date 2022/8/10 14:08 + **/ +@Data +public class JschResult { + private Integer exitCode; + private String result; + + public boolean isOk() { + return exitCode != null && exitCode == 0; + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/ops/jdbc/JdbcInfo.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/ops/jdbc/JdbcInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..2de4e867a04c5804eef293d2795d378b263a554b --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/domain/model/ops/jdbc/JdbcInfo.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * JdbcInfo.java + * + * IDENTIFICATION + * openGauss-visualtool/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/jdbc/JdbcInfo.java + * + * ------------------------------------------------------------------------- + */ + + +package org.opengauss.admin.agent.domain.model.ops.jdbc; + +import lombok.Data; +import org.opengauss.admin.agent.enums.ops.DbTypeEnum; + +/** + * @author lhf + * @date 2023/1/13 13:45 + **/ +@Data +public class JdbcInfo { + private DbTypeEnum dbType; + private String ip; + private String port; +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/enums/ResponseCode.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/enums/ResponseCode.java new file mode 100644 index 0000000000000000000000000000000000000000..76e62badcfea7b0b69c4f9f12b729886baa42d97 --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/enums/ResponseCode.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * ResponseCode.java + * + * IDENTIFICATION + * openGauss-visualtool/visualtool-common/src/main/java/org/opengauss/admin/common/enums/ResponseCode.java + * + * ------------------------------------------------------------------------- + */ + + +package org.opengauss.admin.agent.enums; + +import java.util.HashMap; +import java.util.Map; + +/** + * @description: error codes + * @param: + * @return: + * @author: xielibo + * @date: 2020/11/2 + */ +public enum ResponseCode { + //success + SUCCESS(200, "success"), + + //request params is bad + BAD_REQUEST(400, "request params is bad"), + + //unauthorized + UNAUTHORIZED(401, "unauthorized"), + + //authorization expired + FORBIDDEN(403, "authorization expired"), + + //system error + ERROR(500, "system error"), + + //platform + INTEGRATION_PLUGIN_STOP_ERROR(50101, "plugin stop error"), + INTEGRATION_PLUGIN_START_ERROR(50102, "plugin start error"), + INTEGRATION_PLUGIN_UNINSTALL_ERROR(50103, "plugin uninstall error"), + INTEGRATION_PLUGIN_INSTALL_ERROR(50104, "plugin install error"), + ROLE_EXISTS_ERROR(50105, "role is exists"), + ROLE_PERMISSIONS_EXISTS_ERROR(50106, "role permissions is exists"), + USER_PHONE_EXISTS_ERROR(50107, "user phone is exists"), + USER_EMAIL_EXISTS_ERROR(50108, "user email is exists"), + USER_RESET_PASS_ORIGIN_PASS_ERROR(50109, "origin pass is error"), + USER_PASS_SAME_ERROR(50110, "New password can't be same as old password!"), + MENU_NAME_IS_EXISTS_ERROR(50111, "menu name is exists"), + MENU_NOT_ADD_SELF_AS_SUBMENU_ERROR(50112, "A menu cannot add itself as a submenu"), + MENU_HAS_SUBMENU_NOT_DELETE(50113, "This menu has a submenu, it is not allowed to delete"), + MENU_ASSIGNED_NOT_DELETE(50114, "This menu has already been assigned and cannot be deleted"), + USER_ACCOUNT_EXISTS_ERROR(50115, "user account is exists"), + PLUGIN_MENU_HAS_OTHER_PLUGIN_SUBMENU_UNINSTALL_ERROR(50116, "This plugin menu has submenus for other plugins"), + ROLE_NAME_IS_NOT_EMPTY_ERROR(50117, "Role name cannot be empty"), + ROLE_NAME_MAX_LENGTH_ERROR(50118, "Role name length cannot exceed 25 characters"), + ROLE_REMARK_MAX_LENGTH_ERROR(50119, "Role remark length cannot exceed 200 characters"), + USER_NAME_MAX_LENGTH_ERROR(50120, "User account length cannot exceed 30 characters"), + USER_NICKNAME_MAX_LENGTH_ERROR(50121, "User nickname length cannot exceed 30 characters"), + USER_REMARK_MAX_LENGTH_ERROR(50122, "User remark length cannot exceed 200 characters"), + USER_TELEPHONE_MAX_LENGTH_ERROR(50123, "User telephone length cannot exceed 11 characters"), + + WHITELIST_TITLE_MAX_LENGTH_ERROR(50124, "Whitelist title length cannot exceed 100 characters"), + WHITELIST_IPS_MAX_LENGTH_ERROR(50125, "Whitelist IP list length cannot exceed 200 characters"), + + WHITELIST_TITLE_EXISTS_ERROR(50126, "Whitelist title already exists") + ; + + + private static Map codeMap = new HashMap(); + + private Integer code; + + private String msg; + + private String value; + + /** + * + */ + private ResponseCode() { + } + + /** + * @param value + */ + private ResponseCode(String value) { + this.value = value; + } + + /** + * @param code + * @param msg + */ + private ResponseCode(Integer code, String msg) { + this.code = code; + this.msg = msg; + } + + /** + * @return + */ + public Integer code() { + return this.code; + } + + /** + * @return + */ + public String msg() { + return this.msg; + } + + /** + * @return + */ + public String value() { + return this.value; + } + + /** + * @param codeValue + * @return + */ + public static ResponseCode getInstance(Integer codeValue) { + return getCodeMap().get(codeValue); + } + + /** + * @return + */ + private static Map getCodeMap() { + if (codeMap == null || codeMap.size() == 0) { + ResponseCode[] codeList = ResponseCode.values(); + for (ResponseCode c : codeList) { + codeMap.put(c.code(), c); + } + } + return codeMap; + } + + +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/enums/ops/DbTypeEnum.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/enums/ops/DbTypeEnum.java new file mode 100644 index 0000000000000000000000000000000000000000..462df4b508a016d8af500a4bbdc218845fe6eff6 --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/enums/ops/DbTypeEnum.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * DbTypeEnum.java + * + * IDENTIFICATION + * openGauss-visualtool/visualtool-common/src/main/java/org/opengauss/admin/common/enums/ops/DbTypeEnum.java + * + * ------------------------------------------------------------------------- + */ + + +package org.opengauss.admin.agent.enums.ops; + +import cn.hutool.core.util.StrUtil; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @author lhf + * @date 2023/1/13 11:00 + **/ +@AllArgsConstructor +@Getter +public enum DbTypeEnum { + MYSQL("com.mysql.cj.jdbc.Driver"), + OPENGAUSS("org.opengauss.Driver"), + NULL("null"); + + private String driverClass; + + public static DbTypeEnum typeOf(String dbType) { + if (StrUtil.isEmpty(dbType)) { + return NULL; + } + if (!StrUtil.isEmpty(dbType)) { + for (DbTypeEnum enumConstant : DbTypeEnum.class.getEnumConstants()) { + if (enumConstant.name().equalsIgnoreCase(dbType)) { + return enumConstant; + } + } + } + return NULL; + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/enums/ops/HostFileTypeEnum.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/enums/ops/HostFileTypeEnum.java new file mode 100644 index 0000000000000000000000000000000000000000..e481c0c4107619fe92517f6f07edd7ca6a598340 --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/enums/ops/HostFileTypeEnum.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * HostFileTypeEnum.java + * + * IDENTIFICATION + * openGauss-visualtool/visualtool-common/src/main/java/org/opengauss/admin/common/enums/ops/HostFileTypeEnum.java + * + * ------------------------------------------------------------------------- + */ + + +package org.opengauss.admin.agent.enums.ops; + +/** + * @author lhf + * @date 2022/8/8 10:12 + **/ +public enum HostFileTypeEnum { + FILE, + DIRECTORY +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/exception/ops/OpsException.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/exception/ops/OpsException.java new file mode 100644 index 0000000000000000000000000000000000000000..41357218d39baa2f9c378d436dad85c83b53fa30 --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/exception/ops/OpsException.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * OpsException.java + * + * IDENTIFICATION + * openGauss-visualtool/visualtool-common/src/main/java/org/opengauss/admin/common/exception/ops/OpsException.java + * + * ------------------------------------------------------------------------- + */ + + +package org.opengauss.admin.agent.exception.ops; + +/** + * + * @author lhf + * @date 2022/8/4 22:24 + **/ +public class OpsException extends RuntimeException { + private String message; + + public OpsException(String message) { + super(message); + this.message = message; + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/service/IAgentService.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/service/IAgentService.java new file mode 100644 index 0000000000000000000000000000000000000000..06e781305592a5842d701160eee32be8fed10595 --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/service/IAgentService.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + + +package org.opengauss.admin.agent.service; + +import org.opengauss.admin.agent.domain.model.CfgData; + +/** + * @author lhf + * @date 2022/8/7 22:27 + **/ +public interface IAgentService { + // 设置agent配置 + +// /** +// * saveCfg(保存agent配置) +// * +// * @param cfgData +// */ + + /** + * + * @param cfgData + */ + void saveCfg(CfgData cfgData); + + /** + * doMonitor 10秒循环开始 + */ + void doMonitor (); +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/service/impl/AgentServiceImpl.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/service/impl/AgentServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..1fd7cdc1a996be92425183f072ec050e9fb46c01 --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/service/impl/AgentServiceImpl.java @@ -0,0 +1,719 @@ +package org.opengauss.admin.agent.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.jcraft.jsch.Session; +import lombok.extern.slf4j.Slf4j; +import org.opengauss.admin.agent.domain.model.*; +import org.opengauss.admin.agent.domain.model.ops.JschResult; +import org.opengauss.admin.agent.enums.ops.DbTypeEnum; +import org.opengauss.admin.agent.service.IAgentService; +import org.opengauss.admin.agent.exception.ops.OpsException; +import org.opengauss.admin.agent.util.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.sql.*; +import java.util.*; +import java.util.concurrent.CountDownLatch; + +/** + * @author lhf + * @date 2022/8/7 22:28 + **/ +@Slf4j +@Service +public class AgentServiceImpl implements IAgentService { + @Autowired + private ThreadPoolTaskExecutor threadPoolTaskExecutor; + @Autowired + private JschUtil jschUtil; + + private static String agentId = ""; + private static String serverUrl = ""; + private static List monitorEntities = new ArrayList<>(); + +// /** +// * 设置agent配置 +// * +// * @param cfgData cfgData +// */ + + /** + * + * @param cfgData + */ + @Override + public void saveCfg(CfgData cfgData) { + // 保存url和自己的agentid,上报状态时使用 + serverUrl = cfgData.getSerUrl(); + agentId = cfgData.getAgentId(); + + // 临时保存新下发的配置列表,保存至newMonitorEntirys + List cfgVOList = cfgData.getCfgVOList(); + List newMonitorEntities = new ArrayList<>(); + for (CfgVO cfgVO : cfgVOList) { + newMonitorEntities.add(cfgVO.toMonitorEntity()); + } + + // 1, 遍历老的配置列表,如果在新的列表中没有,就关闭session + for (MonitorEntity monitorEntity : monitorEntities) { + Optional find = findEntiry(newMonitorEntities, monitorEntity); + if (find.isEmpty()) { + monitorEntity.closeSession(); + } + } + + // 2, 遍历新的配置列表,如果在老的列表中有,就把session复制过来 + for (MonitorEntity monitorEntity : newMonitorEntities) { + Optional find = findEntiry(monitorEntities, monitorEntity); + if (find.isPresent()) { + monitorEntity.setSqlConnection(find.get().getSqlConnection()); + monitorEntity.setRootSession(find.get().getRootSession()); + } + } + + // 3, 覆盖老的配置列表 + monitorEntities = newMonitorEntities; + } + + /** + * 查找监控对象,如果type和nodeId都一样则查找成功,否则查找失败 + * @param monitorEntities + * @param monitorEntity + * @return + */ + private Optional findEntiry(List monitorEntities, MonitorEntity monitorEntity) { + for (MonitorEntity tmp : monitorEntities) { + if (tmp.getType().equals(monitorEntity.getType()) + && tmp.getNodeId().equals(monitorEntity.getNodeId())) { + return Optional.of(tmp); + } + } + return Optional.empty(); + } + /** + * doMonitor 5秒循环开始 + */ + @Scheduled(cron="*/5 * * * * ?") + public void doMonitor () { + for (MonitorEntity monitorEntity : monitorEntities) { + if ("host".equals(monitorEntity.getType())) { + monitorHost(monitorEntity); + } + if ("db".equals(monitorEntity.getType())) { + monitorDB(monitorEntity); + } + } + } + + /** + * monitorHost + * + * @param monitorEntity monitorEntity + */ + public void monitorHost (MonitorEntity monitorEntity) { + + threadPoolTaskExecutor.submit(() -> { + // 如果还没有创建连接,就连接 + if (monitorEntity.getRootSession() == null || !monitorEntity.getRootSession().isConnected()) { + // 创建session连接 + Optional session = jschUtil.getSession(monitorEntity.getIp(), monitorEntity.getPort(), monitorEntity.getUser(), monitorEntity.getPass()); + if (session.isPresent()) { + monitorEntity.setRootSession(session.get()); + } + } + + // 对进行主机监控 + doMonitorHost(monitorEntity); + }); + } + + /** + * doMonitorHost + * + * @param monitorEntity monitorEntity + */ + private void doMonitorHost(MonitorEntity monitorEntity) { + // 创建同步队列,并设置初始计数器值为4 + CountDownLatch countDownLatch = new CountDownLatch(4); + + // 新建上报指标对象 + PerfVO perfVO = new PerfVO(); + perfVO.setNodeId(monitorEntity.getNodeId()); + perfVO.setType(monitorEntity.getType()); + + Session rootSession = monitorEntity.getRootSession(); + + // 获取网卡吞吐量 + threadPoolTaskExecutor.submit(() -> { + try { + String[] net = netMonitor(rootSession); + perfVO.setUpSpeed(net[0]); + perfVO.setDownSpeed(net[1]); + } finally { + countDownLatch.countDown(); + } + }); + + // 获取cpu使用率 + threadPoolTaskExecutor.submit(() -> { + try { + perfVO.setCpu(cpuMonitor(rootSession)); + } finally { + countDownLatch.countDown(); + } + }); + + // 获取内存使用率 + threadPoolTaskExecutor.submit(() -> { + try { + log.info("Host memory: " + memoryMonitor(rootSession)); + perfVO.setMemory(memoryMonitor(rootSession)); + } finally { + countDownLatch.countDown(); + } + }); + + // 获取磁盘使用率 + threadPoolTaskExecutor.submit(() -> { + try { + log.info("Host disk: " + diskMonitor(rootSession)); + perfVO.setDisk(diskMonitor(rootSession)); + } finally { + countDownLatch.countDown(); + } + }); + + try { + // 此时线程会被挂起,它会等待直到countDownLatch值为0才继续执行 + countDownLatch.await(); + } catch (InterruptedException e) { + log.error("waiting for thread to be interrupted", e); + throw new OpsException("monitor error"); + } + // 上报Host监控指标 + sendPerfData(perfVO); + } + + /** + * monitorDB + * + * @param monitorEntity monitorEntity + */ + public void monitorDB (MonitorEntity monitorEntity) { + threadPoolTaskExecutor.submit(() -> { + Connection connection = monitorEntity.getSqlConnection(); + // 如果还没有创建连接,就连接 + try { + if (Objects.isNull(connection) || connection.isClosed()) { + // 连接数据库 + connection = JdbcUtil.getConnection(monitorEntity.getUrl(), monitorEntity.getUser(), monitorEntity.getPass()); + monitorEntity.setSqlConnection(connection); + } + } catch (SQLException e) { + log.error("SQL Error: ", e.getMessage()); + } + + // 对进行主机监控 + doMonitorDB(monitorEntity); + }); + } + + /** + * doMonitorDB + * + * @param monitorEntity monitorEntity + */ + public void doMonitorDB (MonitorEntity monitorEntity) { + if (StringUtils.isEmpty(monitorEntity.getDbType())) { + log.info("dbType cannot is empty!"); + return; + } + if (StringUtils.isEmpty(monitorEntity.getUrl())) { + log.info("url cannot is empty!"); + return; + } + + // 按照dbType区分MYSQL or OPENGAUSS + if (DbTypeEnum.MYSQL.toString().equals(monitorEntity.getDbType())) { + monitorMysql(monitorEntity); + } else if (DbTypeEnum.OPENGAUSS.toString().equals(monitorEntity.getDbType())) { + monitorOpenGauss(monitorEntity); + } + } + + /** + * monitorMysql + * + * @param monitorEntity monitorEntity + */ + public void monitorMysql (MonitorEntity monitorEntity) { + // 创建同步队列,并设置初始计数器值为6 + CountDownLatch countDownLatch = new CountDownLatch(6); + Connection connection = monitorEntity.getSqlConnection(); + + PerfVO perfVO = new PerfVO(); + perfVO.setNodeId(monitorEntity.getNodeId()); + perfVO.setType(monitorEntity.getType()); + perfVO.setDbType(monitorEntity.getDbType()); + + threadPoolTaskExecutor.submit(() -> { + try { + // 获取主备信息 + log.info("Mysql main and backup info: " + role(connection)); + perfVO.setRole(role(connection)); + } finally { + countDownLatch.countDown(); + } + }); + + threadPoolTaskExecutor.submit(() -> { + try { + // 获取连接数 + log.info("Mysql connection num: " + connNum(connection)); + perfVO.setConnNum(connNum(connection)); + } finally { + countDownLatch.countDown(); + } + }); + + threadPoolTaskExecutor.submit(() -> { + try { + // 获取qps + log.info("Mysql qps: " + qps(connection)); + perfVO.setQps(qps(connection)); + } finally { + countDownLatch.countDown(); + } + }); + + threadPoolTaskExecutor.submit(() -> { + try { + // 获取tps + log.info("Mysql tps: " + tps(connection)); + perfVO.setTps(tps(connection)); + } finally { + countDownLatch.countDown(); + } + }); + + threadPoolTaskExecutor.submit(() -> { + try { + // 获取内存使用率(MYSQL) + log.info("Mysql memory: " + memoryUsed(connection)); + perfVO.setMemoryUsed(memoryUsed(connection)); + } finally { + countDownLatch.countDown(); + } + }); + + threadPoolTaskExecutor.submit(() -> { + try { + // 获取表空间使用率(MYSQL) + log.info("Mysql table space: " + tableSpaceUsed(connection)); + perfVO.setTableSpaceUsed(tableSpaceUsed(connection)); + } finally { + countDownLatch.countDown(); + } + }); + + try { + // 此时线程会被挂起,它会等待直到countDownLatch值为0才继续执行 + countDownLatch.await(); + // 上报Mysql监控指标 + sendPerfData(perfVO); + } catch (InterruptedException e) { + log.error("waiting for thread to be interrupted", e); + throw new OpsException("monitor error"); + } + } + + /** + * monitorOpenGauss + * + * @param monitorEntity monitorEntity + */ + public void monitorOpenGauss (MonitorEntity monitorEntity) { + // 创建同步队列,并设置初始计数器值为3 + CountDownLatch countDownLatch = new CountDownLatch(3); + Connection connection = monitorEntity.getSqlConnection(); + + PerfVO perfVO = new PerfVO(); + perfVO.setNodeId(monitorEntity.getNodeId()); + perfVO.setType(monitorEntity.getType()); + perfVO.setDbType(monitorEntity.getDbType()); + + threadPoolTaskExecutor.submit(() -> { + try { + // 获取锁数量 + log.info("OpenGauss lock num: " + lock(connection)); + perfVO.setLockNum(lock(connection)); + } finally { + countDownLatch.countDown(); + } + }); + + threadPoolTaskExecutor.submit(() -> { + try { + // 获取会话数 + log.info("OpenGauss session num: " + session(connection)); + perfVO.setSessionNum(session(connection)); + } finally { + countDownLatch.countDown(); + } + }); + + threadPoolTaskExecutor.submit(() -> { + try { + // 获取连接数 + perfVO.setConnNum(connectNum(connection)); + } finally { + countDownLatch.countDown(); + } + }); + + try { + // 此时线程会被挂起,它会等待直到countDownLatch值为0才继续执行 + countDownLatch.await(); + // 上报openGauss监控指标 + sendPerfData(perfVO); + } catch (InterruptedException e) { + log.error("waiting for thread to be interrupted", e); + throw new OpsException("monitor error"); + } + } + + /** + * 获取表空间使用率 (Mysql) + * + * @param connection connection + * @return tableSpaceUsed + */ + private String tableSpaceUsed(Connection connection) { + String sql = "SELECT SUM( table_schema_size.table_schema_size ) AS 'tableSpaceUsed' FROM ( SELECT table_schema, SUM( data_length + index_length ) AS table_schema_size FROM information_schema.TABLES GROUP BY table_schema ) table_schema_size"; + try (PreparedStatement preparedStatement = connection.prepareStatement(sql); + ResultSet resultSet = preparedStatement.executeQuery()) { + + if (resultSet.next()) { + return resultSet.getString("tableSpaceUsed"); + } + } catch (SQLException e) { + log.error("Failed to get tablespace", e); + } + + throw new OpsException("Failed to get tablespace"); + } + + /** + * 获取内存使用率 (MYSQL) + * + * @param connection connection + * @return memoryUsed + */ + private String memoryUsed(Connection connection) { + String sql = "SELECT (@@key_buffer_size + @@innodb_buffer_pool_size + @@innodb_log_buffer_size + @@max_connections * ( @@read_buffer_size + @@read_rnd_buffer_size + @@sort_buffer_size + @@join_buffer_size + @@binlog_cache_size + @@thread_stack + @@tmp_table_size )) AS 'memoryUsed'"; + + try (PreparedStatement preparedStatement = connection.prepareStatement(sql); + ResultSet resultSet = preparedStatement.executeQuery()) { + + if (resultSet.next()) { + return resultSet.getString("memoryUsed"); + } + } catch (SQLException e) { + log.error("Failed to get memoryUsed", e); + } + + throw new OpsException("Failed to get memoryUsed"); + } + + /** + * TPS = (Com_commit+Com_rollback)/Uptime (Mysql) + * + * @param connection connection + * @return tps + */ + private String tps(Connection connection) { + String commitSql = "show global status like 'Com_commit'"; + String rollbackSql = "show global status like 'Com_rollback'"; + String uptimeSql = "show global status like 'Uptime'"; + + try (PreparedStatement commitPreparedStatement = connection.prepareStatement(commitSql); + PreparedStatement rollbackPreparedStatement = connection.prepareStatement(rollbackSql); + PreparedStatement uptimePreparedStatement = connection.prepareStatement(uptimeSql); + ResultSet commitResultSet = commitPreparedStatement.executeQuery(); + ResultSet rollbackResultSet = rollbackPreparedStatement.executeQuery(); + ResultSet uptimeResultSet = uptimePreparedStatement.executeQuery()) { + + if (commitResultSet.next() && rollbackResultSet.next() && uptimeResultSet.next()) { + long commit = commitResultSet.getLong("Value"); + long rollback = rollbackResultSet.getLong("Value"); + long uptime = uptimeResultSet.getLong("Value"); + + return Long.valueOf((commit + rollback) / uptime).toString(); + } + } catch (SQLException e) { + log.error("Failed to get tps", e); + } + throw new OpsException("Failed to get tps"); + } + + /** + * QPS = Questions/Uptime (Mysql) + * + * @param connection connection + * @return QPS + */ + private String qps(Connection connection) { + String questionsSql = "show global status like 'Questions'"; + String uptimeSql = "show global status like 'Uptime'"; + + try (PreparedStatement questionsPreparedStatement = connection.prepareStatement(questionsSql); + PreparedStatement uptimePreparedStatement = connection.prepareStatement(uptimeSql); + ResultSet questionsResultSet = questionsPreparedStatement.executeQuery(); + ResultSet uptimeResultSet = uptimePreparedStatement.executeQuery()) { + + if (questionsResultSet.next() && uptimeResultSet.next()) { + long questions = questionsResultSet.getLong("Value"); + long uptime = uptimeResultSet.getLong("Value"); + + return Long.valueOf(questions / uptime).toString(); + } + } catch (SQLException e) { + log.error("Failed to get qps", e); + } + throw new OpsException("Failed to get qps"); + } + + /** + * connNum获取连接数 (Mysql) + * + * @param connection connection + * @return connNum + */ + private String connNum(Connection connection) { + String sql = "SHOW STATUS LIKE 'Threads_connected'"; + try (PreparedStatement preparedStatement = connection.prepareStatement(sql); + ResultSet resultSet = preparedStatement.executeQuery()) { + + if (resultSet.next()) { + return resultSet.getString("Value"); + } + } catch (SQLException e) { + log.error("Failed to get connection number", e); + } + + throw new OpsException("Failed to get connection number"); + } + + /** + * role获取主备信息 (Mysql) + * + * @param connection connection + * @return role + */ + private String role(Connection connection) { + String sql = "SHOW SLAVE STATUS"; + try (PreparedStatement preparedStatement = connection.prepareStatement(sql); + ResultSet resultSet = preparedStatement.executeQuery()) { + + if (resultSet.next()) { + return "SLAVE"; + } else { + return "MASTER"; + } + } catch (SQLException e) { + log.error("Failed to get role", e); + } + + throw new OpsException("Failed to get role"); + } + + /** + * 获取磁盘使用率 (Host) + * + * @param rootSession rootSession + * @return diskMonitor + */ + private String diskMonitor(Session rootSession) { + String command = "df -Th | egrep -v \"(tmpfs|sr0)\" | tail -n +2|tr -s \" \" | cut -d \" \" -f6|tr -d \"%\"|head -n 1"; + try { + JschResult jschResult = jschUtil.executeCommand(command, rootSession); + if (jschResult.getExitCode() == 0) { + return jschResult.getResult(); + } else { + log.error("disk monitor error,exitCode:{},exitMsg:{}", jschResult.getExitCode(), jschResult.getResult()); + return ""; + } + } catch (IOException | InterruptedException e) { + throw new OpsException("disk monitor error"); + } + } + + /** + * 内存使用率 (Host) + * + * @param rootSession rootSession + * @return memoryMonitor + */ + private String memoryMonitor(Session rootSession) { + String command = "free -m | awk -F '[ :]+' 'NR==2{printf \"%d\", ($2-$7)/$2*100}'"; + try { + JschResult jschResult = jschUtil.executeCommand(command, rootSession); + if (jschResult.getExitCode() == 0) { + return jschResult.getResult(); + } else { + log.error("memory monitor error,exitCode:{},exitMsg:{}", jschResult.getExitCode(), jschResult.getResult()); + return ""; + } + } catch (IOException | InterruptedException e) { + throw new OpsException("memory monitor error"); + } + } + + /** + * 获取cpu使用率 (Host) + * + * @param rootSession rootSession + * @return cpuMonitor + */ + private String cpuMonitor(Session rootSession) { + String command = "top -b -n1 | fgrep \"Cpu(s)\" | tail -1 | awk -F'id,' '{split($1, vs, \",\"); v=vs[length(vs)]; sub(/\\s+/, \"\", v);sub(/\\s+/, \"\", v); printf \"%d\", 100-v;}'"; + try { + JschResult jschResult = jschUtil.executeCommand(command, rootSession); + if (jschResult.getExitCode() == 0) { + return jschResult.getResult(); + } else { + log.error("cpu monitor error,exitCode:{},exitMsg:{}", jschResult.getExitCode(), jschResult.getResult()); + return ""; + } + } catch (IOException | InterruptedException e) { + throw new OpsException("cpu monitor error"); + } + } + + /** + * 获取网卡吞吐量 (Host) + * + * @param rootSession rootSession + * @return netMonitor + */ + private String[] netMonitor(Session rootSession) { + String[] res = new String[2]; + + String netCardName; + String netCardNameCommand = "cat /proc/net/dev | awk '{i++; if(i>2){print $1}}' | sed 's/^[\\t]*//g' | sed 's/[:]*$//g' | head -n 1"; + try { + JschResult jschResult = jschUtil.executeCommand(netCardNameCommand, rootSession); + if (jschResult.getExitCode() == 0) { + netCardName = jschResult.getResult().trim(); + } else { + log.error("Failed to get network card name,exitCode:{},exitMsg:{}", jschResult.getExitCode(), jschResult.getResult()); + throw new OpsException("Failed to get network card name"); + } + } catch (IOException | InterruptedException e) { + throw new OpsException(e.getMessage()); + } + + String command = "rx_net1=$(ifconfig " + netCardName + " | awk '/RX packets/{print $5}') && tx_net1=$(ifconfig " + netCardName + " | awk '/TX packets/{print $5}') && sleep 1 && rx_net2=$(ifconfig " + netCardName + " | awk '/RX packets/{print $5}') && tx_net2=$(ifconfig " + netCardName + " | awk '/TX packets/{print $5}') && rx_net=$[($rx_net2-$rx_net1)] && tx_net=$[($tx_net2-$tx_net1)] && echo \"$rx_net|$tx_net\""; + try { + JschResult jschResult = jschUtil.executeCommand(command, rootSession); + if (jschResult.getExitCode() == 0) { + String[] split = jschResult.getResult().split("\\|"); + res[0] = split[0]; + res[1] = split[1]; + return res; + } else { + log.error("cpu monitor error,exitCode:{},exitMsg:{}", jschResult.getExitCode(), jschResult.getResult()); + res[0] = ""; + res[1] = ""; + return res; + } + } catch (IOException | InterruptedException e) { + throw new OpsException("cpu monitor error"); + } + } + + /** + * 锁数量 (openGauss) + * + * @param connection connection + * @return lock + */ + private String lock(Connection connection) { + String sql = "SELECT count(*) FROM pg_locks"; + String res = null; + try (Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery(sql)) { + if (resultSet.next()) { + res = resultSet.getString("count"); + } + } catch (SQLException e) { + throw new OpsException(e.getMessage()); + } + + return res; + } + + /** + * 会话数 (openGauss) + * + * @param connection connection + * @return session + */ + public String session(Connection connection) { + String sql = "SELECT count(*) FROM pg_stat_activity"; + String res = null; + try (Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery(sql)) { + if (resultSet.next()) { + res = resultSet.getString("count"); + } + } catch (SQLException e) { + throw new OpsException(e.getMessage()); + } + + return res; + } + + /** + * 连接数 (openGauss) + * + * @param connection connection + * @return connectNum + */ + public String connectNum(Connection connection) { + String sql = "SELECT count(*) FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS s"; + String res = null; + try (Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery(sql)) { + if (resultSet.next()) { + res = resultSet.getString("count"); + } + } catch (SQLException e) { + throw new OpsException(e.getMessage()); + } + + return res; + } + + /** + * sendPerfData(上报数据) + * + * @param perfVO perfVO + */ + private void sendPerfData(PerfVO perfVO) { + List perfVOList = new ArrayList<>(); + perfVOList.add(perfVO); + PerfData perfData = new PerfData(); + perfData.setAgentId(agentId); + perfData.setPerfVOList(perfVOList); + if (serverUrl.contains("https")) { + HttpsClicent.doJsonPost(serverUrl, JSONObject.toJSONString(perfData)); + } else if (serverUrl.contains("http")) { + HttpUtils.sendPost(serverUrl, JSONObject.toJSONString(perfData)); + } + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/HttpUtils.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/HttpUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..bc46a5e4685e2ffa4133ddf66b2766c29534ab1f --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/HttpUtils.java @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * HttpUtils.java + * + * IDENTIFICATION + * openGauss-visualtool/visualtool-common/src/main/java/org/opengauss/admin/common/utils/http/HttpUtils.java + * + * ------------------------------------------------------------------------- + */ + + +package org.opengauss.admin.agent.util; + +import cn.hutool.core.collection.CollUtil; +import lombok.Data; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; + +import javax.net.ssl.*; +import java.io.*; +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.Map; + +/** + * Http Tool + * + * @author xielibo + */ +public class HttpUtils { + private static final Logger log = LoggerFactory.getLogger(HttpUtils.class); + + /** + * sendGet + * + * @param url URL + * @param param param,like name1=value1&name2=value2. + */ + public static String sendGet(String url, String param) { + return sendGet(url, param, "UTF-8"); + } + + /** + * sendGet + * + * @param url URL + * @param param param,like name1=value1&name2=value2. + * @param contentType contentType + */ + public static String sendGet(String url, String param, String contentType) { + StringBuilder result = new StringBuilder(); + BufferedReader in = null; + InputStreamReader isr = null; + try { + String urlNameString = url + "?" + param; + log.info("sendGet - {}", urlNameString); + URL realUrl = new URL(urlNameString); + URLConnection connection = realUrl.openConnection(); + connection.setRequestProperty("accept", "*/*"); + connection.setRequestProperty("connection", "Keep-Alive"); + connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + connection.connect(); + isr = new InputStreamReader(connection.getInputStream(), contentType); + in = new BufferedReader(isr); + String line; + while ((line = in.readLine()) != null) { + result.append(line); + } + log.info("recv - {}", result); + } catch (ConnectException e) { + log.error("sendGet ConnectException, url=" + url + ",param=" + param, e); + } catch (SocketTimeoutException e) { + log.error("sendGet SocketTimeoutException, url=" + url + ",param=" + param, e); + } catch (IOException e) { + log.error("sendGet IOException, url=" + url + ",param=" + param, e); + } catch (Exception e) { + log.error("sendGet Exception, url=" + url + ",param=" + param, e); + } finally { + try { + if (in != null) { + in.close(); + } + } catch (IOException ex) { + log.error("close Exception, url=" + url + ",param=" + param, ex); + } + if (isr != null) { + try { + isr.close(); + } catch (IOException e) { + log.error("close input stream reader failed: " + e.getMessage()); + } + } + } + return result.toString(); + } + + /** + * sendPost + * + * @param url URL + * @param param param,like name1=value1&name2=value2. + */ + public static PostResponse sendPost(String url, String param) { + PrintWriter out = null; + BufferedReader in = null; + StringBuilder result = new StringBuilder(); + PostResponse response = new PostResponse(); + InputStreamReader isr = null; + try { + log.info("sendPost - {}", url); + URL realUrl = new URL(url); + if (realUrl.openConnection() instanceof HttpURLConnection) { + HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection(); + conn.setRequestProperty(HttpHeaders.ACCEPT, "*/*"); + conn.setRequestProperty(HttpHeaders.CONNECTION, "Keep-Alive"); + conn.setRequestProperty(HttpHeaders.USER_AGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + conn.setRequestProperty(HttpHeaders.ACCEPT_CHARSET, "utf-8"); + conn.setRequestProperty(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + conn.setRequestMethod(HttpMethod.POST.name()); + conn.setConnectTimeout(0); + conn.setReadTimeout(0); + conn.setDoOutput(true); + conn.setDoInput(true); + out = new PrintWriter(conn.getOutputStream()); + out.print(param); + out.flush(); + isr = new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8); + in = new BufferedReader(isr); + String line; + while ((line = in.readLine()) != null) { + result.append(line); + } + response.setBody(result.toString()); + response.setHeaders(conn.getHeaderFields()); + log.info("recv - {}", result); + } + + } catch (ConnectException e) { + log.error("sendPost ConnectException, url=" + url + ",param=" + param, e); + } catch (SocketTimeoutException e) { + log.error("sendPost SocketTimeoutException, url=" + url + ",param=" + param, e); + } catch (IOException e) { + log.error("sendPost IOException, url=" + url + ",param=" + param, e); + } catch (Exception e) { + log.error("sendPost Exception, url=" + url + ",param=" + param, e); + } finally { + try { + if (out != null) { + out.close(); + } + if (in != null) { + in.close(); + } + if (isr != null) { + isr.close(); + } + } catch (IOException ex) { + log.error("close Exception, url=" + url + ",param=" + param, ex); + } + } + return response; + } + + public static String sendSslPost(String url, String param) { + StringBuilder result = new StringBuilder(); + String urlNameString = url + "?" + param; + InputStreamReader isr = null; + try { + log.info("sendSSLPost - {}", urlNameString); + SSLContext sc = SSLContext.getInstance("SSL"); + sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom()); + URL console = new URL(urlNameString); + if (console.openConnection() instanceof HttpsURLConnection) { + HttpsURLConnection conn = (HttpsURLConnection) console.openConnection(); + conn.setRequestProperty("accept", "*/*"); + conn.setRequestProperty("connection", "Keep-Alive"); + conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); + conn.setRequestProperty("Accept-Charset", "utf-8"); + conn.setRequestProperty("contentType", "utf-8"); + conn.setDoOutput(true); + conn.setDoInput(true); + conn.setSSLSocketFactory(sc.getSocketFactory()); + conn.setHostnameVerifier(new TrustAnyHostnameVerifier()); + conn.connect(); + InputStream is = conn.getInputStream(); + isr = new InputStreamReader(is, StandardCharsets.UTF_8); + BufferedReader br = new BufferedReader(isr); + String ret = ""; + while ((ret = br.readLine()) != null) { + if (ret != null && !"".equals(ret.trim())) { + result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8")); + } + } + log.info("recv - {}", result); + conn.disconnect(); + br.close(); + } + + } catch (ConnectException e) { + log.error("sendSSLPost ConnectException, url=" + url + ",param=" + param, e); + } catch (SocketTimeoutException e) { + log.error("sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e); + } catch (IOException e) { + log.error("sendSSLPost IOException, url=" + url + ",param=" + param, e); + } catch (Exception e) { + log.error("sendSSLPost Exception, url=" + url + ",param=" + param, e); + } finally { + if (isr != null) { + try { + isr.close(); + } catch (IOException e) { + log.error("close input stream reader failed: " + e.getMessage()); + } + } + } + return result.toString(); + } + + private static class TrustAnyTrustManager implements X509TrustManager { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[]{}; + } + } + + private static class TrustAnyHostnameVerifier implements HostnameVerifier { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + } + + @Data + public static class PostResponse { + private String body; + private Map> headers; + + public String getHeader(String key) { + if (CollUtil.isEmpty(headers)) { + return ""; + } + List value = headers.get(key); + if (CollUtil.isEmpty(value)) { + return ""; + } + return value.get(0); + } + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/HttpsClicent.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/HttpsClicent.java new file mode 100644 index 0000000000000000000000000000000000000000..ddf0bebfd61ba5b3f32b611abf95468692cd47ad --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/HttpsClicent.java @@ -0,0 +1,110 @@ +package org.opengauss.admin.agent.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.*; +import java.io.*; +import java.net.URL; + +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +public class HttpsClicent { + private static final Logger logger = LoggerFactory.getLogger(HttpsClicent.class); + private static final class DefaultTrustManager implements X509TrustManager { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + } + public static HttpsURLConnection getHttpsURLConnection(String uri, String method) throws IOException { + SSLContext ctx = null; + try { + ctx = SSLContext.getInstance("TLS"); + ctx.init(new KeyManager[0], new TrustManager[] { new DefaultTrustManager() }, new SecureRandom()); + } catch (KeyManagementException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + SSLSocketFactory ssf = ctx.getSocketFactory(); + URL url = new URL(uri); + if (url.openConnection() instanceof HttpsURLConnection) { + HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection(); + httpsConn.setSSLSocketFactory(ssf); + httpsConn.setHostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String arg0, SSLSession arg1) { + return true; + } + }); + httpsConn.setRequestMethod(method); + httpsConn.setDoInput(true); + httpsConn.setDoOutput(true); + httpsConn.setConnectTimeout(4000); + if(method.equals("POST")){ + httpsConn.setRequestProperty("Content-Type", "application/json; charset=utf-8"); + } + return httpsConn; + } else { + throw new IOException("cast "); + } + + } + public static byte[] getBytesFromStream(InputStream is) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] kb = new byte[1024]; + int len; + while ((len = is.read(kb)) != -1) { + baos.write(kb, 0, len); + } + byte[] bytes = baos.toByteArray(); + baos.close(); + is.close(); + return bytes; + } + + private static void setBytesToStream(OutputStream os, byte[] bytes) throws IOException { + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + byte[] kb = new byte[1024]; + int len; + while ((len = bais.read(kb)) != -1) { + os.write(kb, 0, len); + } + os.flush(); + os.close(); + bais.close(); + } + private static String doGet(String uri) { + try { + HttpsURLConnection httpsConn = getHttpsURLConnection(uri, "GET"); + return new String(getBytesFromStream(httpsConn.getInputStream())); + } catch (IOException e) { + logger.error("http Get error:", e.getCause()); + } + return ""; + } + + public static String doJsonPost(String uri, String data) { + try { + HttpsURLConnection httpsConn = getHttpsURLConnection(uri, "POST"); + setBytesToStream(httpsConn.getOutputStream(), data.getBytes("utf-8")); + return new String(getBytesFromStream(httpsConn.getInputStream())); + } catch (IOException e){ + logger.error("http Posy error:", e); + } + return ""; + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/JdbcUtil.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/JdbcUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..ef79ab5b21731f25b877e906d0669027ece59c31 --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/JdbcUtil.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * JdbcUtil.java + * + * IDENTIFICATION + * openGauss-visualtool/visualtool-common/src/main/java/org/opengauss/admin/common/utils/ops/JdbcUtil.java + * + * ------------------------------------------------------------------------- + */ + + +package org.opengauss.admin.agent.util; + +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; +import org.opengauss.admin.agent.domain.model.ops.jdbc.JdbcInfo; +import org.opengauss.admin.agent.enums.ops.DbTypeEnum; +import org.opengauss.admin.agent.exception.ops.OpsException; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author lhf + * @date 2023/1/13 13:43 + **/ +@Slf4j +public class JdbcUtil { + private static Pattern p = Pattern.compile("jdbc:(?\\w+):.*((//)|@)(?.+):(?\\d+)"); + + public static JdbcInfo parseUrl(String url) { + if (StrUtil.isEmpty(url)) { + throw new OpsException("JDBC URL information does not exist"); + } + + JdbcInfo jdbcInfo = new JdbcInfo(); + + Matcher m = p.matcher(url); + if (m.find()) { + String dbType = m.group("dbType"); + if (StrUtil.isEmpty(dbType)) { + throw new OpsException("Error parsing JDBC URL, database type not found"); + } + jdbcInfo.setDbType(DbTypeEnum.typeOf(dbType)); + + String ip = m.group("ip"); + if (StrUtil.isEmpty(ip)) { + throw new OpsException("Error parsing JDBC URL, database ip not found"); + } + jdbcInfo.setIp(ip); + + String port = m.group("port"); + if (StrUtil.isEmpty(port)) { + throw new OpsException("Error parsing JDBC URL, database port not found"); + } + jdbcInfo.setPort(port); + } + + return jdbcInfo; + } + + public static Connection getConnection(String url, String username, String password) { + Connection connection = null; + try { + JdbcInfo jdbcInfo = parseUrl(url); + Class.forName(jdbcInfo.getDbType().getDriverClass()); + connection = DriverManager.getConnection(url, username, password); + } catch (SQLException | ClassNotFoundException e) { + log.error("jdbc failed to get connection", e); + throw new OpsException("jdbc failed to get connection"); + } + return connection; + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/JschUtil.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/JschUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..bdf2ddcd94e75082a74c32c3fe2e0cb3cd52b6fd --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/JschUtil.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * ------------------------------------------------------------------------- + * + * JschUtil.java + * + * IDENTIFICATION + * openGauss-visualtool/visualtool-common/src/main/java/org/opengauss/admin/common/utils/ops/JschUtil.java + * + * ------------------------------------------------------------------------- + */ + + +package org.opengauss.admin.agent.util; + +import cn.hutool.core.collection.CollUtil; +import com.jcraft.jsch.*; +import lombok.extern.slf4j.Slf4j; +import org.opengauss.admin.agent.domain.model.ops.JschResult; +import org.opengauss.admin.agent.exception.ops.OpsException; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.*; + +/** + * Jsch Tools + * + * @author lhf + * @date 2022/6/13 15:18 + * @since 1.0 + **/ +@Slf4j +@Component +public class JschUtil { + private static final int SESSION_TIMEOUT = 10000; + private static final int CHANNEL_TIMEOUT = 50000; + + /** + * Acquiring a Session + * + * @param host host + * @param port port + * @param username username + * @param password password + * @return ssh session + */ + public Optional getSession(String host, Integer port, String username, String password) { + log.info("host:{},port:{},username:{}", host, port, username); + return createSession(host, port, username, password); + } + + /** + * ChannelExec + * + * @param command Instructions to execute + * @param session session + * @return SSH Result + * @throws IOException IO Exception + * @throws InterruptedException Interrupted Exception + */ + public JschResult executeCommand(String command, Session session) throws IOException, InterruptedException { + return executeCommand(command, session, null); + } + + /** + * ChannelExec + * + * @param command Instructions to execute + * @param session session + * @param autoResponse autoResponse + * @return SSH Result + * @throws IOException IO Exception + * @throws InterruptedException Interrupted Exception + */ + public JschResult executeCommand(String command, Session session, Map autoResponse) + throws IOException, InterruptedException { + log.info("Execute an order{}", command); + + ChannelExec channel = null; + try { + Channel exeChannel = session.openChannel("exec"); + if (exeChannel instanceof ChannelExec) { + channel = (ChannelExec) exeChannel; + } + channel.setPtyType("dump"); + channel.setPty(true); + } catch (JSchException e) { + log.error("Obtaining the exec channel fails:", e); + throw new OpsException("Obtaining the exec channel fails"); + } + + channel.setCommand(command); + try { + channel.connect(CHANNEL_TIMEOUT); + } catch (JSchException e) { + log.error("Execute instruction [{}] exception:", command, e); + throw new OpsException("Command execution exception"); + } + + return buildJschResult(channel, autoResponse); + } + + /** + * ChannelShell Creates a session + * + * @param host host + * @param port port + * @param username username + * @param password password + * @return SSH session + */ + private Optional createSession(String host, Integer port, String username, String password) { + JSch jSch = new JSch(); + Session session = null; + try { + session = jSch.getSession(username, host, port); + session.setPassword(password); + session.setConfig("StrictHostKeyChecking", "no"); + session.connect(SESSION_TIMEOUT); + } catch (JSchException e) { + log.error("Connection establishment fail:", e); + session = null; + } + + return Optional.ofNullable(session); + } + + private JschResult buildJschResult(ChannelExec channelExec, Map autoResponse) + throws IOException, InterruptedException { + JschResult jschResult = new JschResult(); + StringBuilder resultStrBuilder = new StringBuilder(); + // The output of the script execution is an input stream to the program + InputStream in = channelExec.getInputStream(); + OutputStream out = channelExec.getOutputStream(); + // Read the input stream from the remote host and get the script execution results + byte[] tmp = new byte[1024]; + while (true) { + while (in.available() > 0) { + int len = in.read(tmp, 0, 1024); + if (len < 0) { + break; + } + + String msg = new String(tmp, 0, len, StandardCharsets.UTF_8); + + resultStrBuilder.append(msg); + } + + if (channelExec.isClosed()) { + if (in.available() > 0) { + continue; + } + in.close(); + out.close(); + + int exitStatus = channelExec.getExitStatus(); + jschResult.setExitCode(exitStatus); + + break; + } + + sleep(); + + autoResponse(autoResponse, resultStrBuilder, out); + } + + channelExec.disconnect(); + jschResult.setResult(resultStrBuilder.toString().trim()); + return jschResult; + } + + private void autoResponse(Map autoResponse, + StringBuilder resultStrBuilder, OutputStream out) { + if (CollUtil.isNotEmpty(autoResponse)) { + autoResponse.forEach((k, v) -> { + if (resultStrBuilder.toString().trim().endsWith(k.trim())) { + try { + out.write((v.trim() + System.getProperty("line.separator")).getBytes(StandardCharsets.UTF_8)); + out.flush(); + resultStrBuilder.append(v.trim() + System.getProperty("line.separator")); + } catch (IOException e) { + log.error("Automatic response exception", e); + } + } + }); + } + } + + private void sleep() throws InterruptedException { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + throw new InterruptedException(); + } + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/StringUtils.java b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/StringUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..92ae83292dd0c5494f486dd3ce36037e18fef049 --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/java/org/opengauss/admin/agent/util/StringUtils.java @@ -0,0 +1,357 @@ +/** + Copyright ewem. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +package org.opengauss.admin.agent.util; + +import org.springframework.util.AntPathMatcher; + +import java.util.*; + +/** + * string tools + * + * @author xielibo + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils { + private static final String NULLSTR = ""; + + private static final char SEPARATOR = '_'; + + /** + * get parameter is not null + * + */ + public static T nvl(T value, T defaultValue) { + return value != null ? value : defaultValue; + } + + /** + * * Determine whether a Collection is empty, including List, Set, Queue + * + */ + public static boolean isEmpty(Collection coll) { + return isNull(coll) || coll.isEmpty(); + } + + /** + * * Determine whether a Collection is not empty, including List, Set, Queue + * + */ + public static boolean isNotEmpty(Collection coll) { + return !isEmpty(coll); + } + + /** + * * Check if an array of objects is empty + * + */ + public static boolean isEmpty(Object[] objects) { + return isNull(objects) || (objects.length == 0); + } + + /** + * * Check if an array of objects is empty + * + */ + public static boolean isNotEmpty(Object[] objects) { + return !isEmpty(objects); + } + + /** + * * Determine whether a Map is empty + * + */ + public static boolean isEmpty(Map map) { + return isNull(map) || map.isEmpty(); + } + + /** + * * Determine whether a Map is empty + * + */ + public static boolean isNotEmpty(Map map) { + return !isEmpty(map); + } + + /** + * * Check if a string is empty + * + */ + public static boolean isEmpty(String str) { + return isNull(str) || NULLSTR.equals(str.trim()); + } + + /** + * * Check if a string is empty + * + */ + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + + /** + * * Check if an object is empty + * + */ + public static boolean isNull(Object object) { + return object == null; + } + + /** + * * Check if an object is empty + * + */ + public static boolean isNotNull(Object object) { + return !isNull(object); + } + + /** + * * Determine whether an object is an array type (Java basic type array) + * + */ + public static boolean isArray(Object object) { + return isNotNull(object) && object.getClass().isArray(); + } + + /** + * trim + */ + public static String trim(String str) { + return (str == null ? "" : str.trim()); + } + + /** + * substring + * + */ + public static String substring(final String str, int start) { + if (str == null) { + return NULLSTR; + } + + if (start < 0) { + start = str.length() + start; + } + + if (start < 0) { + start = 0; + } + if (start > str.length()) { + return NULLSTR; + } + + return str.substring(start); + } + + /** + * substring + * + */ + public static String substring(final String str, int start, int end) { + if (str == null) { + return NULLSTR; + } + + if (end < 0) { + end = str.length() + end; + } + if (start < 0) { + start = str.length() + start; + } + + if (end > str.length()) { + end = str.length(); + } + + if (start > end) { + return NULLSTR; + } + + if (start < 0) { + start = 0; + } + if (end < 0) { + end = 0; + } + + return str.substring(start, end); + } + + + /** + * string to list + * + */ + public static final List str2List(String str, String sep, boolean filterBlank, boolean trim) { + List list = new ArrayList(); + if (StringUtils.isEmpty(str)) { + return list; + } + + if (filterBlank && StringUtils.isBlank(str)) { + return list; + } + String[] split = str.split(sep); + for (String string : split) { + if (filterBlank && StringUtils.isBlank(string)) { + continue; + } + if (trim) { + string = string.trim(); + } + list.add(string); + } + + return list; + } + + + /** + * toUnderScoreCase + */ + public static String toUnderScoreCase(String str) { + if (str == null) { + return NULLSTR; + } + StringBuilder sb = new StringBuilder(); + boolean preCharIsUpperCase = true; + boolean curreCharIsUpperCase = true; + boolean nexteCharIsUpperCase = true; + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + if (i > 0) { + preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); + } else { + preCharIsUpperCase = false; + } + + curreCharIsUpperCase = Character.isUpperCase(c); + + if (i < (str.length() - 1)) { + nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); + } + + if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) { + sb.append(SEPARATOR); + } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) { + sb.append(SEPARATOR); + } + sb.append(Character.toLowerCase(c)); + } + return sb.toString(); + } + + /** + * inStringIgnoreCase + */ + public static boolean inStringIgnoreCase(String str, String... strs) { + if (str != null && strs != null) { + for (String s : strs) { + if (str.equalsIgnoreCase(trim(s))) { + return true; + } + } + } + return false; + } + + /** + * Convert underscore-capitalized strings to camel case. Returns an empty string if the underscore-capitalized string before conversion is empty. For example: HELLO_WORLD->HelloWorld + * + */ + public static String convertToCamelCase(String name) { + StringBuilder result = new StringBuilder(); + if (name == null || name.isEmpty()) { + return ""; + } else if (!name.contains("_")) { + return name.substring(0, 1).toUpperCase(Locale.ENGLISH) + name.substring(1); + } + String[] camels = name.split("_"); + for (String camel : camels) { + if (camel.isEmpty()) { + continue; + } + result.append(camel.substring(0, 1).toUpperCase(Locale.ENGLISH)); + result.append(camel.substring(1).toLowerCase(Locale.ENGLISH)); + } + return result.toString(); + } + + /** + * CamelCase example:user_name->userName + */ + public static String toCamelCase(String s) { + if (s == null) { + return NULLSTR; + } + s = s.toLowerCase(Locale.ENGLISH); + StringBuilder sb = new StringBuilder(s.length()); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + + if (c == SEPARATOR) { + upperCase = true; + } else if (upperCase) { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } else { + sb.append(c); + } + } + return sb.toString(); + } + + /** + * Finds whether the specified string matches any string in the specified string list + * + */ + public static boolean matches(String str, List strs) { + if (isEmpty(str) || isEmpty(strs)) { + return false; + } + for (String pattern : strs) { + if (isMatch(pattern, str)) { + return true; + } + } + return false; + } + + /** + * Determine whether the url matches the rule configuration: + * ? represents a single character; + * Indicates any character string within a layer path, and cannot cross layers; + * Indicates any layer path; + * + * @return + */ + public static boolean isMatch(String pattern, String url) { + AntPathMatcher matcher = new AntPathMatcher(); + return matcher.match(pattern, url); + } + + @SuppressWarnings("unchecked") + public static T cast(Object obj) { + return (T) obj; + } + + public static boolean checkNotEmpty(String str) { + if (str == null || "".equals(str)) { + return false; + } + return true; + } +} diff --git a/openGauss-datakit/datakit-agent/src/main/resources/application.yml b/openGauss-datakit/datakit-agent/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..d1368ccd04a38a11da5c472f7424500f8fb6716c --- /dev/null +++ b/openGauss-datakit/datakit-agent/src/main/resources/application.yml @@ -0,0 +1,25 @@ +server: + port: 9495 + servlet: + context-path: / + tomcat: + uri-encoding: UTF-8 + max-threads: 800 + min-spare-threads: 30 + +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + username: root + password: 123456 + url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8 + + messages: + basename: i18n/messages + servlet: + multipart: + max-file-size: 20GB + max-request-size: 20GB + mvc: + async: + request-timeout: 60000 diff --git a/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/AdminApplication.java b/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/AdminApplication.java index 045db0b012fa0eeb79ae92b7ca90107e6ef883d0..b8783b3e5377a987c9871beaffce669e995def4c 100644 --- a/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/AdminApplication.java +++ b/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/AdminApplication.java @@ -30,6 +30,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.context.annotation.Bean; +import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.context.request.RequestContextListener; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @@ -38,6 +39,7 @@ import org.springframework.web.socket.server.standard.ServerEndpointExporter; * * @author xielibo */ +@EnableScheduling @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class AdminApplication implements SpringBootstrap { diff --git a/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/AgentController.java b/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/AgentController.java new file mode 100644 index 0000000000000000000000000000000000000000..92db39231c4972db648e03bac66d26c494d3bc31 --- /dev/null +++ b/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/AgentController.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.opengauss.admin.web.controller.ops; + +import cn.hutool.core.thread.ThreadUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.opengauss.admin.common.core.handler.ops.cache.WsConnectorManager; +import org.opengauss.admin.common.exception.ops.OpsException; +import org.opengauss.admin.system.service.ops.IWsService; +import org.opengauss.admin.system.service.ops.AgentService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.config.annotation.EnableWebSocket; + +import javax.websocket.*; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.PrintWriter; +import java.io.StringWriter; + +@Slf4j +@Component +@EnableWebSocket +@ServerEndpoint("/agentws/{businessId}") +public class AgentController { + + + private final WsConnectorManager wsConnectorManager; + +// @Autowired + private AgentService agentService; + + private static IWsService wsService; + + public AgentController() { + wsConnectorManager = new WsConnectorManager(); + agentService = new AgentService(); + } + + @Autowired + public void setWsService(IWsService wsService) { + AgentController.wsService = wsService; + } + + @OnOpen + public void onOpen(Session session, @PathParam("businessId") String businessId) { + log.info("install-ws onOpen, businessId:{}", businessId); + wsService.onOpen(businessId, session); + } + + @OnClose + public void onClose(@PathParam("businessId") String businessId) { + log.info("install-ws onOpen, businessId:{}", businessId); + wsService.onClose(businessId); + } + + @OnError + public void onError(@PathParam("businessId") String businessId, Throwable error) { + log.error("install-ws onError, businessId:{}, err", businessId, error); + } + + @OnMessage(maxMessageSize = 10 * 1024 * 1024) + public void onMessage(@PathParam("businessId") String businessId, String message) { + + ThreadUtil.execute(() -> { + try { + JSONObject obj = JSONUtil.parseObj(message); + var session = wsConnectorManager.getSession(businessId) + .orElseThrow(() -> new RuntimeException("websocket session not exist")); + switch (obj.getStr("key")) { + case "install": + agentService.install(session, obj.getStr("hostId"), obj.getStr("path"), obj.getStr("agentVersion"), obj.getInt("agentPort")); + break; + case "uninstall": + agentService.uninstall(session, obj.getStr("hostId"), obj.getStr("path"), obj.getStr("agentVersion")); + break; + case "restart": + agentService.restart(session, obj.getStr("hostId"), obj.getStr("path"), obj.getStr("agentVersion"), obj.getInt("agentPort")); + break; + case "upgrade": + agentService.upgrade(session, obj.getStr("hostId"), obj.getStr("path"), obj.getStr("agentVersion"), obj.getInt("agentPort")); + break; + default: { + log.info("Invalid parameter {}", obj.getStr("key")); + } + } + } catch (OpsException e) { + var sw = new StringWriter(); + try (var pw = new PrintWriter(sw);) { + e.printStackTrace(pw); + } + log.info("install-ws onMessage,businessId:{},message:{}", businessId, message); + wsService.onMessage(businessId, message); + } + }); + } +} diff --git a/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/AgentMngController.java b/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/AgentMngController.java new file mode 100644 index 0000000000000000000000000000000000000000..20017f27d9c0c1802ade8e1df208ff68ecc1d40d --- /dev/null +++ b/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/AgentMngController.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.opengauss.admin.web.controller.ops; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.opengauss.admin.common.core.controller.BaseController; +import org.opengauss.admin.common.core.domain.AjaxResult; +import org.opengauss.admin.common.core.domain.entity.ops.OpsAgentEntity; +import org.opengauss.admin.common.core.domain.model.ops.agent.AgentVO; +import org.opengauss.admin.common.core.domain.model.ops.agent.CfgVO; +import org.opengauss.admin.common.core.domain.model.ops.agent.PerfData; +import org.opengauss.admin.common.core.page.TableDataInfo; +import org.opengauss.admin.system.service.ops.IAgentMngService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Objects; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@RestController +@RequestMapping("/agent") +public class AgentMngController extends BaseController { + + @Autowired + private IAgentMngService agentMngService; + + /** + * 增加Agent + **/ + @PostMapping("/add") + public AjaxResult add(@RequestBody @Validated AgentVO agentVO) { + if (Objects.isNull(agentVO)) { + return AjaxResult.error(); + } + String hostId = agentVO.getHostId(); + boolean agent = agentMngService.checkAgentByHostId(hostId); + if (agent) { + return AjaxResult.error("This agent has Existed"); + } + boolean res = agentMngService.add(agentVO); + return res ? AjaxResult.success() : AjaxResult.error("Failed to add agent"); + } + + /** + * 删除Agent + **/ + @DeleteMapping("/{agentId}") + public AjaxResult del(@PathVariable String agentId) { + //删除该agent对应的Host配置 + agentMngService.removeHostCfgByAgentId(agentId); + //删除该agent对应的DB配置 + agentMngService.removeClusterNodeCfgByAgentId(agentId); + //删除agent + boolean del = agentMngService.removeAgentByAgentId(agentId); + return del? AjaxResult.success() : AjaxResult.error("Failed to delete agent"); + } + + /** + * 修改Agent + **/ + @PostMapping("/edit") + public AjaxResult edit(@RequestBody @Validated AgentVO agentVO) { + if (Objects.isNull(agentVO)) { + return AjaxResult.error(); + } + boolean edit = agentMngService.edit(agentVO); + return edit ? AjaxResult.success() : AjaxResult.error("Failed to edit agent"); + } + + /** + * 获取Agent列表 + **/ + @GetMapping("/listAll") + public AjaxResult listAll() { + List agentList = agentMngService.listAll(); + return AjaxResult.success(agentList); + } + + /** + * 分页显示agent,并可根据name,ip进行过滤 + **/ + @GetMapping("/page") + public TableDataInfo page(@RequestParam(value = "name",required = false) String name, + @RequestParam(value = "ip",required = false) String ip, + @RequestParam(value = "version",required = false) String version) { + IPage page = agentMngService.pageAgent(startPage(), name, ip, version); + return getDataTable(page); + } + + /** + * 根据hostId获取Agent详细信息 + **/ + @GetMapping("/getInfo") + public AjaxResult getAgentByHostId(@RequestParam(value = "hostId",required = false) String hostId) { + OpsAgentEntity agentEntity = agentMngService.getByHostId(hostId); + return AjaxResult.success("success", agentEntity); + } + + /** + * 根据hostId检查是否已安装过Agent + **/ + @GetMapping("/check") + public AjaxResult checkAgentByHostId(@RequestParam(value = "hostId",required = false) String hostId) { + boolean res = agentMngService.checkAgentByHostId(hostId); + return res ? AjaxResult.success("success", res) : AjaxResult.error(); + } + + /** + * 根据agentId获取agent链路状态 + **/ + @GetMapping("/linkStatus") + public AjaxResult getLinkStatusByAgentId(@RequestParam(value = "agentId",required = false) String agentId) { + boolean res = agentMngService.getLinkStatusByAgentId(agentId); + return AjaxResult.success("success", res); + } + + /** + * 根据agentId获取agent监管配置 + **/ + @GetMapping("/getCfg/{agentId}") + public AjaxResult getCfg(@PathVariable String agentId) { + List cfg = agentMngService.getCfg(agentId); + if (Objects.isNull(cfg)) { + AjaxResult.error(); + } + return AjaxResult.success("success", cfg); + } + + /** + * 根据agentId检测其连通性 + **/ + @GetMapping("/ping") + public AjaxResult pingAgent(@RequestParam(value = "agentId",required = false) String agentId) { + return AjaxResult.success(agentMngService.pingAgent(agentId)); + } + + /** + * 根据ip分发该agent的监管配置给远端agent + **/ + @GetMapping("/distributeCFG") + public AjaxResult distributeCFG(@RequestParam(value = "ip",required = false) String ip) { + boolean res = agentMngService.distributeCFGByIP(ip); + return res ? AjaxResult.success() : AjaxResult.error(); + } + + /** + * 接收来自远端agent上报的指标数据 + **/ + @PostMapping("/data") + @ResponseBody + public AjaxResult perfData(@RequestBody PerfData data) { + boolean res = agentMngService.updatePerfData(data); + return res ? AjaxResult.success() : AjaxResult.error(); + } +} diff --git a/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/AgentVersionMngController.java b/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/AgentVersionMngController.java new file mode 100644 index 0000000000000000000000000000000000000000..74ab154a4016def4b11635f43ba6ba5ebea1b36c --- /dev/null +++ b/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/AgentVersionMngController.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.opengauss.admin.web.controller.ops; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.opengauss.admin.common.core.controller.BaseController; +import org.opengauss.admin.common.core.domain.AjaxResult; +import org.opengauss.admin.common.core.domain.entity.ops.OpsAgentVersionEntity; +import org.opengauss.admin.common.core.domain.model.ops.agent.AgentVersionVO; +import org.opengauss.admin.common.core.page.TableDataInfo; +import org.opengauss.admin.common.exception.file.InvalidExtensionException; +import org.opengauss.admin.system.service.ops.IAgentVersionMngService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@RestController +@RequestMapping("/version") +public class AgentVersionMngController extends BaseController { + @Autowired + private IAgentVersionMngService agentVersionMngService; + + /** + * agent jar包上传,并保存相关数据到数据库中 + */ + @PostMapping("/upload") + public AjaxResult upload(@RequestParam("file") MultipartFile file) { + boolean res; + try { + res = agentVersionMngService.upload(file); + } catch (IOException e) { + return AjaxResult.error("Upload fail"); + } catch (InvalidExtensionException e) { + return AjaxResult.error("The package type is illegal, the correct type is jar"); + } catch (RuntimeException e) { + return AjaxResult.error(e.getMessage()); + } + + return res ? AjaxResult.success() : AjaxResult.error(); + } + + /** + * agent jar包上传,并保存相关数据到数据库中 + */ + @GetMapping("/listAll") + public AjaxResult listAll() { + List list = agentVersionMngService.listAll(); + return AjaxResult.success(list); + } + + /** + * 分页显示agent版本信息,并可根据agentVersion进行过滤 + **/ + @GetMapping("/page") + public TableDataInfo page(@RequestParam(value = "version",required = false) String version) { + IPage page = agentVersionMngService.pageAgentVersion(startPage(), version); + return getDataTable(page); + } + +} diff --git a/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/HostController.java b/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/HostController.java index 1eff716c65bec4650e26fa53259c0e94be2c3a4d..d8472312c7a96d584d47a42b4baf5bb6e0bc0550 100644 --- a/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/HostController.java +++ b/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/HostController.java @@ -55,8 +55,7 @@ public class HostController extends BaseController { @PostMapping public AjaxResult add(@RequestBody @Validated HostBody hostBody) { - hostService.add(hostBody); - return AjaxResult.success(); + return AjaxResult.success("success",hostService.add(hostBody)); } @GetMapping("/listAll") @@ -109,7 +108,7 @@ public class HostController extends BaseController { } @GetMapping("/monitor") - public AjaxResult monitor(@RequestParam String hostId, @RequestParam String businessId, @RequestParam(value = "rootPassword",required = false) String rootPassword){ - return AjaxResult.success(hostService.monitor(hostId,businessId,rootPassword)); + public AjaxResult monitor(@RequestParam String hostId, @RequestParam String businessId){ + return AjaxResult.success(hostService.perfHostMonitor(hostId,businessId)); } } diff --git a/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/JdbcDbClusterNodeController.java b/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/JdbcDbClusterNodeController.java index 76f231f5fa3c9506a8801cc4f55fba65d91e3b46..72edd51b207ccff48d3261c11a5645935031cb65 100644 --- a/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/JdbcDbClusterNodeController.java +++ b/openGauss-datakit/visualtool-api/src/main/java/org/opengauss/admin/web/controller/ops/JdbcDbClusterNodeController.java @@ -67,7 +67,7 @@ public class JdbcDbClusterNodeController extends BaseController { @GetMapping("/monitor/{clusterNodeId}") public AjaxResult monitor(@PathVariable("clusterNodeId") String clusterNodeId,@RequestParam("businessId") String businessId){ - return AjaxResult.success(opsJdbcDbClusterNodeService.monitor(clusterNodeId,businessId)); + return AjaxResult.success(opsJdbcDbClusterNodeService.perfDbMonitor(clusterNodeId,businessId)); } } diff --git a/openGauss-datakit/visualtool-api/src/main/resources/db/openGauss-visualtool.sql b/openGauss-datakit/visualtool-api/src/main/resources/db/openGauss-visualtool.sql index 3ec2ab2a89a74ea8fad2ab7fffcef904166eb83b..22424818774c0fe2fc1d042dc18e0734c4c40d9b 100644 --- a/openGauss-datakit/visualtool-api/src/main/resources/db/openGauss-visualtool.sql +++ b/openGauss-datakit/visualtool-api/src/main/resources/db/openGauss-visualtool.sql @@ -428,6 +428,80 @@ SELECT add_host_user_field_func(); DROP FUNCTION add_host_user_field_func; +-- ---------------------------- +-- Table structure for ops_agent +-- ---------------------------- +CREATE TABLE IF NOT EXISTS "public"."ops_agent" ( + "agent_id" int8 NOT NULL, + "agent_name" varchar(255) COLLATE "pg_catalog"."default", + "agent_version" varchar(255) COLLATE "pg_catalog"."default", + "port" int2, + "install_path" varchar(255) COLLATE "pg_catalog"."default", + "is_alive" bool NOT NULL DEFAULT false, + "last_heart_beat_time" timestamp(6), + "remark" varchar(255) COLLATE "pg_catalog"."default", + "host_id" int8, + "server_url" varchar(255) COLLATE "pg_catalog"."default", + "create_by" varchar(64) COLLATE "pg_catalog"."default", + "create_time" timestamp(6), + "update_by" varchar(64) COLLATE "pg_catalog"."default", + "update_time" timestamp(6) +) +; +COMMENT ON COLUMN "public"."ops_agent"."agent_id" IS 'Agent ID'; +COMMENT ON COLUMN "public"."ops_agent"."agent_name" IS 'Agent名称'; +COMMENT ON COLUMN "public"."ops_agent"."agent_version" IS 'Agent版本'; +COMMENT ON COLUMN "public"."ops_agent"."port" IS 'Agent端口'; +COMMENT ON COLUMN "public"."ops_agent"."install_path" IS 'Agent安装路径'; +COMMENT ON COLUMN "public"."ops_agent"."is_alive" IS 'Agent链路状态'; +COMMENT ON COLUMN "public"."ops_agent"."last_heart_beat_time" IS 'Agent最近一次心跳时间'; +COMMENT ON COLUMN "public"."ops_agent"."remark" IS '备注'; +COMMENT ON COLUMN "public"."ops_agent"."host_id" IS '主机ID'; +COMMENT ON COLUMN "public"."ops_agent"."server_url" IS '服务端URL'; +COMMENT ON COLUMN "public"."ops_agent"."create_by" IS '创建者'; +COMMENT ON COLUMN "public"."ops_agent"."create_time" IS '创建时间'; +COMMENT ON COLUMN "public"."ops_agent"."update_by" IS '更新者'; +COMMENT ON COLUMN "public"."ops_agent"."update_time" IS '更新时间'; + +-- ---------------------------- +-- Table structure for ops_agent_version +-- ---------------------------- +CREATE TABLE IF NOT EXISTS "public"."ops_agent_version" ( + "version_id" int8 NOT NULL, + "jar_name" varchar(50) COLLATE "pg_catalog"."default", + "version" varchar(10) COLLATE "pg_catalog"."default", + "path" varchar(100) COLLATE "pg_catalog"."default", + "remark" varchar(100) COLLATE "pg_catalog"."default" +) +; +COMMENT ON COLUMN "public"."ops_agent_version"."version_id" IS 'Agent版本ID'; +COMMENT ON COLUMN "public"."ops_agent_version"."jar_name" IS 'Agent安装包名'; +COMMENT ON COLUMN "public"."ops_agent_version"."version" IS 'Agent版本'; +COMMENT ON COLUMN "public"."ops_agent_version"."path" IS '安装包路径'; +COMMENT ON COLUMN "public"."ops_agent_version"."remark" IS '备注'; + +-- ---------------------------- +-- Table structure for ops_agent_mng_host +-- ---------------------------- +CREATE TABLE IF NOT EXISTS "public"."ops_agent_mng_host" ( + "agent_id" varchar(255) COLLATE "pg_catalog"."default" NOT NULL, + "host_id" varchar(255) COLLATE "pg_catalog"."default" NOT NULL +) +; +COMMENT ON COLUMN "public"."ops_agent_mng_host"."agent_id" IS 'Agent ID'; +COMMENT ON COLUMN "public"."ops_agent_mng_host"."host_id" IS '主机ID'; + +-- ---------------------------- +-- Table structure for ops_agent_mng_cluster_node +-- ---------------------------- +CREATE TABLE IF NOT EXISTS "public"."ops_agent_mng_cluster_node" ( + "agent_id" varchar(255) COLLATE "pg_catalog"."default" NOT NULL, + "cluster_node_id" varchar(255) COLLATE "pg_catalog"."default" NOT NULL +) +; +COMMENT ON COLUMN "public"."ops_agent_mng_cluster_node"."agent_id" IS 'Agent ID'; +COMMENT ON COLUMN "public"."ops_agent_mng_cluster_node"."cluster_node_id" IS '数据库实例NodeID'; + -- ---------------------------- -- Table structure for sys_log_config -- ---------------------------- @@ -1165,6 +1239,7 @@ OR REPLACE FUNCTION init_data_fuc() RETURNS integer AS 'BEGIN NOT EXISTS (select 1 from "public"."sys_menu") THEN INSERT INTO "public"."sys_menu" ("menu_id", "menu_name", "parent_id", "order_num", "path", "component", "query", "is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon", "create_by", "create_time", "update_by", "update_time", "remark", "open_way", "plugin_id", "open_position", "query_template", "plugin_theme", "menu_classify", "menu_en_name") VALUES (2, ''资源中心'', 0, 2, ''/resource'', NULL, NULL, 1, 0, ''M'', ''0'', ''0'', NULL, ''resource'', ''admin'', ''2022-10-10 22:16:07.030737'', NULL, NULL, NULL, 1, NULL, 1, NULL, NULL, 1, ''Resources''); + INSERT INTO "public"."sys_menu" ("menu_id", "menu_name", "parent_id", "order_num", "path", "component", "query", "is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon", "create_by", "create_time", "update_by", "update_time", "remark", "open_way", "plugin_id", "open_position", "query_template", "plugin_theme", "menu_classify", "menu_en_name") VALUES (3, ''Agent管理'', 0, 3, ''/agent/manager'', ''agent/manager/index'', NULL, 1, 0, ''C'', ''0'', ''0'', NULL, ''resource'', ''admin'', ''2022-10-10 22:16:07.030737'', NULL, NULL, NULL, 1, NULL, 1, NULL, NULL, 1, ''Agent Manager''); INSERT INTO "public"."sys_menu" ("menu_id", "menu_name", "parent_id", "order_num", "path", "component", "query", "is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon", "create_by", "create_time", "update_by", "update_time", "remark", "open_way", "plugin_id", "open_position", "query_template", "plugin_theme", "menu_classify", "menu_en_name") VALUES (5, ''插件管理'', 0, 5, ''/plugin/manage'', ''plugin/manage/index'', NULL, 1, 0, ''C'', ''0'', ''0'', NULL, ''plugin'', ''admin'', ''2022-10-10 22:16:07.030737'', NULL, NULL, NULL, 1, NULL, 1, NULL, NULL, 2, ''Plugins''); INSERT INTO "public"."sys_menu" ("menu_id", "menu_name", "parent_id", "order_num", "path", "component", "query", "is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon", "create_by", "create_time", "update_by", "update_time", "remark", "open_way", "plugin_id", "open_position", "query_template", "plugin_theme", "menu_classify", "menu_en_name") VALUES (6, ''安全中心'', 0, 6, ''/security'', NULL, NULL, 1, 0, ''M'', ''0'', ''0'', NULL, ''security'', ''admin'', ''2022-10-10 22:16:07.030737'', NULL, NULL, NULL, 1, NULL, 1, NULL, NULL, 2, ''Security''); INSERT INTO "public"."sys_menu" ("menu_id", "menu_name", "parent_id", "order_num", "path", "component", "query", "is_frame", "is_cache", "menu_type", "visible", "status", "perms", "icon", "create_by", "create_time", "update_by", "update_time", "remark", "open_way", "plugin_id", "open_position", "query_template", "plugin_theme", "menu_classify", "menu_en_name") VALUES (7, ''日志中心'', 0, 7, ''/logs'', NULL, NULL, 1, 0, ''M'', ''0'', ''0'', NULL, ''logs'', ''admin'', ''2022-11-23 20:54:36.439'', NULL, NULL, NULL, 1, NULL, 1, NULL, NULL, 2, ''Logs''); @@ -1321,7 +1396,9 @@ IF ( SELECT COUNT ( * ) AS ct1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ''ops_host'' AND COLUMN_NAME = ''os'' ) = 0 THEN ALTER TABLE ops_host ADD COLUMN os varchar(255); +ALTER TABLE ops_host ADD COLUMN os_version varchar(255); COMMENT ON COLUMN "public"."ops_host"."os" IS ''操作系统''; +COMMENT ON COLUMN "public"."ops_host"."os_version" IS ''操作系统版本''; END IF; IF ( SELECT COUNT ( * ) AS ct1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ''ops_host'' AND COLUMN_NAME = ''cpu_arch'' ) = 0 diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsAgentEntity.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsAgentEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..04c5f56e142daa7180541739bd8c5d99f596ad03 --- /dev/null +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsAgentEntity.java @@ -0,0 +1,27 @@ +package org.opengauss.admin.common.core.domain.entity.ops; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import org.opengauss.admin.common.core.domain.BaseEntity; + +import java.util.Date; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Data +@TableName("ops_agent") +public class OpsAgentEntity extends BaseEntity { + @TableId + private String agentId; + private String agentName; + private String hostId; + private String agentVersion; + private Integer port; + private String installPath; + private Boolean isAlive; + private Date lastHeartBeatTime; + private String serverUrl; +} diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsAgentMngClusterNodeEntity.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsAgentMngClusterNodeEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..66b11415146e73075dfb0bd3221ebf1bcb56a211 --- /dev/null +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsAgentMngClusterNodeEntity.java @@ -0,0 +1,16 @@ +package org.opengauss.admin.common.core.domain.entity.ops; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Data +@TableName("ops_agent_mng_cluster_node") +public class OpsAgentMngClusterNodeEntity { + private Integer isValid; + private String agentId; + private String clusterNodeId; +} diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsAgentMngHostEntity.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsAgentMngHostEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..04965760ac698245fa04583e095b3b57314b576f --- /dev/null +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsAgentMngHostEntity.java @@ -0,0 +1,16 @@ +package org.opengauss.admin.common.core.domain.entity.ops; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Data +@TableName("ops_agent_mng_host") +public class OpsAgentMngHostEntity { + private Integer isValid; + private String agentId; + private String hostId; +} diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsAgentVersionEntity.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsAgentVersionEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..bf48f9972abfd9a7c453de067f1070ffbc679e51 --- /dev/null +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsAgentVersionEntity.java @@ -0,0 +1,20 @@ +package org.opengauss.admin.common.core.domain.entity.ops; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Data +@TableName("ops_agent_version") +public class OpsAgentVersionEntity { + @TableId + private String versionId; + private String jarName; + private String version; + private String path; + private String remark; +} diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsHostEntity.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsHostEntity.java index 5aff9abab78e56e5d088fe28ade81cb80b69fa81..9dd8c508a0ccbff9eca26b1c72de1b5b1ced1eba 100644 --- a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsHostEntity.java +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/entity/ops/OpsHostEntity.java @@ -46,6 +46,7 @@ public class OpsHostEntity extends BaseEntity { private String publicIp; private Integer port; private String os; + private String osVersion; private String cpuArch; @TableField(exist = false) private Boolean isRemember; diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/HostBody.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/HostBody.java index e6b0399e4d79e16964efae328268d0d53af9fb8b..d6d543dc5c354bc200a737a0df70ba3964fad574 100644 --- a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/HostBody.java +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/HostBody.java @@ -55,7 +55,7 @@ public class HostBody { private List tags; private String username; - public OpsHostEntity toHostEntity(String hostName,String os,String cpuArch) { + public OpsHostEntity toHostEntity(String hostName,String os,String osVersion,String cpuArch) { OpsHostEntity hostEntity = new OpsHostEntity(); hostEntity.setPublicIp(publicIp); hostEntity.setPrivateIp(privateIp); @@ -63,6 +63,7 @@ public class HostBody { hostEntity.setHostname(hostName); hostEntity.setRemark(remark); hostEntity.setOs(os); + hostEntity.setOsVersion(osVersion); hostEntity.setCpuArch(cpuArch); hostEntity.setName(name); return hostEntity; diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/AgentVO.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/AgentVO.java new file mode 100644 index 0000000000000000000000000000000000000000..bb932a8d5d088454ff197e76166dc375ba397585 --- /dev/null +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/AgentVO.java @@ -0,0 +1,44 @@ +package org.opengauss.admin.common.core.domain.model.ops.agent; + +import lombok.Data; +import org.opengauss.admin.common.core.domain.entity.ops.OpsAgentEntity; + +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Data +public class AgentVO { + private String agentId; + private String agentName; + private String ip; + @NotNull + private String hostId; + @NotNull + private String agentVersion; + @NotNull + private Integer port; + private String installPath; + private Boolean isAlive; + private Date lastHeartBeatTime; + private String serverUrl; + private String remark; + + public OpsAgentEntity toAgentEntity() { + OpsAgentEntity agentEntity = new OpsAgentEntity(); + agentEntity.setAgentId(agentId); + agentEntity.setAgentName(agentName); + agentEntity.setHostId(hostId); + agentEntity.setAgentVersion(agentVersion); + agentEntity.setPort(port); + agentEntity.setInstallPath(installPath); + agentEntity.setIsAlive(isAlive); + agentEntity.setLastHeartBeatTime(lastHeartBeatTime); + agentEntity.setServerUrl(serverUrl); + agentEntity.setRemark(remark); + return agentEntity; + } +} diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/AgentVersionVO.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/AgentVersionVO.java new file mode 100644 index 0000000000000000000000000000000000000000..a5fc1a30a50bb005e4f3ae818fc3286155f350ff --- /dev/null +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/AgentVersionVO.java @@ -0,0 +1,27 @@ +package org.opengauss.admin.common.core.domain.model.ops.agent; + +import lombok.Data; +import org.opengauss.admin.common.core.domain.entity.ops.OpsAgentVersionEntity; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Data +public class AgentVersionVO { + private String versionId; + private String jarName; + private String version; + private String path; + private String remark; + + public OpsAgentVersionEntity toAgentVersionEntity() { + OpsAgentVersionEntity agentVersionEntity = new OpsAgentVersionEntity(); + agentVersionEntity.setVersionId(versionId); + agentVersionEntity.setJarName(jarName); + agentVersionEntity.setVersion(version); + agentVersionEntity.setPath(path); + agentVersionEntity.setRemark(remark); + return agentVersionEntity; + } +} diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/CfgData.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/CfgData.java new file mode 100644 index 0000000000000000000000000000000000000000..4cafa9ae95aa409c8560286a5f73c2e79dbe8662 --- /dev/null +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/CfgData.java @@ -0,0 +1,16 @@ +package org.opengauss.admin.common.core.domain.model.ops.agent; + +import lombok.Data; + +import java.util.List; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Data +public class CfgData { + private String agentId; + private String serUrl; + private List cfgVOList; +} diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/CfgVO.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/CfgVO.java new file mode 100644 index 0000000000000000000000000000000000000000..f9e05b6727d26fa4e3f90e1c70f938a7abb0ac9c --- /dev/null +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/CfgVO.java @@ -0,0 +1,29 @@ +package org.opengauss.admin.common.core.domain.model.ops.agent; + +import lombok.Data; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Data +public class CfgVO { + //对应hostId或者clusterNodeId + private String nodeId; + //值为 host 或者 db + private String type; + //如果type为db,该字段有效:为集群名称 + private String clusterName; + //如果type为db,该字段有效:MYSQL 或者 OPENGAUSS + private String dbType; + //IP地址 + private String ip; + //端口号 + private Integer port; + //用户名 + private String user; + //密码 + private String pass; + //数据库url + private String url; +} diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfData.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfData.java new file mode 100644 index 0000000000000000000000000000000000000000..2ed981ec024cac016d81435af7c5b1fd54c3f926 --- /dev/null +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfData.java @@ -0,0 +1,15 @@ +package org.opengauss.admin.common.core.domain.model.ops.agent; + +import lombok.Data; + +import java.util.List; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Data +public class PerfData { + private String agentId; + private List perfVOList; +} diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfHostVO.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfHostVO.java new file mode 100644 index 0000000000000000000000000000000000000000..f99ee358cc18c796ea06fe1d36acb20b3d3b0bd2 --- /dev/null +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfHostVO.java @@ -0,0 +1,21 @@ +package org.opengauss.admin.common.core.domain.model.ops.agent; + +import lombok.Data; + +import java.util.Date; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Data +public class PerfHostVO { + private String hostId; + private String networkUplink; + private String networkDownlink; + private String cpuUsage; + private String memoryUsage; + private String diskUsage; + private String agentId; + private Date updateTime; +} diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfMySqlVO.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfMySqlVO.java new file mode 100644 index 0000000000000000000000000000000000000000..1f6e9be3d22abbf544bbeaced9f5f1121fdad261 --- /dev/null +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfMySqlVO.java @@ -0,0 +1,18 @@ +package org.opengauss.admin.common.core.domain.model.ops.agent; + +import lombok.Data; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Data +public class PerfMySqlVO { + private String hostId; + private String role; + private String qps; + private String tps; + private String connectionNumber; + private String tablespaceOccupy; + private String memoryOccupy; +} diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfOpenGaussVO.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfOpenGaussVO.java new file mode 100644 index 0000000000000000000000000000000000000000..b0639754419cc7885491d7e24e29e0fc624537df --- /dev/null +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfOpenGaussVO.java @@ -0,0 +1,15 @@ +package org.opengauss.admin.common.core.domain.model.ops.agent; + +import lombok.Data; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Data +public class PerfOpenGaussVO { + private String hostId; + private String connectionNumber; + private String session; + private String lock; +} diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfVO.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfVO.java new file mode 100644 index 0000000000000000000000000000000000000000..52654c9a11513f1684e788e665773df70c4958c6 --- /dev/null +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/agent/PerfVO.java @@ -0,0 +1,107 @@ +package org.opengauss.admin.common.core.domain.model.ops.agent; + +import lombok.Data; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Data +public class PerfVO { + // 对应hostId或者clusterNodeId + private String nodeId; + // 需要监控的对象类型,值为 host 或者 db + private String type; + // 如果type为db,该字段有效:MYSQL 或者 OPENGAUSS + private String dbType; + // 网卡流出量 + private String upSpeed; + // 网卡流入量 + private String downSpeed; + // cpu使用率 + private String cpu; + // 内存使用率 + private String memory; + // 磁盘使用率 + private String disk; + // 主备(MYSQL),值为:MASTER or SLAVE or CASCADE + private String role; + // 连接数(MYSQL, openGauss) + private String connNum; + // 每秒请求数,就是说服务器在一秒的时间内处理了多少个请求(MYSQL) + private String qps; + // 吞吐量,每秒处理事务数(MYSQL) + private String tps; + // 内存使用率(MYSQL) + private String memoryUsed; + // 表空间占用(MYSQL) + private String tableSpaceUsed; + // 锁数量(OPENGAUSS) + private String lockNum; + // 会话数(OPENGAUSS) + private String sessionNum; + + public PerfHostVO toHostVO() { + PerfHostVO perfHostVO = new PerfHostVO(); + perfHostVO.setHostId(nodeId); + perfHostVO.setNetworkUplink(upSpeed); + perfHostVO.setNetworkDownlink(downSpeed); + perfHostVO.setCpuUsage(cpu); + perfHostVO.setMemoryUsage(memory); + perfHostVO.setDiskUsage(disk); + return perfHostVO; + } + + public PerfHostVO toHostDefaultVO(String hostId) { + PerfHostVO perfHostVO = new PerfHostVO(); + perfHostVO.setHostId(hostId); + perfHostVO.setNetworkUplink(""); + perfHostVO.setNetworkDownlink(""); + perfHostVO.setCpuUsage(""); + perfHostVO.setMemoryUsage(""); + perfHostVO.setDiskUsage(""); + return perfHostVO; + } + + public PerfMySqlVO toMySqlVO() { + PerfMySqlVO perfMySqlVO = new PerfMySqlVO(); + perfMySqlVO.setHostId(nodeId); + perfMySqlVO.setRole(role); + perfMySqlVO.setQps(qps); + perfMySqlVO.setTps(tps); + perfMySqlVO.setConnectionNumber(connNum); + perfMySqlVO.setTablespaceOccupy(tableSpaceUsed); + perfMySqlVO.setMemoryOccupy(memoryUsed); + return perfMySqlVO; + } + + public PerfMySqlVO toMySqlDefaultVO(String cluterNodeId) { + PerfMySqlVO perfMySqlVO = new PerfMySqlVO(); + perfMySqlVO.setHostId(cluterNodeId); + perfMySqlVO.setRole(""); + perfMySqlVO.setQps(""); + perfMySqlVO.setTps(""); + perfMySqlVO.setConnectionNumber(""); + perfMySqlVO.setTablespaceOccupy(""); + perfMySqlVO.setMemoryOccupy(""); + return perfMySqlVO; + } + + public PerfOpenGaussVO toOpenGaussVO() { + PerfOpenGaussVO perfOpenGaussVO = new PerfOpenGaussVO(); + perfOpenGaussVO.setHostId(nodeId); + perfOpenGaussVO.setConnectionNumber(connNum); + perfOpenGaussVO.setSession(sessionNum); + perfOpenGaussVO.setLock(lockNum); + return perfOpenGaussVO; + } + + public PerfOpenGaussVO toOpenGaussDefaultVO(String clusterNodeId) { + PerfOpenGaussVO perfOpenGaussVO = new PerfOpenGaussVO(); + perfOpenGaussVO.setHostId(clusterNodeId); + perfOpenGaussVO.setConnectionNumber(""); + perfOpenGaussVO.setSession(""); + perfOpenGaussVO.setLock(""); + return perfOpenGaussVO; + } +} diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/host/OpsHostVO.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/host/OpsHostVO.java index 1ec969d584dd891d630aa24ab23d6fd7a087bacd..548c3ea0d833bc0f45026cc1bb45182429d34299 100644 --- a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/host/OpsHostVO.java +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/host/OpsHostVO.java @@ -44,6 +44,7 @@ public class OpsHostVO { private String remark; private Boolean isRemember; private String os; + private String osVersion; private String cpuArch; private String name; private Set tags; diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/jdbc/JdbcDbClusterNodeInputDto.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/jdbc/JdbcDbClusterNodeInputDto.java index f49b6d831c191d139d8afbbb1ea8bb35859eb427..84c9fdafcf43ce1da42a6220f53692bfe68c8032 100644 --- a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/jdbc/JdbcDbClusterNodeInputDto.java +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/jdbc/JdbcDbClusterNodeInputDto.java @@ -33,6 +33,7 @@ import org.opengauss.admin.common.enums.ops.DeployTypeEnum; **/ @Data public class JdbcDbClusterNodeInputDto { + private String agentId; private String name; private String url; private String username; diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/jdbc/JdbcDbClusterNodeVO.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/jdbc/JdbcDbClusterNodeVO.java index 9e964430e267d3ff817fd9bc8e3295aab4c9327a..63a0f2c9207e1e0ab559bf82ebb98e15dc695d83 100644 --- a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/jdbc/JdbcDbClusterNodeVO.java +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/core/domain/model/ops/jdbc/JdbcDbClusterNodeVO.java @@ -33,6 +33,7 @@ import org.opengauss.admin.common.core.domain.entity.ops.OpsJdbcDbClusterNodeEnt **/ @Data public class JdbcDbClusterNodeVO { + private String agentId; private String clusterNodeId; private String name; private String ip; @@ -42,7 +43,7 @@ public class JdbcDbClusterNodeVO { private String url; private String os; - public static JdbcDbClusterNodeVO of(OpsJdbcDbClusterNodeEntity clusterNodeEntity, String os) { + public static JdbcDbClusterNodeVO of(OpsJdbcDbClusterNodeEntity clusterNodeEntity, String os, String agentId) { JdbcDbClusterNodeVO jdbcDbClusterNodeVO = new JdbcDbClusterNodeVO(); jdbcDbClusterNodeVO.setClusterNodeId(clusterNodeEntity.getClusterNodeId()); jdbcDbClusterNodeVO.setName(clusterNodeEntity.getName()); @@ -52,6 +53,7 @@ public class JdbcDbClusterNodeVO { jdbcDbClusterNodeVO.setPassword(clusterNodeEntity.getPassword()); jdbcDbClusterNodeVO.setUrl(clusterNodeEntity.getUrl()); jdbcDbClusterNodeVO.setOs(os); + jdbcDbClusterNodeVO.setAgentId(agentId); return jdbcDbClusterNodeVO; } } diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/file/FileUploadUtils.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/file/FileUploadUtils.java index 91fb4d6b179f2c6c580827a28fa568da70488df5..97929f91f932fda6dc99cf4bda5d49b9cdb92c44 100644 --- a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/file/FileUploadUtils.java +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/file/FileUploadUtils.java @@ -153,6 +153,12 @@ public class FileUploadUtils { public static final String upload(String baseDir, String fileName, MultipartFile file, String[] allowedExtension) throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException, InvalidExtensionException { + File fs = new File(baseDir); + boolean isExist = fs.exists(); + if (!isExist) { + fs.mkdir(); + } + int fileNamelength = file.getOriginalFilename().length(); if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) { throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH); diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/http/HttpUtils.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/http/HttpUtils.java index 7257bb1b86a4c76b22f61ee6b25eb352888eea5d..cecc344514bbab02545ed2ea646247c6f4d1de9c 100644 --- a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/http/HttpUtils.java +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/http/HttpUtils.java @@ -153,12 +153,16 @@ public class HttpUtils { log.info("recv - {}", result); } catch (ConnectException e) { log.error("sendPost ConnectException, url=" + url + ",param=" + param, e); + response.setBody(e.getMessage()); } catch (SocketTimeoutException e) { log.error("sendPost SocketTimeoutException, url=" + url + ",param=" + param, e); + response.setBody(e.getMessage()); } catch (IOException e) { log.error("sendPost IOException, url=" + url + ",param=" + param, e); + response.setBody(e.getMessage()); } catch (Exception e) { log.error("sendPost Exception, url=" + url + ",param=" + param, e); + response.setBody(e.getMessage()); } finally { try { if (out != null) { diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/ops/JschUtil.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/ops/JschUtil.java index 9a0b40c95f282bba89e56508f3b8469a702b23cb..af6bd42d874086fe69f1862e2e194f622458056b 100644 --- a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/ops/JschUtil.java +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/ops/JschUtil.java @@ -88,6 +88,10 @@ public class JschUtil { return executeCommand(command, session, null, null); } + public JschResult execCommand(String command, Session session) throws IOException, InterruptedException { + return execCommand(command, session, null); + } + /** * ChannelExec * @@ -182,6 +186,34 @@ public class JschUtil { return buildJschResult(channel, wsSession, autoResponse); } + + public JschResult execCommand(String command, Session session, WsSession wsSession) throws IOException, InterruptedException { + log.info("Execute an order{}", command); + ChannelExec channel = null; + try { + Channel exeChannel = session.openChannel("exec"); + if (exeChannel instanceof ChannelExec) { + channel = (ChannelExec) exeChannel; + } + channel.setPtyType("dump"); + channel.setPty(true); + } catch (JSchException e) { + log.error("Obtaining the exec channel fails:", e); + throw new OpsException("Obtaining the exec channel fails"); + } + + channel.setCommand(command); + try { + channel.connect(CHANNEL_TIMEOUT); + } catch (JSchException e) { + log.error("Execute instruction [{}] exception:", command, e); + throw new OpsException("Command execution exception"); + } + return execJschResult(channel, wsSession); + + } + + /** * open ChannelShell * @@ -280,6 +312,22 @@ public class JschUtil { log.info("Upload End"); } + public synchronized void upload(Session session, String sourceFilePath, String targetPath) { + log.info("Start uploading {} to {}", sourceFilePath, targetPath); + try { + ChannelSftp channel = null; + Channel sftpChannel = session.openChannel("sftp"); + if (sftpChannel instanceof ChannelSftp) { + channel = (ChannelSftp) sftpChannel; + } + channel.connect(); + channel.put(sourceFilePath, targetPath, ChannelSftp.OVERWRITE); + } catch (JSchException | SftpException e) { + log.error("sftp upload Failure", e); + throw new OpsException("sftp upload Failure"); + } + log.info("Upload End"); + } /** * ChannelShell Creates a session @@ -352,6 +400,38 @@ public class JschUtil { return jschResult; } + private JschResult execJschResult(ChannelExec channelExec, WsSession wsSession) throws IOException, InterruptedException { + JschResult jschResult = new JschResult(); + StringBuilder resultStrBuilder = new StringBuilder(); + // The output of the script execution is an input stream to the program + InputStream in = channelExec.getInputStream(); + + byte[] tmp = new byte[1024]; + + while (in.available() > 0) { + int len = in.read(tmp, 0, 1024); + if (len < 0) { + break; + } + + String msg = new String(tmp, 0, len, StandardCharsets.UTF_8); + + msgToWs(msg, wsSession); + + resultStrBuilder.append(msg); + } + + sleep(); + + + + channelExec.disconnect(); + jschResult.setResult(resultStrBuilder.toString().trim()); + return jschResult; + } + + + private void msgToWs(String msg, WsSession wsSession) throws IOException { if (Objects.nonNull(wsSession) && Objects.nonNull(wsSession.getSession()) && wsSession.getSession().isOpen()) { diff --git a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/ops/WsUtil.java b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/ops/WsUtil.java index cec5293f32c2e6090037fc78a21760caba48eb18..3ad173533f01fb86ca79e8b0c4a79f14f7c76e02 100644 --- a/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/ops/WsUtil.java +++ b/openGauss-datakit/visualtool-common/src/main/java/org/opengauss/admin/common/utils/ops/WsUtil.java @@ -46,6 +46,10 @@ public class WsUtil { @Autowired private WsConnectorManager wsConnectorManager; + public WsUtil() { + wsConnectorManager = new WsConnectorManager(); + } + public void sendText(WsSession wsSession, String message) { if (StrUtil.isEmpty(message)) { return; diff --git a/openGauss-datakit/visualtool-framework/src/main/java/org/opengauss/admin/framework/config/SecurityConfig.java b/openGauss-datakit/visualtool-framework/src/main/java/org/opengauss/admin/framework/config/SecurityConfig.java index 2f49410ac0282aa97715e58b6238d9f80b3fa421..f9e7791212c6a466916fe43c204c8074ae39dd4f 100644 --- a/openGauss-datakit/visualtool-framework/src/main/java/org/opengauss/admin/framework/config/SecurityConfig.java +++ b/openGauss-datakit/visualtool-framework/src/main/java/org/opengauss/admin/framework/config/SecurityConfig.java @@ -118,6 +118,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .antMatchers("/webjars/**").anonymous() .antMatchers("/*/api-docs").anonymous() .antMatchers("/websocket/**").anonymous() + .antMatchers("/agentws/**").anonymous() + .antMatchers("/agent/data").anonymous() .antMatchers("/ws/**").anonymous() .antMatchers("/static-plugin/**").anonymous() .antMatchers("/plugins/observability-sql-diagnosis/sqlDiagnosis/api/open/v1/diagnosisTasks/**").anonymous() diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/base/Step.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/base/Step.java new file mode 100644 index 0000000000000000000000000000000000000000..376f4fe822c041122c441e5b2dd95dca282fbe5d --- /dev/null +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/base/Step.java @@ -0,0 +1,33 @@ +package org.opengauss.admin.system.base; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Accessors(chain = true) +@NoArgsConstructor +public class Step { + String name; + status state = status.TODO; + List msg = new ArrayList<>(); + + public Step(String name) { + this.name = name; + } + + public void add(String e) { + msg.add(e); + } + + public enum status { + TODO, + DOING, + DONE, + SKIP, + ERROR + } +} diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsAgentMngMapper.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsAgentMngMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..634a6561d0680c0c11dc01950abbb68c4c8a7361 --- /dev/null +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsAgentMngMapper.java @@ -0,0 +1,55 @@ +package org.opengauss.admin.system.mapper.ops; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.*; +import org.opengauss.admin.common.core.domain.entity.ops.OpsAgentEntity; +import org.opengauss.admin.common.core.domain.model.ops.agent.AgentVO; +import org.opengauss.admin.common.core.domain.model.ops.agent.CfgVO; + +import java.util.List; + +@Mapper +public interface OpsAgentMngMapper extends BaseMapper { + + boolean edit(OpsAgentEntity agentEntity); + + boolean linkFailure(@Param("agentId") String agentId); + + IPage pageAgent(Page page, @Param("name") String name, @Param("ip") String ip, @Param("agentVersion") String agentVersion); + + List listAll(); + + @Insert("INSERT INTO ops_agent_mng_cluster_node values ( #{agentId}, #{clusterNodeId})") + boolean addDbNodeCfg(@Param("agentId") String agentId, @Param("clusterNodeId") String clusterNodeId); + + @Insert("INSERT INTO ops_agent_mng_host values ( #{agentId}, #{hostId})") + boolean addHostCfg(@Param("agentId") String agentId, @Param("hostId") String hostId); + + @Delete("DELETE FROM ops_agent_mng_host WHERE host_id = #{hostId}") + boolean removeCfgByHostId(@Param("hostId") String hostId); + + @Delete("DELETE FROM ops_agent_mng_host WHERE agent_id = #{agentId}") + boolean removeHostCfgByAgentId(@Param("agentId") String agentId); + + @Select("SELECT agent_id FROM ops_agent_mng_cluster_node WHERE cluster_node_id = #{clusterNodeId}") + String getAgentIdByClusterNodeId(@Param("clusterNodeId") String clusterNodeId); + + @Delete("DELETE FROM ops_agent_mng_cluster_node WHERE cluster_node_id = #{clusterNodeId}") + boolean removeCfgByClusterNodeId(@Param("clusterNodeId") String clusterNodeId); + + @Delete("DELETE FROM ops_agent_mng_cluster_node WHERE agent_id = #{agentId}") + boolean removeClusterNodeCfgByAgentId(@Param("agentId") String agentId); + + @Select("SELECT count(1) FROM ops_agent WHERE host_id = #{hostId}") + boolean checkAgentByHostId(@Param("hostId") String hostId); + + List getHostInfo(@Param("agentId") String agentId); + + List getDbInfo(@Param("agentId") String agentId); + + @Select("SELECT bbb.agent_id FROM (SELECT host_id FROM ops_host WHERE public_ip = #{ip}) as aaa " + + "LEFT JOIN ops_agent as bbb on aaa.host_id = bbb.host_id") + String getAgentIdByIP(@Param("ip") String ip); +} diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsAgentVersionMngMapper.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsAgentVersionMngMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..007b849d488379138cbbe74d71af5d0654e71eaa --- /dev/null +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsAgentVersionMngMapper.java @@ -0,0 +1,19 @@ +package org.opengauss.admin.system.mapper.ops; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.opengauss.admin.common.core.domain.entity.ops.OpsAgentVersionEntity; +import org.opengauss.admin.common.core.domain.model.ops.agent.AgentVersionVO; + +import java.util.List; + +@Mapper +public interface OpsAgentVersionMngMapper extends BaseMapper { + + List listAll(); + + IPage pageAgentVersion(Page page, @Param("agentVersion") String agentVersion); +} diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsHostMapper.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsHostMapper.java index 5190478d24fdfcde8ecf87952b615f76e10a65b4..4c4dd8f0ca5db1539035f888bec4f46162e401d0 100644 --- a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsHostMapper.java +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsHostMapper.java @@ -27,12 +27,11 @@ package org.opengauss.admin.system.mapper.ops; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; -import org.opengauss.admin.common.core.domain.model.ops.host.OpsHostVO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; +import org.opengauss.admin.common.core.domain.model.ops.host.OpsHostVO; -import java.util.List; import java.util.Set; /** diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsJdbcDbClusterNodeMapper.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsJdbcDbClusterNodeMapper.java index 952bfed55afd7e17b340c2b29cd075347fe5629c..1d6c82a5d82bd87d58926d78d9042863b00423fe 100644 --- a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsJdbcDbClusterNodeMapper.java +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/mapper/ops/OpsJdbcDbClusterNodeMapper.java @@ -26,12 +26,19 @@ package org.opengauss.admin.system.mapper.ops; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; import org.opengauss.admin.common.core.domain.entity.ops.OpsJdbcDbClusterNodeEntity; +import java.util.List; + /** * @author lhf * @date 2023/1/13 11:06 **/ @Mapper public interface OpsJdbcDbClusterNodeMapper extends BaseMapper { + + @Select("SELECT * from ops_jdbcdb_cluster_node WHERE cluster_id = #{clusterId}") + List getList(@Param("clusterId") String clusterId); } diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/AgentService.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/AgentService.java new file mode 100644 index 0000000000000000000000000000000000000000..6970a7aef583daf94bf42c9bdac7965070b8b94c --- /dev/null +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/AgentService.java @@ -0,0 +1,416 @@ +package org.opengauss.admin.system.service.ops; + +import cn.hutool.json.JSONUtil; +import com.jcraft.jsch.Session; +import lombok.extern.slf4j.Slf4j; +import org.opengauss.admin.common.core.domain.entity.ops.OpsHostEntity; +import org.opengauss.admin.common.core.domain.model.ops.JschResult; +import org.opengauss.admin.common.core.domain.model.ops.WsSession; +import org.opengauss.admin.common.exception.ops.OpsException; +import org.opengauss.admin.common.utils.ops.JschUtil; +import org.opengauss.admin.common.utils.ops.WsUtil; +import org.opengauss.admin.system.base.Step; +import org.opengauss.admin.system.service.ops.impl.EncryptionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +@Slf4j +@Service +public class AgentService { + + private static IAgentVersionMngService agentVersionMngService; + + // @Autowired + private static IHostService hostService; + + private static IHostUserService hostUserService; + + private static EncryptionUtils encryptionUtils; + + private JschUtil jschUtil; + + private WsUtil wsUtil; + + public AgentService() { + jschUtil = new JschUtil(); + wsUtil = new WsUtil(); + } + + @Autowired + public void setAgentVersionMngService(IAgentVersionMngService agentVersionMngService) { + AgentService.agentVersionMngService = agentVersionMngService; + } + + @Autowired + public void setHostService(IHostService hostService) { + AgentService.hostService = hostService; + } + + @Autowired + public void setHostUserService(IHostUserService hostUserService) { + AgentService.hostUserService = hostUserService; + } + + @Autowired + public void setEncryptionUtils(EncryptionUtils encryptionUtils) { + AgentService.encryptionUtils = encryptionUtils; + } + + public void install(WsSession wsSession, String hostId, String path, String agentVersion, Integer agentPort) { + var steps = Arrays.asList( + new Step("检测安装环境"), + new Step("安装Agent"), + new Step("启动Agent"), + new Step("安装完成") + ); + Session session; + int curr = 0; + try { + OpsHostEntity hostEntity = hostService.getById(hostId); + String password = hostUserService.getRootUserByHostId(hostId).getPassword(); + String agentPackageName = agentVersionMngService.getByVersion(agentVersion).getJarName(); + String sourcePackagePath = agentVersionMngService.getByVersion(agentVersion).getPath(); + String targetPackagePath = path + "/" + agentPackageName; + session = jschUtil.getSession(hostEntity.getPublicIp(), hostEntity.getPort(), "root", encryptionUtils.decrypt(password)) + .orElseThrow(() -> new OpsException("Failed to establish a session with the agent host,root user login failed")); + if (Objects.isNull(session)) { + steps.get(curr).setState(Step.status.ERROR).add("Failed to establish a session with the agent host,root user login failed!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + throw new OpsException("Incorrect password, please enter correct password"); + } + curr = nextStep(wsSession, steps, curr); + + // 检查端口 + String checkPort = "netstat -tuln | grep " + agentPort; + JschResult portResult = jschUtil.executeCommand(checkPort, session); + String checkPortResult = portResult.getResult(); + + // 检查端口时,检查agent所在的服务器时候已经安装net-tools + if (checkPortResult.contains("bash: /usr/bin/netstat: No such file or directory")) { + steps.get(curr).setState(Step.status.ERROR).add("netstat is not available on agent host, please install net-tools on agent host!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error("netstat is not available on agent host, please install net-tools on agent host!"); + throw new OpsException("netstat is not available on agent host, please install net-tools on agent host!"); + } else { + // 已安装net-tools后,检查端口是否可用 + if (checkPortResult.length() == 0) { + log.info("Port " + agentPort + " is available"); + } else { + steps.get(curr).setState(Step.status.ERROR).add("Port " + agentPort + " is not available,please check!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error("Port " + agentPort + " is not available"); + throw new OpsException("Port " + agentPort + " is not available,please check!"); + } + } + + // 检查JDK环境 + String checkJava = "java -version"; + String jdkVersion = "java -version 2>&1 |awk 'NR==1{gsub(/\"/,\"\");print $3}' | awk -F . '{print $1}'"; + JschResult jdkResult = jschUtil.executeCommand(checkJava, session); + String checkJdkResult = jdkResult.getResult(); + String serverIp = hostEntity.getPublicIp(); + if (checkJdkResult.contains("java: command not found")) { + steps.get(curr).setState(Step.status.ERROR).add("Java is not installed on " + serverIp + ", please install jDK 11 or above first!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error("Java is not installed on " + serverIp + ", please install jDK 11 or above first!"); + throw new OpsException("Java is not installed on " + serverIp + ", please install jDK 11 or above first!"); + } else { + JschResult checkJdkVersion = jschUtil.executeCommand(jdkVersion, session); + String jdkVersionResult = checkJdkVersion.getResult(); + int jdkVersionNum = Integer.parseInt(jdkVersionResult); + if (jdkVersionNum < 11) { + steps.get(curr).setState(Step.status.ERROR).add("JDK version is lower than JDK 11 on " + serverIp + ", please install jDK 11 or above first!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error("JDK version is lower than JDK 11 on " + serverIp + ", please install jDK 11 or above first!"); + throw new OpsException("JDK version is lower than JDK 11 on " + serverIp + ", please install jDK 11 or above first!"); + } + } + // 检查agent jar 源文件是否存在,如存在,上传至安装agent的服务器 + File file = new File(sourcePackagePath); + if (file.exists()) { + jschUtil.upload(session, sourcePackagePath, targetPackagePath); + } else { + steps.get(curr).setState(Step.status.ERROR).add(sourcePackagePath + " is not exists,please check!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error(sourcePackagePath + " is not exists,please check!"); + throw new OpsException(sourcePackagePath + " is not exists,please check!"); + } + curr = nextStep(wsSession, steps, curr); + + // 执行agent jar包 + String checkPortCommand = "java -jar /root/" + agentPackageName + " --server.port=" + agentPort; + String command = "nohup java -jar /root/" + agentPackageName + " --server.port=" + agentPort; + String checkProcess = "sleep 5; ps -ef | grep " + agentPackageName + " | grep -v grep"; + + try { + jschUtil.execCommand(command, session); + JschResult jschResult = jschUtil.executeCommand(checkProcess, session); + String processResult = jschResult.getResult(); + if (processResult.contains(checkPortCommand)) { + curr = nextStep(wsSession, steps, curr); + sendMsg(wsSession, steps, curr, Step.status.DONE); + } else { + steps.get(curr).setState(Step.status.ERROR).add(command + " error,please check!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error(command + " error", jschResult.getExitCode(), jschResult.getResult()); + throw new OpsException(command + " error,please check!"); + } + } catch (IOException | InterruptedException e) { + log.error("start agent jar error:", e); + steps.get(curr).setState(Step.status.ERROR).add(e.getMessage()); + } + } catch (OpsException | IOException | InterruptedException e) { + e.printStackTrace(); + } + } + + public void uninstall(WsSession wsSession, String hostId, String path, String agentVersion) { + var steps = Arrays.asList( + new Step("停止agent进程"), + new Step("删除agent安装包"), + new Step("卸载完成") + ); + Session session; + int curr = 0; + try { + OpsHostEntity hostEntity = hostService.getById(hostId); + String password = hostUserService.getRootUserByHostId(hostId).getPassword(); + String agentPackageName = agentVersionMngService.getByVersion(agentVersion).getJarName(); + String targetPackagePath = path + "/" + agentPackageName; + session = jschUtil.getSession(hostEntity.getPublicIp(), hostEntity.getPort(), "root", encryptionUtils.decrypt(password)) + .orElseThrow(() -> new OpsException("Failed to establish a session with the agent host,root user login failed")); + if (Objects.isNull(session)) { + steps.get(curr).setState(Step.status.ERROR).add("Failed to establish a session with the agent host,root user login failed!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + throw new OpsException("Incorrect password, please enter correct password"); + } + // 查询agent进程号,如果有agent进程,先结束进程 + String checkAgentProcess = "pgrep -f " + agentPackageName; + String killProcess = "ps -ef | grep " + agentPackageName + "| grep -v grep | cut -c 9-16 | xargs kill -s 9"; + try { + JschResult jschResult = jschUtil.executeCommand(checkAgentProcess, session); + String processResult = jschResult.getResult(); + if (processResult.length() != 0) { + JschResult killProcessResult = jschUtil.executeCommand(killProcess, session); + if (killProcessResult.getExitCode() != 0) { + steps.get(curr).setState(Step.status.ERROR).add("Failed to kill agent process!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error("Failed to kill agent process!"); + throw new OpsException("Failed to kill agent process!"); + } + } + } catch (IOException | InterruptedException e) { + log.error("Agent still running, please kill agent process!", e); + steps.get(curr).setState(Step.status.ERROR).add("Agent still running, please kill agent process!"); + throw new OpsException("Agent still running, please kill agent process!"); + } + curr = nextStep(wsSession, steps, curr); + sendMsg(wsSession, steps, curr, Step.status.DONE); + + // 卸载安装包 + String removePackage = "rm -f " + targetPackagePath; + JschResult jschResult = jschUtil.executeCommand(removePackage, session); + if (jschResult.getExitCode() != 0) { + steps.get(curr).setState(Step.status.ERROR); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error("Failed to remove " + targetPackagePath, jschResult.getExitCode(), jschResult.getResult()); + throw new OpsException("Failed to remove " + targetPackagePath); + } else { + // 卸载完成 + curr = nextStep(wsSession, steps, curr); + sendMsg(wsSession, steps, curr, Step.status.DONE); + } + } catch (OpsException | IOException | InterruptedException e) { + throw new OpsException(e.getMessage()); + } + } + + public void restart(WsSession wsSession, String hostId, String path, String agentVersion, Integer agentPort) { + var steps = Arrays.asList( + new Step("停止当前agent进程"), + new Step("重新启动jar包"), + new Step("重启完成") + ); + Session session; + int curr = 0; + try { + OpsHostEntity hostEntity = hostService.getById(hostId); + String password = hostUserService.getRootUserByHostId(hostId).getPassword(); + String agentPackageName = agentVersionMngService.getByVersion(agentVersion).getJarName(); + session = jschUtil.getSession(hostEntity.getPublicIp(), hostEntity.getPort(), "root", encryptionUtils.decrypt(password)) + .orElseThrow(() -> new OpsException("Failed to establish a session with the agent host,root user login failed")); + if (Objects.isNull(session)) { + steps.get(curr).setState(Step.status.ERROR).add("Failed to establish a session with the agent host,root user login failed!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + throw new OpsException("Incorrect password, please enter correct password"); + } + + // 查询agent进程号,如果有agent进程,先结束进程 + String checkAgentProcess = "pgrep -f " + agentPackageName; + String killProcess = "ps -ef | grep " + agentPackageName + "| grep -v grep | cut -c 9-16 | xargs kill -s 9"; + try { + JschResult jschResult = jschUtil.executeCommand(checkAgentProcess, session); + String processResult = jschResult.getResult(); + if (processResult.length() != 0) { + JschResult killProcessResult = jschUtil.executeCommand(killProcess, session); + if (killProcessResult.getExitCode() != 0) { + steps.get(curr).setState(Step.status.ERROR).add("Failed to kill agent process!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error("Failed to kill agent process!"); + throw new OpsException("Failed to kill agent process!"); + } + } + } catch (IOException | InterruptedException e) { + log.error("Agent still running, please kill agent process", e); + steps.get(curr).setState(Step.status.ERROR).add("Agent still running, please kill agent process"); + throw new OpsException("Agent still running, please kill agent process"); + } + curr = nextStep(wsSession, steps, curr); + sendMsg(wsSession, steps, curr, Step.status.DONE); + + // 重新执行agent jar包 + // 执行jar包前先检查端口 + String checkPort = "netstat -tuln | grep " + agentPort; + JschResult portResult = jschUtil.executeCommand(checkPort, session); + String checkPortResult = portResult.getResult(); + if (checkPortResult.length() != 0) { + steps.get(curr).setState(Step.status.ERROR).add("Port " + agentPort + " is not available"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error("Port " + agentPort + " is not available"); + throw new OpsException("Port " + agentPort + " is not available,please check!"); + } + + // 执行agent jar包 + String checkPortCommand = "java -jar /root/" + agentPackageName + " --server.port=" + agentPort; + String command = "nohup java -jar /root/" + agentPackageName + " --server.port=" + agentPort; + String checkProcess = "sleep 5; ps -ef | grep " + agentPackageName + " | grep -v grep"; + try { + jschUtil.execCommand(command, session); + JschResult jschResult = jschUtil.executeCommand(checkProcess, session); + String processResult = jschResult.getResult(); + if (processResult.contains(checkPortCommand)) { + curr = nextStep(wsSession, steps, curr); + sendMsg(wsSession, steps, curr, Step.status.DONE); + } else { + steps.get(curr).setState(Step.status.ERROR).add(command + " error,please check!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error(command + " error", jschResult.getExitCode(), jschResult.getResult()); + throw new OpsException(command + " error,please check!"); + } + } catch (IOException | InterruptedException e) { + log.error("start agent jar error:", e); + steps.get(curr).setState(Step.status.ERROR).add("start agent jar error, please check!"); + } + } catch (OpsException | IOException | InterruptedException e) { + throw new OpsException(e.getMessage()); + } + } + + public void upgrade(WsSession wsSession, String hostId, String path, String agentVersion, Integer agentPort) { + var steps = Arrays.asList( + new Step("上传升级包"), + new Step("停止agent进程"), + new Step("启动升级后Agent"), + new Step("完成升级") + ); + Session session; + int curr = 0; + try { + OpsHostEntity hostEntity = hostService.getById(hostId); + String password = hostUserService.getRootUserByHostId(hostId).getPassword(); + String agentPackageName = agentVersionMngService.getByVersion(agentVersion).getJarName(); + String sourcePackagePath = agentVersionMngService.getByVersion(agentVersion).getPath(); + String targetPackagePath = path + "/" + agentPackageName; + session = jschUtil.getSession(hostEntity.getPublicIp(), hostEntity.getPort(), "root", encryptionUtils.decrypt(password)) + .orElseThrow(() -> new OpsException("Failed to establish a session with the agent host,root user login failed")); + if (Objects.isNull(session)) { + steps.get(curr).setState(Step.status.ERROR).add("Failed to establish a session with the agent host,root user login failed!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + throw new OpsException("Incorrect password, please enter correct password"); + } + + // 上传升级包 + File file = new File(sourcePackagePath); + if (file.exists()) { + jschUtil.upload(session, sourcePackagePath, targetPackagePath); + } else { + steps.get(curr).setState(Step.status.ERROR).add(sourcePackagePath + "is not exists,please check!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error(sourcePackagePath + "is not exists,please check!"); + throw new OpsException(sourcePackagePath + "is not exists,please check!"); + } + curr = nextStep(wsSession, steps, curr); + + // 查询agent进程号,如果有agent进程,先结束进程 + String checkAgentProcess = "pgrep -f DataKit-platform-agent-"; + String killProcess = "ps -ef | grep DataKit-platform-agent- | grep -v grep | cut -c 9-16 | xargs kill -s 9"; + try { + JschResult jschResult = jschUtil.executeCommand(checkAgentProcess, session); + String processResult = jschResult.getResult(); + if (processResult.length() != 0) { + try { + JschResult killProcessResult = jschUtil.executeCommand(killProcess, session); + if (killProcessResult.getExitCode() != 0) { + steps.get(curr).setState(Step.status.ERROR).add("Failed to kill agent process"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error("Failed to kill agent process {} : {}", killProcessResult.getExitCode(), killProcessResult.getResult()); + throw new OpsException("Failed to kill agent process"); + } + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + steps.get(curr).setState(Step.status.ERROR).add(e.getMessage()); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + } + } + } catch (IOException | InterruptedException e) { + log.error("Agent still running, please kill agent process", e); + steps.get(curr).setState(Step.status.ERROR).add(e.getMessage()); + throw new OpsException("Agent still running, please kill agent process"); + } + curr = nextStep(wsSession, steps, curr); + sendMsg(wsSession, steps, curr, Step.status.DONE); + + // 启动升级后Agent + String checkPortCommand = "java -jar /root/" + agentPackageName + " --server.port=" + agentPort; + String command = "nohup java -jar /root/" + agentPackageName + " --server.port=" + agentPort; + String checkProcess = "sleep 5; ps -ef | grep " + agentPackageName + " | grep -v grep"; + try { + jschUtil.execCommand(command, session); + JschResult jschResult = jschUtil.executeCommand(checkProcess, session); + String processResult = jschResult.getResult(); + if (processResult.contains(checkPortCommand)) { + curr = nextStep(wsSession, steps, curr); + sendMsg(wsSession, steps, curr, Step.status.DONE); + } else { + steps.get(curr).setState(Step.status.ERROR).add(command + " error,please check!"); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + log.error(command + " error", jschResult.getExitCode(), jschResult.getResult()); + throw new OpsException(command + " error,please check!"); + } + } catch (IOException | InterruptedException e) { + log.error("start agent jar error:", e); + steps.get(curr).setState(Step.status.ERROR).add(e.getMessage()); + } + } catch (OpsException e) { + e.printStackTrace(); + } + } + + private int nextStep(WsSession wsSession, List steps, int curr) { + steps.get(curr).setState(Step.status.DONE); + curr++; + sendMsg(wsSession, steps, curr, Step.status.DOING); + return curr; + } + + private synchronized void sendMsg(WsSession wsSession, List steps, int curr, Step.status state) { + steps.get(curr).setState(state); + wsUtil.sendText(wsSession, JSONUtil.toJsonStr(steps)); + } +} diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IAgentMngService.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IAgentMngService.java new file mode 100644 index 0000000000000000000000000000000000000000..582e4e5e0491146e2aece8920d3a3569e72c15fb --- /dev/null +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IAgentMngService.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + + +package org.opengauss.admin.system.service.ops; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.opengauss.admin.common.core.domain.entity.ops.OpsAgentEntity; +import org.opengauss.admin.common.core.domain.model.ops.agent.*; + +import java.util.List; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +public interface IAgentMngService { + /** + * Install agent + */ + boolean add(AgentVO agentVO); + + boolean edit(AgentVO agentVO); + + boolean addDbNodeCfg(String agentId, String clusterNodeId); + + boolean addHostCfg(String agentId, String hostId); + + List listAll(); + + IPage pageAgent(Page page, String name, String ip, String version); + + List getCfg(String agentId); + + OpsAgentEntity getByAgentId(String agentId); + + OpsAgentEntity getByHostId(String hostId); + + boolean removeAgentByAgentId(String agentId); + + boolean removeAgentByHostId(String hostId); + + boolean removeCfgByHostId(String hostId); + + boolean removeHostCfgByAgentId(String agentId); + + boolean removeCfgByClusterNodeId(String clusterNodeId); + + boolean removeClusterNodeCfgByAgentId(String agentId); + + String getAgentIdByClusterNodeId(String clusterNodeId); + + PerfHostVO getPerfHostVO(String hostId); + + boolean checkPerfIsNull(); + + PerfMySqlVO getPerfMySqlVO(String hostId); + + PerfOpenGaussVO getPerfOpenGaussVO(String hostId); + + boolean checkAgentByHostId(String hostId); + + boolean getLinkStatusByAgentId(String agentId); + + boolean distributeCFGByIP(String IP); + + void distributeCFGByAgentId(String agentId); + + String pingAgent(String agentId); + + boolean updatePerfData(PerfData data); +} diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IAgentVersionMngService.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IAgentVersionMngService.java new file mode 100644 index 0000000000000000000000000000000000000000..926dbd687de9e91b93ac1f0fb57e44349f1412ca --- /dev/null +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IAgentVersionMngService.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + + +package org.opengauss.admin.system.service.ops; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.opengauss.admin.common.core.domain.entity.ops.OpsAgentVersionEntity; +import org.opengauss.admin.common.core.domain.model.ops.agent.AgentVersionVO; +import org.opengauss.admin.common.exception.file.InvalidExtensionException; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.List; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +public interface IAgentVersionMngService { + /** + * agent jar包上传 + */ + boolean upload(MultipartFile file) throws IOException, InvalidExtensionException; + + /** + * 检查当前上传jar是否已存在 + */ + boolean checkExist(String name); + + /** + * 获取agentVersion列表 + */ + List listAll(); + + /** + * 分页显示agentVersion信息 + */ + IPage pageAgentVersion(Page page, String version); + + /** + * 根据agent的Version获取agentVersion详细信息 + */ + OpsAgentVersionEntity getByVersion(String version); +} diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IHostService.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IHostService.java index 292ea1059e939f252fef367ad9a32682305e120d..18fdd16883f822f88d010a43766008898bcccee9 100644 --- a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IHostService.java +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IHostService.java @@ -11,14 +11,6 @@ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. - * ------------------------------------------------------------------------- - * - * IHostService.java - * - * IDENTIFICATION - * openGauss-visualtool/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IHostService.java - * - * ------------------------------------------------------------------------- */ @@ -46,7 +38,7 @@ public interface IHostService extends IService { * * @param hostBody host information */ - boolean add(HostBody hostBody); + String add(HostBody hostBody); /** * test connectivity @@ -92,5 +84,18 @@ public interface IHostService extends IService { List listAll(String azId); - Map monitor(String hostId, String businessId, String rootPassword); + /** + * Get Listen Data + * @param hostId host ID + * @param businessId business ID + * @return Listen Data + */ + Map perfHostMonitor(String hostId, String businessId); + + /** + * Get single host information + * @param hostId host ID + * @return OpsHostEntity + */ + OpsHostEntity getByHostId(String hostId); } diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IOpsJdbcDbClusterNodeService.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IOpsJdbcDbClusterNodeService.java index b4fe4f3ef13057b99fe24b41bfb9405a37e86322..fb8e2c5130380a2809b3f78e9694157a711ee21c 100644 --- a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IOpsJdbcDbClusterNodeService.java +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/IOpsJdbcDbClusterNodeService.java @@ -39,6 +39,13 @@ import java.util.Set; public interface IOpsJdbcDbClusterNodeService extends IService { void del(String clusterNodeId); + /** + * + * @param clusterId cluster ID + * @return + */ + List listNodeByClusterId(String clusterId); + OpsJdbcDbClusterNodeEntity getClusterNodeByIpAndPort(String ip, String port); Set fuzzyQueryClusterIdsByIp(String ip); @@ -53,5 +60,5 @@ public interface IOpsJdbcDbClusterNodeService extends IService monitor(String clusterNodeId, String businessId); + Map perfDbMonitor(String clusterNodeId, String businessId); } diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/AgentMngServiceImpl.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/AgentMngServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..6fd57147686fb665487f5d0af85c58dcc824fdea --- /dev/null +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/AgentMngServiceImpl.java @@ -0,0 +1,575 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + + +package org.opengauss.admin.system.service.ops.impl; + +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.opengauss.admin.common.core.domain.entity.ops.OpsAgentEntity; +import org.opengauss.admin.common.core.domain.model.ops.agent.*; +import org.opengauss.admin.common.utils.http.HttpUtils; +import org.opengauss.admin.system.mapper.ops.OpsAgentMngMapper; +import org.opengauss.admin.system.service.ops.IAgentMngService; +import org.opengauss.admin.system.service.ops.IHostService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Slf4j +@Service +public class AgentMngServiceImpl extends ServiceImpl implements IAgentMngService { + @Autowired + private OpsAgentMngMapper opsAgentMngMapper; + @Autowired + private EncryptionUtils encryptionUtils; + @Autowired + private IHostService hostService; + + private final Map perf = new HashMap<>(); + + /** + * Add agent + * + * @param agentVO agentVo + * @return whether success + */ + @Override + public boolean add(AgentVO agentVO) { + OpsAgentEntity agentEntity = agentVO.toAgentEntity(); + agentEntity.setIsAlive(false); + + // 保存agent信息 + boolean isRes = save(agentEntity); + + // 监控本机,信息保存到host监控配置表 + String agentId = agentEntity.getAgentId(); + String hostId = agentEntity.getHostId(); + addHostCfg(agentId, hostId); + distributeCFGByAgentId(agentId); + return isRes; + } + + /** + * Edit agent + * + * @param agentVO agentVo + * @return whether + */ + @Override + public boolean edit(AgentVO agentVO) { + OpsAgentEntity agentEntity = agentVO.toAgentEntity(); + return updateById(agentEntity); + } + + /** + * Add DBConfig + * + * @param agentId agentId + * @param clusterNodeId clusterNodeId + * @return whether + */ + @Override + public boolean addDbNodeCfg(String agentId, String clusterNodeId) { + return opsAgentMngMapper.addDbNodeCfg(agentId, clusterNodeId); + } + + /** + * Add hostConfig + * + * @param agentId agentId + * @param hostId hostId + * @return whether + */ + @Override + public boolean addHostCfg(String agentId, String hostId) { + return opsAgentMngMapper.addHostCfg(agentId, hostId); + } + + /** + * Get all agent + * + * @return + */ + @Override + public List listAll() { + return opsAgentMngMapper.listAll(); + } + + /** + * Page agent + * + * @param page page + * @param name agentName + * @param ip agentIp + * @param version agentVersion + * @return Page agent + */ + @Override + public IPage pageAgent(Page page, String name, String ip, String version) { + return opsAgentMngMapper.pageAgent(page, name, ip, version); + } + + /** + * Get agentConfig by agentId + * + * @param agentId agentId + * @return agentConfig + */ + @Override + public List getCfg(String agentId) { + List cfgHostVOList = getHostInfo(agentId); + List cfgDbVOList = getDbInfo(agentId); + cfgHostVOList.addAll(cfgDbVOList); + return cfgHostVOList; + } + + /** + * Get agentInfo by agentId + * + * @param agentId agentId + * @return AgentInfo + */ + @Override + public OpsAgentEntity getByAgentId(String agentId) { + if (StrUtil.isEmpty(agentId)) { + return new OpsAgentEntity(); + } + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(OpsAgentEntity.class) + .eq(OpsAgentEntity::getAgentId, agentId); + return getOne(queryWrapper, false); + } + + /** + * Get agentInfo by hostId + * + * @param hostId hostId + * @return AgentInfo + */ + @Override + public OpsAgentEntity getByHostId(String hostId) { + if (StrUtil.isEmpty(hostId)) { + return null; + } + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(OpsAgentEntity.class) + .eq(OpsAgentEntity::getHostId, hostId); + return getOne(queryWrapper, false); + } + + /** + * Remove agent by agentId + * + * @param agentId agentId + * @return whether success + */ + @Override + public boolean removeAgentByAgentId(String agentId) { + if (StrUtil.isEmpty(agentId)) { + return false; + } + + // 清空agent上报的缓存数据 + removePerfDataByAgentId(agentId); + + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(OpsAgentEntity.class) + .eq(OpsAgentEntity::getAgentId, agentId); + return remove(queryWrapper); + } + + /** + * Remove agent by hostId + * + * @param hostId hostId + * @return whether success + */ + @Override + public boolean removeAgentByHostId(String hostId) { + if (StrUtil.isEmpty(hostId)) { + return false; + } + // 通过hostId获取到agentId + String agentId = getAgentIdByHostId(hostId); + // 从数据库实例监管表中删除agentId对应记录 + removeClusterNodeCfgByAgentId(agentId); + // 从服务器监管表中删除agentId对应记录 + removeHostCfgByAgentId(agentId); + // 从agent管理表中删除hostId对应记录; + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(OpsAgentEntity.class) + .eq(OpsAgentEntity::getHostId, hostId); + return remove(queryWrapper); + } + + /** + * Remove hostConfig by hostId + * + * @param hostId hostId + * @return whether success + */ + @Override + public boolean removeCfgByHostId(String hostId) { + if (StrUtil.isEmpty(hostId)) { + return false; + } + return opsAgentMngMapper.removeCfgByHostId(hostId); + } + + /** + * Remove DBConfig by clusterNodeId + * + * @param clusterNodeId clusterNodeId + * @return whether success + */ + @Override + public boolean removeCfgByClusterNodeId(String clusterNodeId) { + if (StrUtil.isEmpty(clusterNodeId)) { + return false; + } + return opsAgentMngMapper.removeCfgByClusterNodeId(clusterNodeId); + } + + /** + * Remove hostConfig by agentId + * + * @param agentId agentId + * @return whether success + */ + @Override + public boolean removeHostCfgByAgentId(String agentId) { + if (StrUtil.isEmpty(agentId)) { + return false; + } + // 清空agent上报的缓存数据 + removePerfDataByAgentId(agentId); + + return opsAgentMngMapper.removeHostCfgByAgentId(agentId); + } + + /** + * Get agentId by clusterNodeId + * + * @param clusterNodeId clusterNodeId + * @return agentId + */ + public String getAgentIdByClusterNodeId(String clusterNodeId) { + if (StrUtil.isEmpty(clusterNodeId)) { + return ""; + } + return opsAgentMngMapper.getAgentIdByClusterNodeId(clusterNodeId); + } + + /** + * Remove agentConfig by agentId + * + * @param agentId agentId + * @return whether success + */ + @Override + public boolean removeClusterNodeCfgByAgentId(String agentId) { + if (StrUtil.isEmpty(agentId)) { + return false; + } + + // 清空agent上报的缓存数据 + removePerfDataByAgentId(agentId); + + return opsAgentMngMapper.removeClusterNodeCfgByAgentId(agentId); + } + + /** + * Get hostData by hostId + * + * @param hostId hostId + * @return hostData + */ + @Override + public PerfHostVO getPerfHostVO(String hostId) { + PerfVO perfVO = perf.get(hostId); + if (perfVO != null) { + return perfVO.toHostVO(); + } else { + return new PerfVO().toHostDefaultVO(hostId); + } + } + + /** + * Get mysqlData by hostId + * + * @param hostId hostId + * @return mysqlData + */ + @Override + public PerfMySqlVO getPerfMySqlVO(String hostId) { + PerfVO perfVO = perf.get(hostId); + if (perfVO != null) { + return perfVO.toMySqlVO(); + } else { + return new PerfVO().toMySqlDefaultVO(hostId); + } + } + + /** + * Get DBData by hostId + * + * @param hostId hostId + * @return PerfOpenGaussVO + */ + @Override + public PerfOpenGaussVO getPerfOpenGaussVO(String hostId) { + PerfVO perfVO = perf.get(hostId); + if (perfVO != null) { + return perfVO.toOpenGaussVO(); + } else { + return new PerfVO().toOpenGaussDefaultVO(hostId); + } + } + + /** + * Check perf whether null + * + * @return whether null + */ + @Override + public boolean checkPerfIsNull() { + boolean isRes = false; + if (perf.isEmpty()) { + isRes = true; + } + return isRes; + } + + /** + * Check isExist agent by hostId + * + * @param hostId hostId + * @return isExist agent + */ + @Override + public boolean checkAgentByHostId(String hostId) { + if (StrUtil.isEmpty(hostId)) { + return false; + } + return opsAgentMngMapper.checkAgentByHostId(hostId); + } + + /** + * Get agent status by agentId + * + * @param agentId agentId + * @return agent status + */ + @Override + public boolean getLinkStatusByAgentId(String agentId) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(OpsAgentEntity.class) + .eq(OpsAgentEntity::getAgentId, agentId); + OpsAgentEntity agent = getOne(queryWrapper); + return agent.getIsAlive(); + } + + /** + * Send agent config by ip + * + * @param ip hostIp + * @return whether success + */ + @Override + public boolean distributeCFGByIP(String ip) { + String agentId = getAgentIdByIP(ip); + distributeCFGByAgentId(agentId); + return true; + } + + /** + * Ping test by agentId + * + * @param agentId agentId + * @return message + */ + @Override + public String pingAgent(String agentId) { + String result = ""; + if (agentId == null) { + return "Unable to test : Missing parameter, agentId is null"; + } + OpsAgentEntity agent = getByAgentId(agentId); + String port = agent.getPort().toString(); + String hostId = agent.getHostId(); + String ip = hostService.getByHostId(hostId).getPublicIp(); + String url = "http://" + ip + ":" + port + "/agent/ping"; + HttpUtils.PostResponse res = HttpUtils.sendPost(url, ""); + if (res.toString().contains("code")) { + JSONObject jsonObject = JSON.parseObject(res.getBody()); + if (Objects.equals(jsonObject.get("code").toString(), "200")) { + result = "Ping test success"; + } + } else { + result = res.getBody(); + } + return result; + } + + /** + * Send listen config by agentId + * + * @param agentId agentId + */ + @Override + public void distributeCFGByAgentId(String agentId) { + if (agentId == null) { + return; + } + OpsAgentEntity agent = getByAgentId(agentId); + String serUrl = agent.getServerUrl() + "/agent/data"; + // 从数据库查询配置List + List cfgHostVOList = getHostInfo(agentId); + List cfgDbVOList = getDbInfo(agentId); + cfgHostVOList.addAll(cfgDbVOList); + + CfgData cfgData = new CfgData(); + cfgData.setAgentId(agentId); + cfgData.setSerUrl(serUrl); + for (CfgVO cfgVO : cfgHostVOList) { + if ("host".equals(cfgVO.getType())) { + String pass = cfgVO.getPass(); + cfgVO.setPass(encryptionUtils.decrypt(pass)); + } + } + cfgData.setCfgVOList(cfgHostVOList); + String port = agent.getPort().toString(); + String hostId = agent.getHostId(); + String ip = hostService.getByHostId(hostId).getPublicIp(); + String url = "http://" + ip + ":" + port + "/agent/cfg"; + HttpUtils.sendPost(url, JSONObject.toJSONString(cfgData)); + } + + /** + * save report data + * + * @param data perfData + * @return whether success + */ + @Override + public boolean updatePerfData(PerfData data) { + // 更新agentId对应的Agent数据上报时间 + OpsAgentEntity agent = new OpsAgentEntity(); + agent.setAgentId(data.getAgentId()); + agent.setIsAlive(true); + agent.setLastHeartBeatTime(new Date()); + boolean isRes = opsAgentMngMapper.edit(agent); + + // 将上报的数据保存到PerfData中 + List perfVOList = data.getPerfVOList(); + if (perfVOList != null) { + for (PerfVO perfVO : perfVOList) { + String nodeId = perfVO.getNodeId(); + perf.put(nodeId, perfVO); + } + } + + return isRes; + } + + /** + * Clear cache data after uninstall agent + * + * @param agentId agentId + */ + private void removePerfDataByAgentId(String agentId) { + List cfg = getCfg(agentId); + for (CfgVO cfgVO : cfg) { + perf.remove(cfgVO.getNodeId()); + } + } + + /** + * Get HostInfo By agentId + * + * @param agentId agentId + * @return HostInfo + */ + private List getHostInfo(String agentId) { + return opsAgentMngMapper.getHostInfo(agentId); + } + + /** + * Get DBInfo by agentId + * + * @param agentId agentId + * @return DBInfo + */ + private List getDbInfo(String agentId) { + return opsAgentMngMapper.getDbInfo(agentId); + } + + /** + * Get agentId by ip + * + * @param ip ip + * @return agentId + */ + private String getAgentIdByIP(String ip) { + return opsAgentMngMapper.getAgentIdByIP(ip); + } + + /** + * Get agentId by hostId + * + * @param hostId hostId + * @return agentId + */ + private String getAgentIdByHostId(String hostId) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(OpsAgentEntity.class) + .eq(OpsAgentEntity::getHostId, hostId); + OpsAgentEntity agent = getOne(queryWrapper); + return agent.getAgentId(); + } + + /** + * Update agent status by report time + */ + @Scheduled(cron = "*/30 * * * * ?") + public void agentLinkStatus() { + Date now = new Date(); + List agentVOList = listAll(); + for (AgentVO agentVO : agentVOList) { + Date date = agentVO.getLastHeartBeatTime(); + String agentId = agentVO.getAgentId(); + if (date != null) { + long time1 = now.getTime(); + long time2 = date.getTime(); + long diff = time1 - time2; + if (diff / 1000 > 60) { + opsAgentMngMapper.linkFailure(agentId); + } + } else { + if (agentVO.getLastHeartBeatTime() == null) { + opsAgentMngMapper.linkFailure(agentId); + } + } + } + } +} diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/AgentVersionMngServiceImpl.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/AgentVersionMngServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..effcc344e74f2450ab866202fafe1911de05578d --- /dev/null +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/AgentVersionMngServiceImpl.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2022 Huawei Technologies Co.,Ltd. + * + * openGauss is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + + +package org.opengauss.admin.system.service.ops.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.opengauss.admin.common.config.SystemConfig; +import org.opengauss.admin.common.core.domain.entity.ops.OpsAgentVersionEntity; +import org.opengauss.admin.common.core.domain.model.ops.agent.AgentVersionVO; +import org.opengauss.admin.common.exception.file.InvalidExtensionException; +import org.opengauss.admin.common.exception.ops.OpsException; +import org.opengauss.admin.common.utils.file.FileUploadUtils; +import org.opengauss.admin.system.mapper.ops.OpsAgentVersionMngMapper; +import org.opengauss.admin.system.service.ops.IAgentVersionMngService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author lixinli + * @date 2023/9/17 22:28 + **/ +@Slf4j +@Service +public class AgentVersionMngServiceImpl extends ServiceImpl implements IAgentVersionMngService { + @Autowired + private OpsAgentVersionMngMapper opsAgentVersionMngMapper; + + @Override + public boolean upload(MultipartFile file) throws IOException, InvalidExtensionException, OpsException { + // 上传jar至System的配置目录 + String filename = file.getOriginalFilename(); + if (filename == null) { + throw new OpsException("Agent package name parsing error"); + } + String version; + String match = "[^\\d.]+"; + try { + String[] split = filename.split("-"); + version = split[3].replace(".jar", ""); + Pattern r = Pattern.compile(match); + Matcher m = r.matcher(version); + if (m.find()) { + throw new OpsException("Agent package name parsing error"); + } + } catch (OpsException e) { + throw new OpsException(e.getMessage()); + } + String[] EXTENSION = {"jar"}; + FileUploadUtils.upload(SystemConfig.getStoragePath() + "/agent", filename, file, EXTENSION); + + // 保存相关数据至数据库 + OpsAgentVersionEntity versionEntity = new OpsAgentVersionEntity(); + versionEntity.setJarName(filename); + versionEntity.setVersion(version); + if (SystemConfig.getStoragePath().charAt(0) == '/') { + versionEntity.setPath(SystemConfig.getStoragePath() + "/agent/" + filename); + } else { + versionEntity.setPath(SystemConfig.getStoragePath() + File.separator + "agent" + File.separator + filename); + } + if (checkExist(filename)) { + versionEntity.setVersionId(getByVersion(version).getVersionId()); + } + return saveOrUpdate(versionEntity); + } + + @Override + public boolean checkExist(String name) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(OpsAgentVersionEntity.class) + .eq(OpsAgentVersionEntity::getJarName, name); + OpsAgentVersionEntity res = getOne(queryWrapper, false); + return res != null; + } + + @Override + public List listAll() { + return opsAgentVersionMngMapper.listAll(); + } + + @Override + public IPage pageAgentVersion(Page page, String version) { + return opsAgentVersionMngMapper.pageAgentVersion(page, version); + } + + @Override + public OpsAgentVersionEntity getByVersion(String version) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(OpsAgentVersionEntity.class) + .eq(OpsAgentVersionEntity::getVersion, version); + return getOne(queryWrapper, false); + } +} diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/HostServiceImpl.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/HostServiceImpl.java index 99809f62d46cc440e1b911bb6caa84e8e1c2dc04..8ed15e007d9615e803a135ee12494812c02a6058 100644 --- a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/HostServiceImpl.java +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/HostServiceImpl.java @@ -11,14 +11,6 @@ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE. * See the Mulan PSL v2 for more details. - * ------------------------------------------------------------------------- - * - * HostServiceImpl.java - * - * IDENTIFICATION - * openGauss-visualtool/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/HostServiceImpl.java - * - * ------------------------------------------------------------------------- */ @@ -41,6 +33,7 @@ import org.opengauss.admin.common.core.domain.entity.ops.OpsHostUserEntity; import org.opengauss.admin.common.core.domain.model.ops.HostBody; import org.opengauss.admin.common.core.domain.model.ops.JschResult; import org.opengauss.admin.common.core.domain.model.ops.WsSession; +import org.opengauss.admin.common.core.domain.model.ops.agent.PerfHostVO; import org.opengauss.admin.common.core.domain.model.ops.host.HostMonitorVO; import org.opengauss.admin.common.core.domain.model.ops.host.OpsHostVO; import org.opengauss.admin.common.core.domain.model.ops.host.SSHBody; @@ -59,7 +52,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.*; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -92,10 +84,12 @@ public class HostServiceImpl extends ServiceImpl i private IOpsHostTagRelService opsHostTagRelService; @Autowired private IOpsHostTagService opsHostTagService; + @Autowired + private IAgentMngService agentMngService; @Override @Transactional(rollbackFor = Exception.class) - public boolean add(HostBody hostBody) { + public String add(HostBody hostBody) { OpsHostEntity hostEntity = getByPublicIp(hostBody.getPublicIp()); if (Objects.nonNull(hostEntity) && hostEntity.getPort().equals(hostBody.getPort())) { throw new OpsException("host[" + hostEntity.getPublicIp() + "]already exists, please do not add it again"); @@ -103,7 +97,7 @@ public class HostServiceImpl extends ServiceImpl i Session session = jschUtil.getSession(hostBody.getPublicIp(), hostBody.getPort(), "root", encryptionUtils.decrypt(hostBody.getPassword())).orElseThrow(() -> new OpsException("Failed to establish a session with the host")); try { - hostEntity = hostBody.toHostEntity(getHostName(session), getOS(session), getCpuArch(session)); + hostEntity = hostBody.toHostEntity(getHostName(session), getOS(session), getOSVersion(session), getCpuArch(session)); } finally { if (Objects.nonNull(session) && session.isConnected()) { session.disconnect(); @@ -113,7 +107,8 @@ public class HostServiceImpl extends ServiceImpl i opsHostTagRelService.cleanHostTag(hostEntity.getHostId()); opsHostTagService.addTag(HostTagInputDto.of(hostBody.getTags(), hostEntity.getHostId())); OpsHostUserEntity hostUserEntity = hostBody.toRootUser(hostEntity.getHostId()); - return hostUserService.save(hostUserEntity); + hostUserService.save(hostUserEntity); + return hostEntity.getHostId(); } private String getCpuArch(Session rootSession) { @@ -148,6 +143,22 @@ public class HostServiceImpl extends ServiceImpl i } } + private String getOSVersion(Session rootSession) { + String command = "cat /etc/os-release | grep VERSION_ID= | head -n 1|awk -F '=' '{print $2}' | sed 's/\\\"//g'"; + try { + JschResult jschResult = jschUtil.executeCommand(command, rootSession); + if (jschResult.getExitCode() != 0) { + log.error("Failed to get system information,exitCode:{},res:{}", jschResult.getExitCode(), jschResult.getResult()); + throw new OpsException("Failed to get system information"); + } + + return jschResult.getResult().trim(); + } catch (Exception e) { + log.error("Failed to get system information", e); + throw new OpsException("Failed to get system information"); + } + } + private String getHostName(Session session) { try { JschResult jschResult = jschUtil.executeCommand(SshCommandConstants.HOSTNAME, session); @@ -179,8 +190,17 @@ public class HostServiceImpl extends ServiceImpl i if (clusterService.countByHostId(hostId) > 0) { throw new OpsException("The host is being used by the cluster"); } + // 删除ops_host表中数据 removeById(hostId); + // 删除ops_host_user表中数据 hostUserService.removeByHostId(hostId); + // 如果该服务器安装了agent,则删除ops_agent表中agent数据,并且删除数据库实例、服务器监管表中agent对应的所有数据 + // 如果该服务器未安装agent,则从服务器监管表(ops_agent_mng_host)中删除该host数据 + if (agentMngService.checkAgentByHostId(hostId)) { + agentMngService.removeAgentByHostId(hostId); + } else { + agentMngService.removeCfgByHostId(hostId); + } return true; } @@ -241,13 +261,12 @@ public class HostServiceImpl extends ServiceImpl i } Session session = jschUtil.getSession(hostBody.getPublicIp(), hostBody.getPort(), "root", encryptionUtils.decrypt(hostBody.getPassword())).orElseThrow(() -> new OpsException("Failed to establish a session with the host")); - OpsHostEntity newHostEntity = hostBody.toHostEntity(getHostName(session), getOS(session), getCpuArch(session)); + OpsHostEntity newHostEntity = hostBody.toHostEntity(getHostName(session), getOS(session), getOSVersion(session), getCpuArch(session)); newHostEntity.setHostId(hostId); updateById(newHostEntity); opsHostTagRelService.cleanHostTag(hostId); opsHostTagService.addTag(HostTagInputDto.of(hostBody.getTags(), hostId)); - return true; } @@ -342,7 +361,7 @@ public class HostServiceImpl extends ServiceImpl i } @Override - public Map monitor(String hostId, String businessId, String rootPassword) { + public Map perfHostMonitor(String hostId, String businessId) { Map res = new HashMap<>(); res.put("res", true); @@ -353,48 +372,12 @@ public class HostServiceImpl extends ServiceImpl i return res; } - OpsHostUserEntity rootUserEntity = hostUserService.getRootUserByHostId(hostId); - if (Objects.isNull(rootUserEntity)) { - res.put("res", false); - res.put("msg", "root user info not found"); - return res; - } - - if (StrUtil.isEmpty(rootUserEntity.getPassword())) { - if (StrUtil.isNotEmpty(rootPassword)) { - rootUserEntity.setPassword(rootPassword); - } else { - res.put("res", false); - res.put("msg", "root user password not found"); - return res; - } - } - - Session rootSession = null; - Optional session = jschUtil.getSession(hostEntity.getPublicIp(), hostEntity.getPort(), rootUserEntity.getUsername(), encryptionUtils.decrypt(rootUserEntity.getPassword())); - if (session.isPresent()) { - rootSession = session.get(); - } else { - res.put("res", false); - res.put("msg", "The root user failed to establish a connection"); - return res; - } - WsSession wsSession = wsConnectorManager.getSession(businessId).orElseThrow(() -> new OpsException("response session does not exist")); - Session finalRootSession = rootSession; Future future = threadPoolTaskExecutor.submit(() -> { try { - doMonitor(wsSession, finalRootSession); + doPerfMonitor(wsSession, hostId); } finally { - if (Objects.nonNull(finalRootSession) && finalRootSession.isConnected()) { - try { - finalRootSession.disconnect(); - } catch (Exception ignore) { - - } - } - wsUtil.close(wsSession); } }); @@ -402,140 +385,27 @@ public class HostServiceImpl extends ServiceImpl i return res; } - private void doMonitor(WsSession wsSession, Session rootSession) { + private void doPerfMonitor(WsSession wsSession, String hostid) { while (wsSession.getSession().isOpen()) { HostMonitorVO hostMonitorVO = new HostMonitorVO(); - CountDownLatch countDownLatch = new CountDownLatch(4); - - threadPoolTaskExecutor.submit(() -> { - try { - String[] net = netMonitor(rootSession); - hostMonitorVO.setUpSpeed(net[0]); - hostMonitorVO.setDownSpeed(net[1]); - } finally { - countDownLatch.countDown(); - } - }); - - threadPoolTaskExecutor.submit(() -> { - try { - hostMonitorVO.setCpu(cpuMonitor(rootSession)); - } finally { - countDownLatch.countDown(); - } - }); - - threadPoolTaskExecutor.submit(() -> { - try { - hostMonitorVO.setMemory(memoryMonitor(rootSession)); - } finally { - countDownLatch.countDown(); - } - }); - - threadPoolTaskExecutor.submit(() -> { - try { - hostMonitorVO.setDisk(diskMonitor(rootSession)); - } finally { - countDownLatch.countDown(); - } - }); - - try { - countDownLatch.await(); - } catch (InterruptedException e) { - log.error("waiting for thread to be interrupted", e); - throw new OpsException("monitor error"); + if (!agentMngService.checkPerfIsNull()) { + PerfHostVO perfHostVO = agentMngService.getPerfHostVO(hostid); + hostMonitorVO.setUpSpeed(perfHostVO.getNetworkUplink()); + hostMonitorVO.setDownSpeed(perfHostVO.getNetworkDownlink()); + hostMonitorVO.setCpu(perfHostVO.getCpuUsage()); + hostMonitorVO.setMemory(perfHostVO.getMemoryUsage()); + hostMonitorVO.setDisk(perfHostVO.getDiskUsage()); } - wsUtil.sendText(wsSession, JSON.toJSONString(hostMonitorVO)); + try { TimeUnit.SECONDS.sleep(5L); } catch (InterruptedException e) { throw new OpsException("thread is interrupted"); } - } - } - - private String diskMonitor(Session rootSession) { - String command = "df -Th | egrep -v \"(tmpfs|sr0)\" | tail -n +2|tr -s \" \" | cut -d \" \" -f6|tr -d \"%\"|head -n 1"; - try { - JschResult jschResult = jschUtil.executeCommand(command, rootSession); - if (0 == jschResult.getExitCode()) { - return jschResult.getResult(); - } else { - log.error("disk monitor error,exitCode:{},exitMsg:{}", jschResult.getExitCode(), jschResult.getResult()); - } - } catch (Exception e) { - log.error("disk monitor error:", e); - } - throw new OpsException("disk monitor error"); - } - - private String memoryMonitor(Session rootSession) { - String command = "free -m | awk -F '[ :]+' 'NR==2{printf \"%d\", ($2-$7)/$2*100}'"; - try { - JschResult jschResult = jschUtil.executeCommand(command, rootSession); - if (0 == jschResult.getExitCode()) { - return jschResult.getResult(); - } else { - log.error("memory monitor error,exitCode:{},exitMsg:{}", jschResult.getExitCode(), jschResult.getResult()); - } - } catch (Exception e) { - log.error("memory monitor error:", e); - } - throw new OpsException("memory monitor error"); - } - - private String cpuMonitor(Session rootSession) { - String command = "top -b -n1 | fgrep \"Cpu(s)\" | tail -1 | awk -F'id,' '{split($1, vs, \",\"); v=vs[length(vs)]; sub(/\\s+/, \"\", v);sub(/\\s+/, \"\", v); printf \"%d\", 100-v;}'"; - try { - JschResult jschResult = jschUtil.executeCommand(command, rootSession); - if (0 == jschResult.getExitCode()) { - return jschResult.getResult(); - } else { - log.error("cpu monitor error,exitCode:{},exitMsg:{}", jschResult.getExitCode(), jschResult.getResult()); - } - } catch (Exception e) { - log.error("cpu monitor error:", e); - } - throw new OpsException("cpu monitor error"); - } - - private String[] netMonitor(Session rootSession) { - String[] res = new String[2]; - - String netCardName; - String netCardNameCommand = "cat /proc/net/dev | awk '{i++; if(i>2){print $1}}' | sed 's/^[\\t]*//g' | sed 's/[:]*$//g' | head -n 1"; - try { - JschResult jschResult = jschUtil.executeCommand(netCardNameCommand, rootSession); - if (0 == jschResult.getExitCode()) { - netCardName = jschResult.getResult().trim(); - } else { - log.error("Failed to get network card name,exitCode:{},exitMsg:{}", jschResult.getExitCode(), jschResult.getResult()); - throw new OpsException("Failed to get network card name"); - } - } catch (Exception e) { - throw new OpsException("cpu monitor error"); - } - String command = "rx_net1=$(ifconfig " + netCardName + " | awk '/RX packets/{print $5}') && tx_net1=$(ifconfig " + netCardName + " | awk '/TX packets/{print $5}') && sleep 1 && rx_net2=$(ifconfig " + netCardName + " | awk '/RX packets/{print $5}') && tx_net2=$(ifconfig " + netCardName + " | awk '/TX packets/{print $5}') && rx_net=$[($rx_net2-$rx_net1)] && tx_net=$[($tx_net2-$tx_net1)] && echo \"$rx_net|$tx_net\""; - try { - JschResult jschResult = jschUtil.executeCommand(command, rootSession); - if (0 == jschResult.getExitCode()) { - String[] split = jschResult.getResult().split("\\|"); - res[0] = split[0]; - res[1] = split[1]; - return res; - } else { - log.error("cpu monitor error,exitCode:{},exitMsg:{}", jschResult.getExitCode(), jschResult.getResult()); - } - } catch (Exception e) { - log.error("cpu monitor error:", e); } - throw new OpsException("cpu monitor error"); } - private void populateTags(List list) { List hostIds = list.stream().map(OpsHostVO::getHostId).collect(Collectors.toList()); if (CollUtil.isNotEmpty(hostIds)) { @@ -592,4 +462,13 @@ public class HostServiceImpl extends ServiceImpl i return getOne(queryWrapper, false); } + @Override + public OpsHostEntity getByHostId(String hostId) { + if (StrUtil.isEmpty(hostId)) { + return new OpsHostEntity(); + } + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(OpsHostEntity.class) + .eq(OpsHostEntity::getHostId, hostId); + return getOne(queryWrapper, false); + } } diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/OpsJdbcDbClusterNodeServiceImpl.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/OpsJdbcDbClusterNodeServiceImpl.java index fbb291aac891e8c1ec94cf6287ac8ed2935952c3..98d813abc2fae21182ac6eb215efb88a2e3717f2 100644 --- a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/OpsJdbcDbClusterNodeServiceImpl.java +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/OpsJdbcDbClusterNodeServiceImpl.java @@ -33,6 +33,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.opengauss.admin.common.core.domain.entity.ops.OpsJdbcDbClusterEntity; import org.opengauss.admin.common.core.domain.entity.ops.OpsJdbcDbClusterNodeEntity; import org.opengauss.admin.common.core.domain.model.ops.WsSession; +import org.opengauss.admin.common.core.domain.model.ops.agent.PerfMySqlVO; +import org.opengauss.admin.common.core.domain.model.ops.agent.PerfOpenGaussVO; import org.opengauss.admin.common.core.domain.model.ops.jdbc.JdbcDbClusterNodeInputDto; import org.opengauss.admin.common.core.domain.model.ops.jdbc.JdbcInfo; import org.opengauss.admin.common.core.domain.model.ops.jdbc.JdbcMonitorVO; @@ -44,7 +46,7 @@ import org.opengauss.admin.common.exception.ops.OpsException; import org.opengauss.admin.common.utils.ops.JdbcUtil; import org.opengauss.admin.common.utils.ops.WsUtil; import org.opengauss.admin.system.mapper.ops.OpsJdbcDbClusterNodeMapper; -import org.opengauss.admin.system.service.ops.IOpsClusterService; +import org.opengauss.admin.system.service.ops.IAgentMngService; import org.opengauss.admin.system.service.ops.IOpsJdbcDbClusterNodeService; import org.opengauss.admin.system.service.ops.IOpsJdbcDbClusterService; import org.springframework.beans.factory.annotation.Autowired; @@ -53,11 +55,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.*; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -78,7 +76,7 @@ public class OpsJdbcDbClusterNodeServiceImpl extends ServiceImpl listNodeByClusterId(String clusterId) { + @Override + public List listNodeByClusterId(String clusterId) { if (StrUtil.isEmpty(clusterId)) { return Collections.emptyList(); } @@ -246,7 +245,7 @@ public class OpsJdbcDbClusterNodeServiceImpl extends ServiceImpl monitor(String clusterNodeId, String businessId) { + public Map perfDbMonitor(String clusterNodeId, String businessId) { Map res = new HashMap<>(); res.put("res", true); @@ -265,36 +264,12 @@ public class OpsJdbcDbClusterNodeServiceImpl extends ServiceImpl new OpsException("response session does not exist")); - Connection finalConnection = connection; Future future = threadPoolTaskExecutor.submit(() -> { try { - doMonitor(wsSession, finalConnection, clusterEntity.getDbType()); + doPerfDbMonitor(wsSession, clusterEntity.getDbType(), clusterNodeId); } finally { - if (Objects.nonNull(finalConnection)) { - try { - finalConnection.close(); - } catch (SQLException ignore) { - - } - } - wsUtil.close(wsSession); } }); @@ -302,14 +277,30 @@ public class OpsJdbcDbClusterNodeServiceImpl extends ServiceImpl { - try { - jdbcMonitorVO.setLockNum(opsClusterService.lock(connection)); - } finally { - countDownLatch.countDown(); - } - }); - - threadPoolTaskExecutor.submit(() -> { - try { - jdbcMonitorVO.setSessionNum(opsClusterService.session(connection)); - } finally { - countDownLatch.countDown(); - } - }); - - threadPoolTaskExecutor.submit(() -> { - try { - jdbcMonitorVO.setConnNum(opsClusterService.connectNum(connection)); - } finally { - countDownLatch.countDown(); - } - }); - - try { - countDownLatch.await(); - } catch (InterruptedException e) { - log.error("waiting for thread to be interrupted", e); - throw new OpsException("monitor error"); - } - } - - private void doMonitorMysql(Connection connection, JdbcMonitorVO jdbcMonitorVO) { - CountDownLatch countDownLatch = new CountDownLatch(6); - - threadPoolTaskExecutor.submit(() -> { - try { - jdbcMonitorVO.setRole(role(connection)); - } finally { - countDownLatch.countDown(); - } - }); - - threadPoolTaskExecutor.submit(() -> { - try { - jdbcMonitorVO.setConnNum(connNum(connection)); - } finally { - countDownLatch.countDown(); - } - }); - - threadPoolTaskExecutor.submit(() -> { - try { - jdbcMonitorVO.setQps(qps(connection)); - } finally { - countDownLatch.countDown(); - } - }); - - threadPoolTaskExecutor.submit(() -> { - try { - jdbcMonitorVO.setTps(tps(connection)); - } finally { - countDownLatch.countDown(); - } - }); - - threadPoolTaskExecutor.submit(() -> { - try { - jdbcMonitorVO.setMemoryUsed(memoryUsed(connection)); - } finally { - countDownLatch.countDown(); - } - }); - - threadPoolTaskExecutor.submit(() -> { - try { - jdbcMonitorVO.setTableSpaceUsed(tableSpaceUsed(connection)); - } finally { - countDownLatch.countDown(); - } - }); - - try { - countDownLatch.await(); - } catch (InterruptedException e) { - log.error("waiting for thread to be interrupted", e); - throw new OpsException("monitor error"); - } - } - - private String tableSpaceUsed(Connection connection) { - String sql = "SELECT SUM( table_schema_size.table_schema_size ) AS 'tableSpaceUsed' FROM ( SELECT table_schema, SUM( data_length + index_length ) AS table_schema_size FROM information_schema.TABLES GROUP BY table_schema ) table_schema_size"; - try (PreparedStatement preparedStatement = connection.prepareStatement(sql); - ResultSet resultSet = preparedStatement.executeQuery()) { - - if (resultSet.next()) { - return resultSet.getString("tableSpaceUsed"); - } - } catch (Exception e) { - log.error("Failed to get tablespace", e); - } - - throw new OpsException("Failed to get tablespace"); - } - - private String memoryUsed(Connection connection) { - String sql = "SELECT (@@key_buffer_size + @@innodb_buffer_pool_size + @@innodb_log_buffer_size + @@max_connections * ( @@read_buffer_size + @@read_rnd_buffer_size + @@sort_buffer_size + @@join_buffer_size + @@binlog_cache_size + @@thread_stack + @@tmp_table_size )) AS 'memoryUsed'"; - - try (PreparedStatement preparedStatement = connection.prepareStatement(sql); - ResultSet resultSet = preparedStatement.executeQuery()) { - - if (resultSet.next()) { - return resultSet.getString("memoryUsed"); - } - } catch (Exception e) { - log.error("Failed to get memoryUsed", e); - } - - throw new OpsException("Failed to get memoryUsed"); - } - - /** - * TPS = (Com_commit+Com_rollback)/Uptime - * - * @param connection - * @return - */ - private String tps(Connection connection) { - String commitSql = "show global status like 'Com_commit'"; - String rollbackSql = "show global status like 'Com_rollback'"; - String uptimeSql = "show global status like 'Uptime'"; - - try (PreparedStatement commitPreparedStatement = connection.prepareStatement(commitSql); - PreparedStatement rollbackPreparedStatement = connection.prepareStatement(rollbackSql); - PreparedStatement uptimePreparedStatement = connection.prepareStatement(uptimeSql); - ResultSet commitResultSet = commitPreparedStatement.executeQuery(); - ResultSet rollbackResultSet = rollbackPreparedStatement.executeQuery(); - ResultSet uptimeResultSet = uptimePreparedStatement.executeQuery()) { - - if (commitResultSet.next() && rollbackResultSet.next() && uptimeResultSet.next()) { - long commit = commitResultSet.getLong("Value"); - long rollback = rollbackResultSet.getLong("Value"); - long uptime = uptimeResultSet.getLong("Value"); - - return Long.valueOf((commit + rollback) / uptime).toString(); - } - } catch (Exception e) { - log.error("Failed to get tps", e); - } - throw new OpsException("Failed to get tps"); - } - - /** - * QPS = Questions/Uptime - * - * @param connection - * @return - */ - private String qps(Connection connection) { - String questionsSql = "show global status like 'Questions'"; - String uptimeSql = "show global status like 'Uptime'"; - - try (PreparedStatement questionsPreparedStatement = connection.prepareStatement(questionsSql); - PreparedStatement uptimePreparedStatement = connection.prepareStatement(uptimeSql); - ResultSet questionsResultSet = questionsPreparedStatement.executeQuery(); - ResultSet uptimeResultSet = uptimePreparedStatement.executeQuery()) { - - if (questionsResultSet.next() && uptimeResultSet.next()) { - long questions = questionsResultSet.getLong("Value"); - long uptime = uptimeResultSet.getLong("Value"); - - return Long.valueOf(questions / uptime).toString(); - } - } catch (Exception e) { - log.error("Failed to get qps", e); - } - throw new OpsException("Failed to get qps"); - } - - private String connNum(Connection connection) { - String sql = "SHOW STATUS LIKE 'Threads_connected'"; - try (PreparedStatement preparedStatement = connection.prepareStatement(sql); - ResultSet resultSet = preparedStatement.executeQuery()) { - - if (resultSet.next()) { - return resultSet.getString("Value"); - } - } catch (Exception e) { - log.error("Failed to get connection number", e); - } - - throw new OpsException("Failed to get connection number"); - } - - private ClusterRoleEnum role(Connection connection) { - String sql = "SHOW SLAVE STATUS"; - try (PreparedStatement preparedStatement = connection.prepareStatement(sql); - ResultSet resultSet = preparedStatement.executeQuery()) { - - if (resultSet.next()) { - return ClusterRoleEnum.SLAVE; - } else { - return ClusterRoleEnum.MASTER; - } - } catch (Exception e) { - log.error("Failed to get role", e); - } - - throw new OpsException("Failed to get role"); - } } diff --git a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/OpsJdbcDbClusterServiceImpl.java b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/OpsJdbcDbClusterServiceImpl.java index a7870bac850445b742f6788e2408ba1a6472bdf1..9c49af0a6cc946c25c04c99aa452c58cd1120bf8 100644 --- a/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/OpsJdbcDbClusterServiceImpl.java +++ b/openGauss-datakit/visualtool-service/src/main/java/org/opengauss/admin/system/service/ops/impl/OpsJdbcDbClusterServiceImpl.java @@ -40,6 +40,7 @@ import org.opengauss.admin.common.enums.ops.DeployTypeEnum; import org.opengauss.admin.common.exception.ops.OpsException; import org.opengauss.admin.common.utils.ops.JdbcUtil; import org.opengauss.admin.system.mapper.ops.OpsJdbcDbClusterMapper; +import org.opengauss.admin.system.service.ops.IAgentMngService; import org.opengauss.admin.system.service.ops.IHostService; import org.opengauss.admin.system.service.ops.IOpsJdbcDbClusterNodeService; import org.opengauss.admin.system.service.ops.IOpsJdbcDbClusterService; @@ -66,6 +67,8 @@ public class OpsJdbcDbClusterServiceImpl extends ServiceImpl list = opsJdbcDbClusterNodeService.listNodeByClusterId(clusterId); + for (OpsJdbcDbClusterNodeEntity opsJdbcDbClusterNodeEntity : list) { + String clusterNodeId = opsJdbcDbClusterNodeEntity.getClusterNodeId(); + // 删除监管配置中ClusterNode对应记录前,先获取到其对应的agent + String agentId = agentMngService.getAgentIdByClusterNodeId(clusterNodeId); + agentMngService.removeCfgByClusterNodeId(clusterNodeId); + // 删除监管配置后,触发下发新的监管配置给agent + agentMngService.distributeCFGByAgentId(agentId); + } opsJdbcDbClusterNodeService.delByClusterId(clusterId); removeById(clusterId); } @@ -504,13 +518,13 @@ public class OpsJdbcDbClusterServiceImpl extends ServiceImpl clusterNodeEntityList = clusterNodeMap.get(clusterId); if (CollUtil.isNotEmpty(clusterNodeEntityList)) { for (OpsJdbcDbClusterNodeEntity clusterNodeEntity : clusterNodeEntityList) { - nodes.add(JdbcDbClusterNodeVO.of(clusterNodeEntity, ipOsMap.get(clusterNodeEntity.getIp()))); + String agentId = agentMngService.getAgentIdByClusterNodeId(clusterNodeEntity.getClusterNodeId()); + nodes.add(JdbcDbClusterNodeVO + .of(clusterNodeEntity, ipOsMap.get(clusterNodeEntity.getIp()), agentId)); } } - res.add(jdbcDbClusterVO); } - return res; } @@ -521,7 +535,6 @@ public class OpsJdbcDbClusterServiceImpl extends ServiceImpl clusterNodeEntityList = new ArrayList<>(); for (JdbcDbClusterNodeInputDto node : nodes) { String url = node.getUrl(); JdbcInfo jdbcInfo = JdbcUtil.parseUrl(url); @@ -532,7 +545,6 @@ public class OpsJdbcDbClusterServiceImpl extends ServiceImpl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + update ops_agent + + agent_name = #{agentName}, + agent_version = #{agentVersion}, + host_id = #{hostId}, + port = #{port}, + install_path = #{installPath}, + is_alive = #{isAlive}, + server_url = #{serverUrl}, + last_heart_beat_time = #{lastHeartBeatTime}, + remark = #{remark} + + where agent_id = #{agentId} + + + update ops_agent + set is_alive = false + where agent_id = #{agentId} + + diff --git a/openGauss-datakit/visualtool-service/src/main/resources/mapper/ops/OpsAgentVersionMngMapper.xml b/openGauss-datakit/visualtool-service/src/main/resources/mapper/ops/OpsAgentVersionMngMapper.xml new file mode 100644 index 0000000000000000000000000000000000000000..4fc3e8baec8b4e96faebae8bf2c4aee5ef6d6f12 --- /dev/null +++ b/openGauss-datakit/visualtool-service/src/main/resources/mapper/ops/OpsAgentVersionMngMapper.xml @@ -0,0 +1,20 @@ + + + + + + + + diff --git a/openGauss-datakit/visualtool-ui/src/api/ops/index.ts b/openGauss-datakit/visualtool-ui/src/api/ops/index.ts index 46c75d4b61854a3532b4ae8fe46496a10e8d0fa0..d8996cada3ea7563a589b5086c11ed66bcb28b93 100644 --- a/openGauss-datakit/visualtool-ui/src/api/ops/index.ts +++ b/openGauss-datakit/visualtool-ui/src/api/ops/index.ts @@ -249,4 +249,64 @@ export const jdbcNodeMonitor = (clusterNodeId: any, data: KeyValue) => { return axios.get(`jdbcDbClusterNode/monitor/${clusterNodeId}`, { params: data }) -} \ No newline at end of file +} + +export const addAgent = (data: KeyValue) => { + return axios.post('agent/add', data) +} + +export const pageAgent = (data: KeyValue) => { + return axios.get('agent/page', { + params: data + }) +} + +export const editAgent = (data: KeyValue) => { + return axios.post('agent/edit', data) +} + +export const allAgent = () => { + return axios.get('agent/listAll') +} + +export const delAgent = (agentId: any) => { + return axios.delete(`agent/${agentId}`) +} + +export const checkAgentByHostId = (hostId: any) => { + return axios.get(`agent/check/${hostId}`) +} + +export const getAllAgentPackage = () => { + return axios.get('version/listAll') +} + +export const pageAgentPkg = (data: KeyValue) => { + return axios.get('version/page', { + params: data + }) +} + +export const distributeCFG = (data: KeyValue) => { + return axios.get('agent/distributeCFG', { + params: data + }) +} + +export const getAgentByHostId = (data: any) => { + return axios.get('agent/getInfo', { + params: data + }) +} + +export const getAgentById = (data: any) => { + return axios.get('agent/linkStatus', { + params: data + }) +} + +export const pingAgentById = (data: any) => { + return axios.get('agent/ping', { + params: data + }) +} diff --git a/openGauss-datakit/visualtool-ui/src/locale/locale/en.json b/openGauss-datakit/visualtool-ui/src/locale/locale/en.json index 82193e0a68e1b6888bb142ed8880b94d71b98f2a..0037ec58a16662dee3bf6e54efc969608442baad 100644 --- a/openGauss-datakit/visualtool-ui/src/locale/locale/en.json +++ b/openGauss-datakit/visualtool-ui/src/locale/locale/en.json @@ -63,6 +63,53 @@ } }, "components": { + "AddAgent": { + "else1": "Please enter the correct port number", + "else2": "The value cannot be pure space", + "cancel": "Cancel", + "confirm": "Confirm", + "back": "Back", + "name": "Name", + "nameInput": "Please Input Agent Name", + "server": "Server", + "serverInput": "Please Select Server", + "installPath": "Installation Path", + "installPathInput": "Please Input Installation Path", + "agentPort": "Agent Service Port", + "agentPortInput": "Please Input Agent Service Port", + "remark": "Remark", + "remarkInput": "Please Input Remark", + "installAgent": "Install Agent", + "editAgent": "Modify Agent", + "agentVersion": "Agent Version", + "agentSelect": "Please one Agent Version" + }, + "RestartAgent": { + "else1": "Are you sure to restart this Agent?", + "title": "Restart Agent", + "cancel": "Cancel", + "confirm": "Confirm", + "close": "Close" + }, + "UnInstallAgent": { + "else1": "Are you sure to uninstall this Agent?", + "title": "Uninstall Agent", + "cancel": "Cancel", + "confirm": "Confirm", + "close": "Close" + }, + "UpgradeAgent": { + "selectPlaceholder": "Please select an upgrade package", + "confirm": "Confirm" + }, + "uploadAgent": { + "agentPkgName": "Name", + "agentVersion": "Version", + "create": "Create", + "upload": "Upload", + "version-input": "Please Input Version", + "search": "Search" + }, "UpdateDefaultCode": { "5nus586u4jg0": "Rest Default Password", "5n7vbkp1s580": "Change Password", @@ -232,6 +279,7 @@ "AddHost": { "else1": "Please enter the correct port number", "else2": "Remember", + "else3": "Install Agent", "currentStatus": "Current status", "ipAddress": "Intranet IP", "name": "name", @@ -256,7 +304,9 @@ "5mphy3snyxc0": "Please enter a remark", "5mphy3snz5k0": "Adding a Dedicated Server", "5mphy3snzb80": "The current server is unavailable", - "5mphy3snzrk0": "Edit Host" + "5mphy3snzrk0": "Edit Host", + "5mphy3snag00": "Agent", + "5mphy3snag01": "Please select one agent" }, "AddHostUser": { "else1": "Confirm", @@ -704,7 +754,8 @@ "5mphf11tfjw0": "operation", "5mphf11tfr80": "Not detected", "5mphf11tfx80": "Not available", - "5mphf11tg780": "available" + "5mphf11tg780": "available", + "5mphf11tun00": "Uninstall Agent" } }, "label": { @@ -813,6 +864,8 @@ "5oxhtcboa7c0": "Please enter the user name", "5oxhtcboac00": "Password", "5oxhtcboags0": "Please enter password", + "5oxhtcboag00": "Agent", + "5oxhtcboag01": "Please select one Agent", "5oxhtcboap00": "extension", "5oxhtcboatc0": "Add", "5oxhtcboaxc0": "Delete", @@ -860,5 +913,33 @@ "index": { "5msicm67hz00": "all rights reserved" } + }, + "agent":{ + "index": { + "create": "Install Agent", + "plugin-manager": "Plug Manager", + "plugin": "Plugin", + "ip": "Ip Address", + "ip-input": "Please input IP Address", + "name": "Agent Name", + "name-input": "Please Input Agent Name", + "search": "Search", + "running": "Running", + "disconnect": "Disconnect", + "edit": "Edit", + "upgrade": "Upgrade", + "unInstall": "UnInstall", + "restart": "Restart", + "state": "State", + "version": "Version", + "version-input": "Please enter version", + "operate": "Operate", + "agentPkgManager": "Agent Package Manager", + "ping": "CheckPing", + "ping-ping": "During connectivity testing", + "ping-success": "Connectivity test successful", + "ping-failed": "Connectivity test failed", + "confirm": "Confirm" + } } } \ No newline at end of file diff --git a/openGauss-datakit/visualtool-ui/src/locale/locale/zh-cn.json b/openGauss-datakit/visualtool-ui/src/locale/locale/zh-cn.json index 3f3af49d08b06b5255fdbbd90b69b46fd1fd454a..9d9217cecb9f1f1a20fd4ad420cd2e0041ce81e2 100644 --- a/openGauss-datakit/visualtool-ui/src/locale/locale/zh-cn.json +++ b/openGauss-datakit/visualtool-ui/src/locale/locale/zh-cn.json @@ -63,6 +63,53 @@ } }, "components": { + "AddAgent": { + "else1": "请输入正确的端口号", + "else2": "不能为纯空格", + "cancel": "取消", + "confirm": "确定", + "back": "返回", + "name": "名称", + "nameInput": "请输入Agent名称", + "server": "服务器", + "serverInput": "请选择安装Agent的服务器", + "installPath": "安装路径", + "installPathInput": "请输入安装路径", + "agentPort": "代理服务端口", + "agentPortInput": "请输入代理服务端口", + "remark": "备注", + "remarkInput": "请输入备注", + "installAgent": "安装Agent", + "editAgent": "修改Agent", + "agentVersion": "Agent版本", + "agentSelect": "请选择Agent版本" + }, + "RestartAgent": { + "else1": "确定重启此Agent吗?", + "title": "重启Agent", + "cancel": "取消", + "confirm": "确定", + "close": "关闭" + }, + "UnInstallAgent": { + "else1": "确定卸载此Agent吗?", + "title": "卸载Agent", + "cancel": "取消", + "confirm": "确定", + "close": "关闭" + }, + "UpgradeAgent": { + "selectPlaceholder": "请选择升级包", + "confirm": "确定" + }, + "uploadAgent": { + "agentPkgName": "名称", + "agentVersion": "版本", + "create": "创建", + "upload": "上传", + "version-input": "请输入版本号", + "search": "搜索" + }, "UpdateDefaultCode": { "5nus586u4jg0": "重置默认密码", "5n7vbkp1s580": "修改密码", @@ -232,6 +279,7 @@ "AddHost": { "else1": "请输入正确的端口号", "else2": "记住密码", + "else3": "安装代理", "currentStatus": "当前状态", "ipAddress": "内网IP", "name": "名称", @@ -256,7 +304,9 @@ "5mphy3snyxc0": "请输入备注", "5mphy3snz5k0": "新增物理机", "5mphy3snzb80": "当前服务器不可用", - "5mphy3snzrk0": "编辑物理机" + "5mphy3snzrk0": "编辑物理机", + "5mphy3snag00": "代理", + "5mphy3snag01": "请选择代理" }, "AddHostUser": { "else1": "确认", @@ -704,7 +754,8 @@ "5mphf11tfjw0": "操作", "5mphf11tfr80": "未检测", "5mphf11tfx80": "不可用", - "5mphf11tg780": "可用" + "5mphf11tg780": "可用", + "5mphf11tun00": "卸载Agent" } }, "label": { @@ -813,6 +864,8 @@ "5oxhtcboa7c0": "请输入用户名", "5oxhtcboac00": "密码", "5oxhtcboags0": "请输入密码", + "5oxhtcboag00": "代理", + "5oxhtcboag01": "请选择代理", "5oxhtcboap00": "连接扩展属性", "5oxhtcboatc0": "新增", "5oxhtcboaxc0": "删除", @@ -860,5 +913,33 @@ "index": { "5msicm67hz00": "版权所有" } + }, + "agent":{ + "index": { + "create": "安装代理", + "plugin-manager": "插件管理", + "plugin": "插件", + "ip": "IP地址", + "ip-input": "请输入ip", + "name": "Agent名称", + "name-input": "请输入Agent名称", + "search": "查询", + "running": "运行中", + "disconnect": "断开", + "edit": "修改", + "upgrade": "升级", + "unInstall": "卸载", + "restart": "重启", + "state": "状态", + "version": "版本", + "version-input": "请输入版本", + "operate": "操作", + "agentPkgManager": "Agent包管理", + "ping": "连通性测试", + "ping-ing": "连通性测试中", + "ping-success": "连通性测试成功", + "ping-failed": "连通性测试失败", + "confirm": "确认" + } } } \ No newline at end of file diff --git a/openGauss-datakit/visualtool-ui/src/router/routes/modules/agent.ts b/openGauss-datakit/visualtool-ui/src/router/routes/modules/agent.ts new file mode 100644 index 0000000000000000000000000000000000000000..8fe28d2e005b87fcd6d488afaef033fff3105138 --- /dev/null +++ b/openGauss-datakit/visualtool-ui/src/router/routes/modules/agent.ts @@ -0,0 +1,31 @@ +import { DEFAULT_LAYOUT } from '@/router/constants' +import { AppRouteRecordRaw } from '../types' + +const AGENT: AppRouteRecordRaw = { + path: '/agent', + name: 'agent', + component: DEFAULT_LAYOUT, + redirect: '/agent/manager', + meta: { + title: 'Agent管理', + requiresAuth: false, + icon: 'icon-command', + order: 5, + hideChildrenInMenu: true + // activeMenu: 'agent', + }, + children: [ + { + path: '/agent/manager', + name: 'AgentManager', + component: () => import('@/views/agent/manager/index.vue'), + meta: { + title: 'Agent管理', + requiresAuth: true, + roles: ['*'] + } + } + ] +} + +export default AGENT diff --git a/openGauss-datakit/visualtool-ui/src/utils/websocket.ts b/openGauss-datakit/visualtool-ui/src/utils/websocket.ts index 90c9b07b5d7e62586ee7e2248c39212c65020346..b4cd98639b5d4e4494079d3250588a0b45176c8c 100644 --- a/openGauss-datakit/visualtool-ui/src/utils/websocket.ts +++ b/openGauss-datakit/visualtool-ui/src/utils/websocket.ts @@ -3,6 +3,7 @@ export type MessageCallback = (e: RT) => void interface Ioptions { url: string | null // The address of the linked channel + path?: string | null heartTime?: number // heartbeat interval heartMsg?: string // Heartbeat information, the default is 'ping' isReconnect?: boolean // Whether to automatically reconnect @@ -53,7 +54,8 @@ export default class Socket extends Heart { reconnectCount = 10 // Variables are saved to prevent loss options: Ioptions = { - url: null, // The address of the linked channel + url: null, // The address of the linked channel, + path: 'websocket', heartTime: 5000, // heartbeat interval heartMsg: 'ping', // Heartbeat information, the default is 'ping' isReconnect: true, // Whether to automatically reconnect @@ -94,10 +96,10 @@ export default class Socket extends Heart { console.log('get locaion host: ', window.location.host) let wsUrl if (process.env.NODE_ENV === 'development') { - wsUrl = `wss://${process.env.VUE_APP_WS_BASE_URL}/websocket/${this.options.url}` + wsUrl = `wss://${process.env.VUE_APP_WS_BASE_URL}/${this.options.path}/${this.options.url}` } else { const wsPrefix = window.location.protocol.includes('https') ? 'wss' : 'ws' - wsUrl = `${wsPrefix}://${window.location.host}/websocket/${this.options.url}` + wsUrl = `${wsPrefix}://${window.location.host}/${this.options.path}/${this.options.url}` } this.ws = new WebSocket(wsUrl) this.onopen(this.options.openCb as Callback) @@ -168,8 +170,16 @@ export default class Socket extends Heart { * Custom send message event * @param {String} data text sent */ - send (data: T | string): void { + send (data: string): void { console.log('doNothing', data) + this.ws.send(data) + // if(!!this.ws && this.ws.readyState === 3) { + // this.ws.close() + // this.create() + // } else if (this.ws.readyState === 1) { + // this.ws.send(data) + // } + // this.ws.send(data); } /** diff --git a/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/AddAgent.vue b/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/AddAgent.vue new file mode 100644 index 0000000000000000000000000000000000000000..0b9910980e5a71d52acc6140074753689f33a958 --- /dev/null +++ b/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/AddAgent.vue @@ -0,0 +1,390 @@ + + + + + diff --git a/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/RestartAgent.vue b/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/RestartAgent.vue new file mode 100644 index 0000000000000000000000000000000000000000..85e1be35ee3bf7aa2de939c0f0993092b4ae9945 --- /dev/null +++ b/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/RestartAgent.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/UnInstallAgent.vue b/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/UnInstallAgent.vue new file mode 100644 index 0000000000000000000000000000000000000000..f2e1357aecc1080870898f83aae646dfa0a4e1eb --- /dev/null +++ b/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/UnInstallAgent.vue @@ -0,0 +1,166 @@ + + + + + diff --git a/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/UpgradeAgent.vue b/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/UpgradeAgent.vue new file mode 100644 index 0000000000000000000000000000000000000000..5f1c34eb8ddd40077051c7b07ae9e6ff36b9038e --- /dev/null +++ b/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/UpgradeAgent.vue @@ -0,0 +1,223 @@ + + + + + diff --git a/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/UploadAgent.vue b/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/UploadAgent.vue new file mode 100644 index 0000000000000000000000000000000000000000..9e97fc31b2d2eb220bb8ecccb198982793657455 --- /dev/null +++ b/openGauss-datakit/visualtool-ui/src/views/agent/manager/components/UploadAgent.vue @@ -0,0 +1,244 @@ + + + + + diff --git a/openGauss-datakit/visualtool-ui/src/views/agent/manager/index.vue b/openGauss-datakit/visualtool-ui/src/views/agent/manager/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..95dbfb7081dbb02e56cdb2098120f16f869a9bf5 --- /dev/null +++ b/openGauss-datakit/visualtool-ui/src/views/agent/manager/index.vue @@ -0,0 +1,379 @@ + + + + + diff --git a/openGauss-datakit/visualtool-ui/src/views/resource/database/AddJdbc.vue b/openGauss-datakit/visualtool-ui/src/views/resource/database/AddJdbc.vue index 8a5e4d52c076f6cccc180f3ee334420603906055..d1148d07dd3cf5299a937227f5fb78a1a1a344d8 100644 --- a/openGauss-datakit/visualtool-ui/src/views/resource/database/AddJdbc.vue +++ b/openGauss-datakit/visualtool-ui/src/views/resource/database/AddJdbc.vue @@ -73,7 +73,7 @@ import { addJdbc, editJdbc, hostListAll } from '@/api/ops' import { Message } from '@arco-design/web-vue' import JdbcInstance from './JdbcInstance.vue' import { useI18n } from 'vue-i18n' -// import { encryptPassword } from '@/utils/jsencrypt' + const { t } = useI18n() enum jdbcStatusEnum { unTest = -1, @@ -103,6 +103,7 @@ const data = reactive({ ] }) const formRef = ref(null) + const handleCustomChange = (val: boolean) => { formRef.value?.clearValidate() if (val) { @@ -219,7 +220,6 @@ const submit = () => { return } - // save data.loading = true const param: { @@ -423,7 +423,8 @@ const open = (type: string, editData?: KeyValue) => { username: item.username, password: item.password, props: getProps(item.url), - status: jdbcStatusEnum.unTest + status: jdbcStatusEnum.unTest, + agentId: item.agentId } data.form.nodes.push(temp) }) diff --git a/openGauss-datakit/visualtool-ui/src/views/resource/database/JdbcInstance.vue b/openGauss-datakit/visualtool-ui/src/views/resource/database/JdbcInstance.vue index dd2ed2b8fc6056d96ea5307e661c5754ba4c4d75..9ac0735ae45a74e0ad6b78559044be9080e97db3 100644 --- a/openGauss-datakit/visualtool-ui/src/views/resource/database/JdbcInstance.vue +++ b/openGauss-datakit/visualtool-ui/src/views/resource/database/JdbcInstance.vue @@ -15,6 +15,13 @@ + + + + {{ item.agentName + "(" + item.ip + ")" }} + + +