diff --git a/docker/service/Dockerfile b/docker/service/Dockerfile index b846a739..1a2bc6d4 100644 --- a/docker/service/Dockerfile +++ b/docker/service/Dockerfile @@ -17,12 +17,19 @@ RUN \ ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime && \ echo "${TZ}" > /etc/timezone +# 复制启动脚本 +COPY ./service/entrypoint.sh /app/entrypoint.sh +RUN chmod +x /app/entrypoint.sh + # 复制 jar 包 COPY ./service/orion-visor-launch.jar /app/app.jar +# 复制探针包 +ADD ./service/agent-release.tar.gz /app/agent-release # 启动检测 HEALTHCHECK --interval=15s --timeout=5s --retries=5 --start-period=10s \ CMD wget -T5 -qO- http://127.0.0.1:9200/orion-visor/api/server/bootstrap/health | grep ok || exit 1 # 启动 +ENTRYPOINT ["/app/entrypoint.sh"] CMD ["java", "-jar", "/app/app.jar"] diff --git a/docker/service/entrypoint.sh b/docker/service/entrypoint.sh new file mode 100644 index 00000000..12ee8bf0 --- /dev/null +++ b/docker/service/entrypoint.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +AGENT_RELEASE_DIR="/root/orion/orion-visor/agent-release" +DEFAULT_AGENT_DIR="/app/agent-release" + +# 确保父目录存在 +mkdir -p "$(dirname "$AGENT_RELEASE_DIR")" + +# 加载探针 +if [ -d "$AGENT_RELEASE_DIR" ] && [ -n "$(ls -A "$AGENT_RELEASE_DIR" 2>/dev/null)" ]; then + echo "Using mounted agent release: $AGENT_RELEASE_DIR" +else + echo "Using default agent release: $DEFAULT_AGENT_DIR" + # 复制探针 + cp -rf "$DEFAULT_AGENT_DIR" "$AGENT_RELEASE_DIR" +fi + +# 打印探针版本信息 +if [ -f "$AGENT_RELEASE_DIR/.version" ]; then + echo "Agent version: $(cat "$AGENT_RELEASE_DIR/.version")" +fi + +exec "$@" \ No newline at end of file diff --git a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/AutoConfigureOrderConst.java b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/AutoConfigureOrderConst.java index e652083a..2b089ba3 100644 --- a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/AutoConfigureOrderConst.java +++ b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/AutoConfigureOrderConst.java @@ -53,21 +53,23 @@ public interface AutoConfigureOrderConst { int FRAMEWORK_REDIS_CACHE = Integer.MIN_VALUE + 2000; - int FRAMEWORK_CONFIG = Integer.MIN_VALUE + 2100; + int FRAMEWORK_INFLUXDB = Integer.MIN_VALUE + 2100; - int FRAMEWORK_ENCRYPT = Integer.MIN_VALUE + 2200; + int FRAMEWORK_CONFIG = Integer.MIN_VALUE + 2300; - int FRAMEWORK_STORAGE = Integer.MIN_VALUE + 2300; + int FRAMEWORK_CYPHER = Integer.MIN_VALUE + 2400; - int FRAMEWORK_JOB = Integer.MIN_VALUE + 2400; + int FRAMEWORK_STORAGE = Integer.MIN_VALUE + 2500; - int FRAMEWORK_JOB_QUARTZ = Integer.MIN_VALUE + 2500; + int FRAMEWORK_JOB = Integer.MIN_VALUE + 2600; - int FRAMEWORK_JOB_ASYNC = Integer.MIN_VALUE + 2600; + int FRAMEWORK_JOB_QUARTZ = Integer.MIN_VALUE + 2700; - int FRAMEWORK_MONITOR = Integer.MIN_VALUE + 2700; + int FRAMEWORK_JOB_ASYNC = Integer.MIN_VALUE + 2800; - int FRAMEWORK_BIZ_OPERATOR_LOG = Integer.MIN_VALUE + 2800; + int FRAMEWORK_MONITOR = Integer.MIN_VALUE + 2900; + + int FRAMEWORK_BIZ_OPERATOR_LOG = Integer.MIN_VALUE + 3000; int FRAMEWORK_BANNER = Integer.MIN_VALUE + 10000; diff --git a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/BeanOrderConst.java b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/BeanOrderConst.java index a84c8b3b..7c898e04 100644 --- a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/BeanOrderConst.java +++ b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/BeanOrderConst.java @@ -31,24 +31,29 @@ package org.dromara.visor.common.constant; */ public interface BeanOrderConst { - /** - * 公共返回值包装处理器 - */ - int RESPONSE_ADVICE_WRAPPER = Integer.MIN_VALUE + 1000; - /** * 演示模式切面 */ - int DEMO_DISABLE_API_ASPECT = Integer.MIN_VALUE + 10; + int DEMO_DISABLE_API_ASPECT = Integer.MIN_VALUE + 100; /** * 全局日志打印 */ - int LOG_PRINT_ASPECT = Integer.MIN_VALUE + 20; + int LOG_PRINT_ASPECT = Integer.MIN_VALUE + 200; + + /** + * 暴露接口切面 + */ + int EXPOSE_API_ASPECT = Integer.MIN_VALUE + 300; /** * 操作日志切面 */ - int OPERATOR_LOG_ASPECT = Integer.MIN_VALUE + 30; + int OPERATOR_LOG_ASPECT = Integer.MIN_VALUE + 400; + + /** + * 公共返回值包装处理器 + */ + int RESPONSE_ADVICE_WRAPPER = Integer.MIN_VALUE + 1000; } diff --git a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/CustomHeaderConst.java b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/CustomHeaderConst.java index 3f1017cc..5e96e40d 100644 --- a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/CustomHeaderConst.java +++ b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/CustomHeaderConst.java @@ -33,4 +33,8 @@ public interface CustomHeaderConst { String APP_VERSION = "X-App-Version"; + String AGENT_KEY_HEADER = "X-Agent-Key"; + + String AGENT_VERSION_HEADER = "X-Agent-Version"; + } diff --git a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/ErrorCode.java b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/ErrorCode.java index 9e981d47..d1dcd803 100644 --- a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/ErrorCode.java +++ b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/ErrorCode.java @@ -48,6 +48,8 @@ public enum ErrorCode implements CodeInfo { UNAUTHORIZED(401, "当前认证信息已失效, 请重新登录"), + EXPOSE_UNAUTHORIZED(401, "当前认证信息错误, 请检查后重试"), + FORBIDDEN(403, "无操作权限"), NOT_FOUND(404, "未找到该资源"), diff --git a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/ErrorMessage.java b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/ErrorMessage.java index ae874b64..c1463e93 100644 --- a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/ErrorMessage.java +++ b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/ErrorMessage.java @@ -102,7 +102,7 @@ public interface ErrorMessage { String HOST_TYPE_ERROR = "主机类型错误"; - String HOST_NOT_ENABLED = "主机未启用"; + String HOST_NOT_ENABLED = "{} 主机未启用"; String CONFIG_NOT_ENABLED = "配置未启用"; @@ -146,6 +146,8 @@ public interface ErrorMessage { String FILE_ABSENT = "文件不存在"; + String FILE_EXTENSION_TYPE = "文件类型不正确"; + String FILE_ABSENT_CLEAR = "文件不存在 (可能已被清理)"; String LOG_ABSENT = "日志不存在"; @@ -158,6 +160,8 @@ public interface ErrorMessage { String FILE_UPLOAD_ERROR = "文件上传失败"; + String CALC_SIGN_FAILED = "计算签名失败"; + String SCRIPT_UPLOAD_ERROR = "脚本上传失败"; String EXEC_ERROR = "执行失败"; @@ -182,6 +186,8 @@ public interface ErrorMessage { String COMPRESS_FILE_ABSENT = "压缩文件不存在"; + String DECOMPRESS_FILE_ABSENT = "压缩文件不存在"; + String UNABLE_DOWNLOAD_FOLDER = "无法下载文件夹"; String VALID_ERROR = "验证失败"; @@ -209,6 +215,27 @@ public interface ErrorMessage { || ex instanceof ApplicationException; } + /** + * 获取错误信息 + * + * @param ex ex + * @return message + */ + static String getErrorMessage(Exception ex) { + return getErrorMessage(ex, ErrorMessage.EXEC_ERROR, 0); + } + + /** + * 获取错误信息 + * + * @param ex ex + * @param len len + * @return message + */ + static String getErrorMessage(Exception ex, int len) { + return getErrorMessage(ex, ErrorMessage.EXEC_ERROR, len); + } + /** * 获取错误信息 * @@ -217,6 +244,18 @@ public interface ErrorMessage { * @return message */ static String getErrorMessage(Exception ex, String defaultMsg) { + return getErrorMessage(ex, defaultMsg, 0); + } + + /** + * 获取错误信息 + * + * @param ex ex + * @param defaultMsg defaultMsg + * @param len len + * @return message + */ + static String getErrorMessage(Exception ex, String defaultMsg, int len) { if (ex == null) { return null; } @@ -226,7 +265,11 @@ public interface ErrorMessage { } // 业务异常 if (isBizException(ex)) { - return message; + if (len > 0) { + return Strings.retain(message, len); + } else { + return message; + } } return defaultMsg; } diff --git a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/ExtraFieldConst.java b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/ExtraFieldConst.java index acbaf3e1..830d6739 100644 --- a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/ExtraFieldConst.java +++ b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/ExtraFieldConst.java @@ -35,6 +35,8 @@ public interface ExtraFieldConst extends FieldConst { String TRACE_ID = "traceId"; + String TASK_ID = "taskId"; + String IDENTITY = "identity"; String GROUP_NAME = "groupName"; @@ -69,4 +71,6 @@ public interface ExtraFieldConst extends FieldConst { String DARK = "dark"; + String AGENT_KEY = "agentKey"; + } diff --git a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/FieldConst.java b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/FieldConst.java index 9097021a..539875e1 100644 --- a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/FieldConst.java +++ b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/FieldConst.java @@ -45,12 +45,18 @@ public interface FieldConst { String LABEL = "label"; + String FIELD = "field"; + String TYPE = "type"; String COLOR = "color"; + String LOADING = "loading"; + String STATUS = "status"; + String SWITCH = "switch"; + String INFO = "info"; String EXTRA = "extra"; @@ -71,6 +77,8 @@ public interface FieldConst { String SEQ = "seq"; + String START = "start"; + String PATH = "path"; String ADDRESS = "address"; @@ -119,4 +127,12 @@ public interface FieldConst { String CONFIG = "config"; + String VERSION = "version"; + + String SYNCED = "synced"; + + String SIGN = "sign"; + + String SIGN_SHORT = "signShort"; + } diff --git a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/FileConst.java b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/FileConst.java index df4b1d5f..8995c4f3 100644 --- a/orion-visor-common/src/main/java/org/dromara/visor/common/constant/FileConst.java +++ b/orion-visor-common/src/main/java/org/dromara/visor/common/constant/FileConst.java @@ -37,4 +37,16 @@ public interface FileConst { String SCRIPT = "script"; + String AGENT = "agent"; + + String AGENT_RELEASE = "agent-release"; + + String AGENT_RELEASE_TEMP = "agent-release-temp"; + + String AGENT_RELEASE_TAR_GZ = "agent-release.tar.gz"; + + String VERSION = ".version"; + + String CONFIG_YAML = "config.yaml"; + } diff --git a/orion-visor-common/src/main/java/org/dromara/visor/common/entity/chart/TimeChartSeries.java b/orion-visor-common/src/main/java/org/dromara/visor/common/entity/chart/TimeChartSeries.java new file mode 100644 index 00000000..670b8c62 --- /dev/null +++ b/orion-visor-common/src/main/java/org/dromara/visor/common/entity/chart/TimeChartSeries.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.common.entity.chart; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.Map; + +/** + * 时序图系列 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/9/3 21:08 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "TimeChartSeries", description = "时序图系列") +public class TimeChartSeries { + + @Schema(description = "name") + private String name; + + @Schema(description = "颜色") + private String color; + + @Schema(description = "tags") + private Map tags; + + @Schema(description = "数据 [0]timestampMills [1]value") + private List> data; + +} diff --git a/orion-visor-common/src/main/java/org/dromara/visor/common/session/config/BaseConnectConfig.java b/orion-visor-common/src/main/java/org/dromara/visor/common/session/config/BaseConnectConfig.java index e9d0d82b..785d8ab9 100644 --- a/orion-visor-common/src/main/java/org/dromara/visor/common/session/config/BaseConnectConfig.java +++ b/orion-visor-common/src/main/java/org/dromara/visor/common/session/config/BaseConnectConfig.java @@ -63,6 +63,9 @@ public class BaseConnectConfig implements IBaseConnectConfig { @Schema(description = "主机端口") private Integer hostPort; + @Schema(description = "agentKey") + private String agentKey; + @Schema(description = "用户名") private String username; diff --git a/orion-visor-common/src/main/java/org/dromara/visor/common/session/config/IBaseConnectConfig.java b/orion-visor-common/src/main/java/org/dromara/visor/common/session/config/IBaseConnectConfig.java index f6893156..cbba6814 100644 --- a/orion-visor-common/src/main/java/org/dromara/visor/common/session/config/IBaseConnectConfig.java +++ b/orion-visor-common/src/main/java/org/dromara/visor/common/session/config/IBaseConnectConfig.java @@ -61,6 +61,10 @@ public interface IBaseConnectConfig { void setHostPort(Integer hostPort); + String getAgentKey(); + + void setAgentKey(String agentKey); + String getUsername(); void setUsername(String username); diff --git a/orion-visor-common/src/main/java/org/dromara/visor/common/validator/group/Id.java b/orion-visor-common/src/main/java/org/dromara/visor/common/validator/group/Id.java index 5fccd109..6bc5930d 100644 --- a/orion-visor-common/src/main/java/org/dromara/visor/common/validator/group/Id.java +++ b/orion-visor-common/src/main/java/org/dromara/visor/common/validator/group/Id.java @@ -23,7 +23,7 @@ package org.dromara.visor.common.validator.group; /** - * 分页验证分组 + * id 验证分组 * * @author Jiahang Li * @version 1.0.0 diff --git a/orion-visor-common/src/main/java/org/dromara/visor/common/validator/group/Key.java b/orion-visor-common/src/main/java/org/dromara/visor/common/validator/group/Key.java new file mode 100644 index 00000000..6bbe8ea6 --- /dev/null +++ b/orion-visor-common/src/main/java/org/dromara/visor/common/validator/group/Key.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.common.validator.group; + +/** + * key 验证分组 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023/9/1 19:13 + */ +public interface Key { +} diff --git a/orion-visor-dependencies/pom.xml b/orion-visor-dependencies/pom.xml index cd7ee7c8..6991b4f3 100644 --- a/orion-visor-dependencies/pom.xml +++ b/orion-visor-dependencies/pom.xml @@ -31,6 +31,7 @@ 1.2.16 3.18.0 2.14.2 + 6.6.0 4.11.0 1.0.7 7.2.11.RELEASE @@ -54,8 +55,12 @@ ${orion.kit.version} - orion-log cn.orionsec.kit + orion-log + + + cn.orionsec.kit + orion-generator @@ -146,6 +151,11 @@ orion-visor-spring-boot-starter-test ${revision} + + org.dromara.visor + orion-visor-spring-boot-starter-influxdb + ${revision} + org.dromara.visor orion-visor-spring-boot-starter-biz-operator-log @@ -272,6 +282,13 @@ ${transmittable.thread.local.version} + + + com.influxdb + influxdb-client-java + ${influxdb.client.version} + + org.springframework.boot diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-cipher/src/main/java/org/dromara/visor/framework/encrypt/configuration/OrionEncryptAutoConfiguration.java b/orion-visor-framework/orion-visor-spring-boot-starter-cipher/src/main/java/org/dromara/visor/framework/encrypt/configuration/OrionEncryptAutoConfiguration.java index 36110dfa..27c5864b 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-cipher/src/main/java/org/dromara/visor/framework/encrypt/configuration/OrionEncryptAutoConfiguration.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-cipher/src/main/java/org/dromara/visor/framework/encrypt/configuration/OrionEncryptAutoConfiguration.java @@ -22,10 +22,10 @@ */ package org.dromara.visor.framework.encrypt.configuration; -import org.dromara.visor.common.config.ConfigStore; -import org.dromara.visor.common.constant.AutoConfigureOrderConst; import org.dromara.visor.common.cipher.AesEncryptor; import org.dromara.visor.common.cipher.RsaDecryptor; +import org.dromara.visor.common.config.ConfigStore; +import org.dromara.visor.common.constant.AutoConfigureOrderConst; import org.dromara.visor.common.utils.AesEncryptUtils; import org.dromara.visor.common.utils.RsaParamDecryptUtils; import org.dromara.visor.framework.encrypt.configuration.config.AesEncryptConfig; @@ -45,7 +45,7 @@ import org.springframework.context.annotation.Bean; */ @AutoConfiguration @EnableConfigurationProperties({AesEncryptConfig.class}) -@AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_ENCRYPT) +@AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_CYPHER) public class OrionEncryptAutoConfiguration { /** diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/pom.xml b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/pom.xml new file mode 100644 index 00000000..fe47372d --- /dev/null +++ b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/pom.xml @@ -0,0 +1,39 @@ + + + + org.dromara.visor + orion-visor-framework + ${revision} + + + 4.0.0 + orion-visor-spring-boot-starter-influxdb + ${project.artifactId} + jar + + 项目 influxdb 配置包 + https://github.com/dromara/orion-visor + + + + + org.dromara.visor + orion-visor-common + + + + + com.influxdb + influxdb-client-java + + + + + org.springframework.boot + spring-boot-starter-web + + + + \ No newline at end of file diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/java/org/dromara/visor/framework/influxdb/configuration/OrionInfluxdbAutoConfiguration.java b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/java/org/dromara/visor/framework/influxdb/configuration/OrionInfluxdbAutoConfiguration.java new file mode 100644 index 00000000..e6982f35 --- /dev/null +++ b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/java/org/dromara/visor/framework/influxdb/configuration/OrionInfluxdbAutoConfiguration.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.framework.influxdb.configuration; + +import cn.orionsec.kit.lang.utils.Strings; +import com.influxdb.LogLevel; +import com.influxdb.client.InfluxDBClient; +import com.influxdb.client.InfluxDBClientFactory; +import com.influxdb.client.InfluxDBClientOptions; +import org.dromara.visor.common.constant.AutoConfigureOrderConst; +import org.dromara.visor.framework.influxdb.configuration.config.InfluxdbConfig; +import org.dromara.visor.framework.influxdb.core.utils.InfluxdbUtils; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigureOrder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Lazy; + +import java.net.ConnectException; + +/** + * influxdb 配置类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/10 20:35 + */ +@Lazy(false) +@AutoConfiguration +@AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_INFLUXDB) +@ConditionalOnProperty(value = "spring.influxdb.enabled", havingValue = "true") +@EnableConfigurationProperties(InfluxdbConfig.class) +public class OrionInfluxdbAutoConfiguration { + + /** + * TODO 重连 + * + * @param config config + * @return influxdb 客户端 + */ + @Bean(name = "influxDBClient") + public InfluxDBClient influxDBClient(InfluxdbConfig config) throws ConnectException { + // 参数 + InfluxDBClientOptions options = InfluxDBClientOptions.builder() + .url(config.getUrl()) + .authenticateToken(config.getToken().toCharArray()) + .org(config.getOrg()) + .bucket(config.getBucket()) + .logLevel(LogLevel.NONE) + .build(); + // 客户端 + InfluxDBClient client = InfluxDBClientFactory.create(options); + // 尝试连接 + Boolean ping = client.ping(); + if (!ping) { + throw new ConnectException(Strings.format("connect to influxdb failed. url: {}, org: {}", config.getUrl(), config.getOrg())); + } + // 设置工具类 + InfluxdbUtils.setInfluxClient(config.getBucket(), client); + return client; + } + +} diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/java/org/dromara/visor/framework/influxdb/configuration/config/InfluxdbConfig.java b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/java/org/dromara/visor/framework/influxdb/configuration/config/InfluxdbConfig.java new file mode 100644 index 00000000..c9d53f61 --- /dev/null +++ b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/java/org/dromara/visor/framework/influxdb/configuration/config/InfluxdbConfig.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.framework.influxdb.configuration.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * influxdb 配置 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/10 20:36 + */ +@Data +@ConfigurationProperties("spring.influxdb") +public class InfluxdbConfig { + + /** + * url + */ + private String url; + + /** + * org + */ + private String org; + + /** + * bucket + */ + private String bucket; + + /** + * apiToken + */ + private String token; + +} diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/java/org/dromara/visor/framework/influxdb/core/query/FluxQueryBuilder.java b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/java/org/dromara/visor/framework/influxdb/core/query/FluxQueryBuilder.java new file mode 100644 index 00000000..1e479080 --- /dev/null +++ b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/java/org/dromara/visor/framework/influxdb/core/query/FluxQueryBuilder.java @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.framework.influxdb.core.query; + +import cn.orionsec.kit.lang.utils.collect.Collections; +import cn.orionsec.kit.lang.utils.collect.Lists; +import org.dromara.visor.common.constant.Const; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * flux 查询构建器 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/9/3 16:08 + */ +public class FluxQueryBuilder { + + private final StringBuilder query; + + private boolean hasFilter; + + private boolean pretty; + + private FluxQueryBuilder(String bucket) { + this.query = new StringBuilder(); + this.query.append(String.format("from(bucket: \"%s\")", bucket)); + } + + /** + * 创建构建器 + * + * @param bucket bucket + * @return builder + */ + public static FluxQueryBuilder from(String bucket) { + return new FluxQueryBuilder(bucket); + } + + /** + * 时间范围 + * + * @param start 开始时间 + * @param end 结束时间 + * @return this + */ + public FluxQueryBuilder range(long start, long end) { + query.append(String.format(" |> range(start: %s, stop: %s)", Instant.ofEpochMilli(start), Instant.ofEpochMilli(end))); + return this; + } + + /** + * 时间范围 + * + * @param range range + * @return this + */ + public FluxQueryBuilder range(String range) { + query.append(String.format(" |> range(start: %s)", range)); + return this; + } + + /** + * 过滤 measurement + * + * @param measurement measurement + * @return this + */ + public FluxQueryBuilder measurement(String measurement) { + this.appendFilter(String.format("r[\"_measurement\"] == \"%s\"", measurement)); + this.closeFilter(); + return this; + } + + /** + * 过滤单个 field + * + * @param field field + * @return this + */ + public FluxQueryBuilder field(String field) { + this.appendFilter(String.format("r[\"_field\"] == \"%s\"", field)); + this.closeFilter(); + return this; + } + + /** + * 过滤多个 field + * + * @param fields fields + * @return this + */ + public FluxQueryBuilder fields(Collection fields) { + if (Collections.isEmpty(fields)) { + return this; + } + List conditions = new ArrayList<>(); + for (String field : fields) { + conditions.add(String.format("r[\"_field\"] == \"%s\"", field)); + } + this.appendFilter(String.join(" or ", conditions)); + this.closeFilter(); + return this; + } + + /** + * 过滤 tag key + * + * @param value value + * @return this + */ + public FluxQueryBuilder key(String value) { + return this.tag(Const.KEY, value); + } + + /** + * 过滤 tag key + * + * @param values values + * @return this + */ + public FluxQueryBuilder key(Collection values) { + return this.tag(Const.KEY, values); + } + + /** + * 过滤 tag name + * + * @param value value + * @return this + */ + public FluxQueryBuilder name(String value) { + return this.tag(Const.NAME, value); + } + + /** + * 过滤 tag name + * + * @param values values + * @return this + */ + public FluxQueryBuilder name(Collection values) { + return this.tag(Const.NAME, values); + } + + /** + * 过滤 tag + * + * @return this + */ + public FluxQueryBuilder tag(String key, String value) { + this.appendFilter(String.format("r[\"%s\"] == \"%s\"", key, value)); + this.closeFilter(); + return this; + } + + /** + * 过滤 tag + * + * @param key key + * @param values values + * @return this + */ + public FluxQueryBuilder tag(String key, Collection values) { + if (values == null || values.isEmpty()) { + return this; + } + if (values.size() == 1) { + return this.tag(key, Collections.first(values)); + } + // + Collection conditions = values.stream() + .map(value -> String.format("r[\"%s\"] == \"%s\"", key, value)) + .collect(Collectors.toList()); + this.appendFilter(String.join(" or ", conditions)); + this.closeFilter(); + return this; + } + + /** + * 过滤多个 tag + * tag 使用 and + * value 使用 or + * + * @param tags tags + * @return this + */ + public FluxQueryBuilder tags(Map> tags) { + for (Map.Entry> entry : tags.entrySet()) { + String key = entry.getKey(); + Collection values = entry.getValue(); + if (Collections.isEmpty(values)) { + continue; + } + if (values.size() == 1) { + // 单值直接用等号 + String singleValue = values.iterator().next(); + this.appendFilter(String.format("r[\"%s\"] == \"%s\"", key, singleValue)); + } else { + // 多值用 OR + Collection conditions = values.stream() + .map(v -> String.format("r[\"%s\"] == \"%s\"", key, v)) + .collect(Collectors.toList()); + this.appendFilter("(" + String.join(" or ", conditions) + ")"); + } + } + this.closeFilter(); + return this; + } + + /** + * 聚合窗口 + */ + public FluxQueryBuilder aggregateWindow(String every, String fn) { + query.append(String.format(" |> aggregateWindow(every: %s, fn: %s)", every, fn)); + return this; + } + + /** + * 聚合窗口 + */ + public FluxQueryBuilder aggregateWindow(String every, String fn, boolean createEmpty) { + query.append(String.format(" |> aggregateWindow(every: %s, fn: %s, createEmpty: %b)", every, fn, createEmpty)); + return this; + } + + /** + * 排序 + * + * @param columns columns + * @return this + */ + public FluxQueryBuilder sort(List columns) { + StringBuilder cols = new StringBuilder(); + for (int i = 0; i < columns.size(); i++) { + cols.append("\"").append(columns.get(i)).append("\""); + if (i < columns.size() - 1) cols.append(", "); + } + query.append(String.format(" |> sort(columns: [%s])", cols)); + return this; + } + + /** + * 降序 + * + * @param column column + * @return this + */ + public FluxQueryBuilder sortDesc(String column) { + return this.sort(Lists.singleton("-" + column)); + } + + /** + * 升序 + * + * @param column column + * @return this + */ + public FluxQueryBuilder sortAsc(String column) { + return this.sort(Lists.singleton(column)); + } + + /** + * 限制条数 + * + * @param n limit + * @return this + */ + public FluxQueryBuilder limit(int n) { + query.append(String.format(" |> limit(n: %d)", n)); + return this; + } + + /** + * 基础过滤拼接 + */ + private void appendFilter(String condition) { + if (!hasFilter) { + query.append(" |> filter(fn: (r) => "); + this.hasFilter = true; + } else { + query.append(" and "); + } + query.append(condition); + } + + /** + * 结束 filter 并闭合括号 + */ + private void closeFilter() { + if (hasFilter) { + query.append(")"); + this.hasFilter = false; + } + } + + /** + * 设置美观输出 + * + * @return this + */ + public FluxQueryBuilder pretty() { + this.pretty = true; + return this; + } + + /** + * 构建查询 + */ + public String build() { + if (this.pretty) { + return query.toString().replaceAll("\\|>", "\n |>"); + } else { + return query.toString(); + } + } + + @Override + public String toString() { + return this.build(); + } + +} diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/java/org/dromara/visor/framework/influxdb/core/utils/InfluxdbUtils.java b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/java/org/dromara/visor/framework/influxdb/core/utils/InfluxdbUtils.java new file mode 100644 index 00000000..71a7d901 --- /dev/null +++ b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/java/org/dromara/visor/framework/influxdb/core/utils/InfluxdbUtils.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.framework.influxdb.core.utils; + +import cn.orionsec.kit.lang.utils.Exceptions; +import cn.orionsec.kit.lang.utils.collect.Lists; +import com.influxdb.client.InfluxDBClient; +import com.influxdb.client.WriteApi; +import com.influxdb.client.write.Point; +import com.influxdb.query.FluxRecord; +import com.influxdb.query.FluxTable; +import org.dromara.visor.common.constant.Const; +import org.dromara.visor.common.entity.chart.TimeChartSeries; +import org.dromara.visor.framework.influxdb.core.query.FluxQueryBuilder; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * influxdb 工具类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/10 20:47 + */ +public class InfluxdbUtils { + + private static final String FIELD_KEY = "_field"; + + private static final List SKIP_EXTRA_KEY = Lists.of("result", "table", "_measurement", "_start", "_stop", "_time", "_value"); + + private static InfluxDBClient client; + + private static String bucket; + + private InfluxdbUtils() { + } + + /** + * 写入指标 + * + * @param points points + */ + public static void writePoints(List points) { + try (WriteApi api = client.makeWriteApi()) { + // 写入指标 + api.writePoints(points); + } + } + + /** + * 查询数据点 + * + * @param query query + * @return points + */ + public static List queryTable(String query) { + return client.getQueryApi().query(query); + } + + /** + * 查询数据点 + * + * @param query query + * @return points + */ + public static FluxTable querySingleTable(String query) { + return Lists.first(queryTable(query)); + } + + /** + * 查询时序系列 + * + * @param query query + * @return points + */ + public static List querySeries(String query) { + return toSeries(queryTable(query)); + } + + /** + * 查询时序系列 + * + * @param query query + * @return points + */ + public static TimeChartSeries querySingleSeries(String query) { + return toSeries(querySingleTable(query)); + } + + /** + * 转为时序系列 + * + * @param table table + * @return series + */ + public static TimeChartSeries toSeries(FluxTable table) { + // 数据 + Map tags = new HashMap<>(); + List> dataList = new ArrayList<>(); + for (FluxRecord record : table.getRecords()) { + Instant time = record.getTime(); + if (time == null) { + continue; + } + // 设置数据 + List data = new ArrayList<>(2); + data.add(time.toEpochMilli()); + data.add(record.getValue()); + dataList.add(data); + // 设置额外值 + record.getValues().forEach((k, v) -> { + if (SKIP_EXTRA_KEY.contains(k)) { + return; + } + tags.put(k, v); + }); + } + // 设置 field + tags.put(Const.FIELD, tags.get(FIELD_KEY)); + tags.remove(FIELD_KEY); + // 创建 series + return TimeChartSeries.builder() + .data(dataList) + .tags(tags) + .build(); + } + + /** + * 转为时序系列 + * + * @param tables tables + * @return series + */ + public static List toSeries(List tables) { + return tables.stream() + .map(InfluxdbUtils::toSeries) + .collect(Collectors.toList()); + } + + /** + * 获取查询构建器 + * + * @return builder + */ + public static FluxQueryBuilder query() { + return FluxQueryBuilder.from(bucket); + } + + public static void setInfluxClient(String bucket, InfluxDBClient client) { + if (InfluxdbUtils.client != null) { + // unmodified + throw Exceptions.state(); + } + InfluxdbUtils.client = client; + InfluxdbUtils.bucket = bucket; + } + +} diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 00000000..28c7773f --- /dev/null +++ b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,37 @@ +{ + "groups": [ + { + "name": "spring.influxdb", + "type": "org.dromara.visor.framework.influxdb.configuration.config.InfluxdbConfig", + "sourceType": "org.dromara.visor.framework.influxdb.configuration.config.InfluxdbConfig" + } + ], + "properties": [ + { + "name": "spring.influxdb.enabled", + "type": "java.lang.Boolean", + "description": "是否启用 influxdb.", + "defaultValue": "false" + }, + { + "name": "spring.influxdb.url", + "type": "java.lang.String", + "description": "influxdb 地址." + }, + { + "name": "spring.influxdb.org", + "type": "java.lang.String", + "description": "influxdb org." + }, + { + "name": "spring.influxdb.bucket", + "type": "java.lang.String", + "description": "influxdb bucket." + }, + { + "name": "spring.influxdb.token", + "type": "java.lang.String", + "description": "influxdb token." + } + ] +} \ No newline at end of file diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000..3eda3a8a --- /dev/null +++ b/orion-visor-framework/orion-visor-spring-boot-starter-influxdb/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.visor.framework.influxdb.configuration.OrionInfluxdbAutoConfiguration \ No newline at end of file diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-job/src/main/java/org/dromara/visor/framework/job/configuration/OrionAsyncAutoConfiguration.java b/orion-visor-framework/orion-visor-spring-boot-starter-job/src/main/java/org/dromara/visor/framework/job/configuration/OrionAsyncAutoConfiguration.java index 30427ded..7544e5b8 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-job/src/main/java/org/dromara/visor/framework/job/configuration/OrionAsyncAutoConfiguration.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-job/src/main/java/org/dromara/visor/framework/job/configuration/OrionAsyncAutoConfiguration.java @@ -23,13 +23,13 @@ package org.dromara.visor.framework.job.configuration; import org.dromara.visor.common.constant.AutoConfigureOrderConst; +import org.dromara.visor.common.constant.Const; import org.dromara.visor.common.thread.ThreadPoolMdcTaskExecutor; import org.dromara.visor.framework.job.configuration.config.AsyncExecutorConfig; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.annotation.EnableAsync; @@ -49,13 +49,10 @@ import java.util.concurrent.ThreadPoolExecutor; public class OrionAsyncAutoConfiguration { /** - * 支持 MDC 的异步线程池 - *

* {@code @Async("asyncExecutor")} * - * @return 异步线程池 + * @return 支持 MDC 的异步线程池 */ - @Primary @Bean(name = "asyncExecutor") public TaskExecutor asyncExecutor(AsyncExecutorConfig config) { ThreadPoolMdcTaskExecutor executor = new ThreadPoolMdcTaskExecutor(); @@ -75,4 +72,25 @@ public class OrionAsyncAutoConfiguration { return executor; } + /** + * {@code @Async("metricsExecutor")} + * + * @return 指标线程池 + */ + @Bean(name = "metricsExecutor") + public TaskExecutor metricsExecutor() { + ThreadPoolMdcTaskExecutor executor = new ThreadPoolMdcTaskExecutor(); + executor.setCorePoolSize(4); + executor.setMaxPoolSize(8); + executor.setQueueCapacity(1000); + executor.setKeepAliveSeconds(Const.MS_S_60); + executor.setAllowCoreThreadTimeOut(true); + executor.setThreadNamePrefix("metrics-task-"); + executor.setWaitForTasksToCompleteOnShutdown(true); + executor.setAwaitTerminationSeconds(60); + executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + executor.initialize(); + return executor; + } + } diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-log/src/main/java/org/dromara/visor/framework/log/core/interceptor/AbstractLogPrinterInterceptor.java b/orion-visor-framework/orion-visor-spring-boot-starter-log/src/main/java/org/dromara/visor/framework/log/core/interceptor/AbstractLogPrinterInterceptor.java index 2b219c1a..f0411deb 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-log/src/main/java/org/dromara/visor/framework/log/core/interceptor/AbstractLogPrinterInterceptor.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-log/src/main/java/org/dromara/visor/framework/log/core/interceptor/AbstractLogPrinterInterceptor.java @@ -22,6 +22,7 @@ */ package org.dromara.visor.framework.log.core.interceptor; +import cn.orionsec.kit.lang.utils.Strings; import cn.orionsec.kit.lang.utils.collect.Maps; import cn.orionsec.kit.lang.utils.reflect.Classes; import com.alibaba.fastjson.JSON; @@ -31,8 +32,8 @@ import com.alibaba.fastjson.serializer.ValueFilter; import org.aopalliance.intercept.MethodInvocation; import org.dromara.visor.common.json.FieldDesensitizeFilter; import org.dromara.visor.common.json.FieldIgnoreFilter; -import org.dromara.visor.common.trace.TraceIdHolder; import org.dromara.visor.common.security.SecurityHolder; +import org.dromara.visor.common.trace.TraceIdHolder; import org.dromara.visor.framework.log.configuration.config.LogPrinterConfig; import org.dromara.visor.framework.log.core.annotation.IgnoreLog; import org.dromara.visor.framework.log.core.enums.IgnoreLogMode; @@ -42,12 +43,13 @@ import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Date; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; -import java.util.function.Predicate; /** * 日志打印拦截器 基类 @@ -60,11 +62,6 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce private static final ThreadLocal IGNORE_LOG_MODE = new ThreadLocal<>(); - /** - * 请求头过滤器 - */ - protected Predicate headerFilter; - /** * 字段过滤器 */ @@ -93,8 +90,6 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce @Override public void init() { - // 请求头过滤器 - this.headerFilter = header -> config.getHeaders().contains(header); // 参数过滤器 this.serializeFilters = new SerializeFilter[]{ // 忽略字段过滤器 @@ -136,6 +131,24 @@ public abstract class AbstractLogPrinterInterceptor implements LogPrinterInterce } } + /** + * 获取请求头 + * + * @param request request + * @return headers + */ + protected Map getHeaderMap(HttpServletRequest request) { + Map headers = new LinkedHashMap<>(); + for (String headerName : config.getHeaders()) { + String headerValue = request.getHeader(headerName); + if (Strings.isBlank(headerValue)) { + continue; + } + headers.put(headerName, headerValue); + } + return headers; + } + /** * 打印请求信息 * diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-log/src/main/java/org/dromara/visor/framework/log/core/interceptor/PrettyLogPrinterInterceptor.java b/orion-visor-framework/orion-visor-spring-boot-starter-log/src/main/java/org/dromara/visor/framework/log/core/interceptor/PrettyLogPrinterInterceptor.java index 1031ad25..d0aee0dc 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-log/src/main/java/org/dromara/visor/framework/log/core/interceptor/PrettyLogPrinterInterceptor.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-log/src/main/java/org/dromara/visor/framework/log/core/interceptor/PrettyLogPrinterInterceptor.java @@ -84,13 +84,11 @@ public class PrettyLogPrinterInterceptor extends AbstractLogPrinterInterceptor { if (request != null) { // remoteAddr requestLog.append("\tremoteAddr: ").append(IpUtils.getRemoteAddr(request)).append('\n'); - // header - Servlets.getHeaderMap(request).forEach((hk, hv) -> { - if (headerFilter.test(hk.toLowerCase())) { - requestLog.append('\t') - .append(hk).append(": ") - .append(hv).append('\n'); - } + // headers + this.getHeaderMap(request).forEach((hk, hv) -> { + requestLog.append('\t') + .append(hk).append(": ") + .append(hv).append('\n'); }); } Method method = invocation.getMethod(); diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-log/src/main/java/org/dromara/visor/framework/log/core/interceptor/RowLogPrinterInterceptor.java b/orion-visor-framework/orion-visor-spring-boot-starter-log/src/main/java/org/dromara/visor/framework/log/core/interceptor/RowLogPrinterInterceptor.java index 6e7696a0..20d47322 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-log/src/main/java/org/dromara/visor/framework/log/core/interceptor/RowLogPrinterInterceptor.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-log/src/main/java/org/dromara/visor/framework/log/core/interceptor/RowLogPrinterInterceptor.java @@ -85,14 +85,8 @@ public class RowLogPrinterInterceptor extends AbstractLogPrinterInterceptor impl if (request != null) { // remoteAddr fields.put(REMOTE_ADDR, IpUtils.getRemoteAddr(request)); - // header - Map headers = new LinkedHashMap<>(); - Servlets.getHeaderMap(request).forEach((hk, hv) -> { - if (headerFilter.test(hk.toLowerCase())) { - headers.put(hk, hv); - } - }); - fields.put(HEADERS, headers); + // headers + fields.put(HEADERS, this.getHeaderMap(request)); } Method method = invocation.getMethod(); // 方法签名 diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/domain/BaseDO.java b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/domain/BaseDO.java index e15ccd3e..03feba02 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/domain/BaseDO.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/domain/BaseDO.java @@ -66,7 +66,7 @@ public class BaseDO implements Serializable { private String creator; @Schema(description = "修改人") - @TableField(fill = FieldFill.INSERT_UPDATE, jdbcType = JdbcType.VARCHAR) + @TableField(fill = FieldFill.INSERT_UPDATE, update = "IFNULL(#{et.updater}, updater)", jdbcType = JdbcType.VARCHAR) private String updater; /** @@ -78,4 +78,4 @@ public class BaseDO implements Serializable { @TableField(fill = FieldFill.INSERT, jdbcType = JdbcType.TINYINT) private Boolean deleted; -} \ No newline at end of file +} diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/CodeGenerators.java b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/CodeGenerators.java index 1cd3bd16..1396b731 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/CodeGenerators.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/CodeGenerators.java @@ -54,12 +54,13 @@ public class CodeGenerators { // 作者 String author = Const.ORION_AUTHOR; // 模块 - String module = "infra"; + String module = "asset"; // 生成的表 Table[] tables = { // Template.create("dict_key", "字典配置项", "dict") // .enableProviderApi() // .disableUnitTest() + // .enableDeleteUseBatch() // .cache("dict:keys", "字典配置项") // .expire(8, TimeUnit.HOURS) // .vue("system", "dict-key") @@ -73,23 +74,28 @@ public class CodeGenerators { // .color("blue", "gray", "red", "green", "white") // .valueUseFields() // .build(), - // Template.create("exec_template_host", "执行模板主机", "exec") - // .enableProviderApi() - // .cache("sl", "22") - // .vue("exec", "exec-template-host") - // .build(), - Template.create("system_message", "系统消息", "message") + + Template.create("host_agent_log", "主机探针日志", "agent") .disableUnitTest() - .enableProviderApi() - .vue("system", "message") - .dict("messageType", "type", "messageType") - .comment("消息类型") - .fields("EXEC_FAILED", "UPLOAD_FAILED") - .labels("执行失败", "上传失败") - .extra("tagLabel", "执行失败", "上传失败") - .extra("tagVisible", true, true) - .extra("tagColor", "red", "red") + .vue("monitor", "monitor-host") + .disableRowSelection() + .enableCardView() + .enableDrawerForm() + + .dict("agentLogType", "type") + .comment("探针日志类型") + .fields("OFFLINE", "ONLINE", "INSTALL", "START", "STOP") + .labels("下线", "上线", "安装", "启动", "停止") .valueUseFields() + + .dict("agentLogStatus", "status") + .comment("探针日志状态") + .fields("WAIT", "RUNNING", "SUCCESS", "FAILED") + .labels("等待中", "运行中", "成功", "失败") + .color("green", "green", "arcoblue", "red") + .loading(true, true, false, false) + .valueUseFields() + .build(), }; // jdbc 配置 - 使用配置文件 @@ -98,7 +104,6 @@ public class CodeGenerators { String url = resolveConfigValue(yaml.getValue("spring.datasource.druid.url")); String username = resolveConfigValue(yaml.getValue("spring.datasource.druid.username")); String password = resolveConfigValue(yaml.getValue("spring.datasource.druid.password")); - // 执行 runGenerator(outputDir, author, tables, module, diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/core/CodeGenerator.java b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/core/CodeGenerator.java index 462ada82..258e70c7 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/core/CodeGenerator.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/core/CodeGenerator.java @@ -194,6 +194,8 @@ public class CodeGenerator implements Executable { case Types.BIT: case Types.TINYINT: return DbColumnType.INTEGER; + case Types.DOUBLE: + return DbColumnType.DOUBLE; default: return typeRegistry.getColumnType(metaInfo); } @@ -327,9 +329,14 @@ public class CodeGenerator implements Executable { */ private InjectionConfig getInjectionConfig() { String[][] customFileDefineArr = new String[][]{ - // -------------------- 后端 - module -------------------- + // -------------------- 后端 -------------------- // http 文件 new String[]{"/templates/orion-server-module-controller.http.vm", "${type}Controller.http", "controller"}, + // operator log define 文件 + new String[]{"/templates/orion-server-module-operator-key-define.java.vm", "${type}OperatorType.java", "define.operator"}, + // convert 文件 + new String[]{"/templates/orion-server-module-convert.java.vm", "${type}Convert.java", "convert"}, + // -------------------- 后端 - 实体 -------------------- // vo 文件 new String[]{"/templates/orion-server-module-entity-vo.java.vm", "${type}VO.java", "entity.vo"}, // create request 文件 @@ -338,19 +345,19 @@ public class CodeGenerator implements Executable { new String[]{"/templates/orion-server-module-entity-request-update.java.vm", "${type}UpdateRequest.java", "entity.request.${bizPackage}"}, // query request 文件 new String[]{"/templates/orion-server-module-entity-request-query.java.vm", "${type}QueryRequest.java", "entity.request.${bizPackage}"}, - // convert 文件 - new String[]{"/templates/orion-server-module-convert.java.vm", "${type}Convert.java", "convert"}, + // -------------------- 后端 - 缓存 -------------------- // cache dto 文件 new String[]{"/templates/orion-server-module-cache-dto.java.vm", "${type}CacheDTO.java", "entity.dto"}, // cache key define 文件 new String[]{"/templates/orion-server-module-cache-key-define.java.vm", "${type}CacheKeyDefine.java", "define.cache"}, - // operator log define 文件 - new String[]{"/templates/orion-server-module-operator-key-define.java.vm", "${type}OperatorType.java", "define.operator"}, // -------------------- 后端 - provider -------------------- // api 文件 new String[]{"/templates/orion-server-provider-api.java.vm", "${type}Api.java", "api"}, // api impl 文件 new String[]{"/templates/orion-server-provider-api-impl.java.vm", "${type}ApiImpl.java", "api.impl"}, + // convert 文件 + new String[]{"/templates/orion-server-provider-convert.java.vm", "${type}ProviderConvert.java", "convert"}, + // -------------------- 后端 - provider 实体 -------------------- // dto 文件 new String[]{"/templates/orion-server-provider-entity-dto.java.vm", "${type}DTO.java", "entity.dto.${bizPackage}"}, // create dto 文件 @@ -359,8 +366,6 @@ public class CodeGenerator implements Executable { new String[]{"/templates/orion-server-provider-entity-dto-update.java.vm", "${type}UpdateDTO.java", "entity.dto.${bizPackage}"}, // query dto 文件 new String[]{"/templates/orion-server-provider-entity-dto-query.java.vm", "${type}QueryDTO.java", "entity.dto.${bizPackage}"}, - // convert 文件 - new String[]{"/templates/orion-server-provider-convert.java.vm", "${type}ProviderConvert.java", "convert"}, // -------------------- 后端 - test -------------------- // service unit test 文件 new String[]{"/templates/orion-server-test-service-impl-tests.java.vm", "${type}ServiceImplTests.java", "service.impl"}, @@ -375,22 +380,26 @@ public class CodeGenerator implements Executable { new String[]{"/templates/orion-vue-router.ts.vm", "${feature}.ts", "vue/router/routes/modules"}, // views index.ts 文件 new String[]{"/templates/orion-vue-views-index.vue.vm", "index.vue", "vue/views/${module}/${feature}"}, + // const.ts 文件 + new String[]{"/templates/orion-vue-views-types-const.ts.vm", "const.ts", "vue/views/${module}/${feature}/types"}, + // -------------------- 前端 - form -------------------- // form-modal.vue 文件 new String[]{"/templates/orion-vue-views-components-form-modal.vue.vm", "${feature}-form-modal.vue", "vue/views/${module}/${feature}/components"}, // form-drawer.vue 文件 new String[]{"/templates/orion-vue-views-components-form-drawer.vue.vm", "${feature}-form-drawer.vue", "vue/views/${module}/${feature}/components"}, - // table.vue 文件 - new String[]{"/templates/orion-vue-views-components-table.vue.vm", "${feature}-table.vue", "vue/views/${module}/${feature}/components"}, - // card-list.vue 文件 - new String[]{"/templates/orion-vue-views-components-card-list.vue.vm", "${feature}-card-list.vue", "vue/views/${module}/${feature}/components"}, - // const.ts 文件 - new String[]{"/templates/orion-vue-views-types-const.ts.vm", "const.ts", "vue/views/${module}/${feature}/types"}, // form.rules.ts 文件 new String[]{"/templates/orion-vue-views-types-form.rules.ts.vm", "form.rules.ts", "vue/views/${module}/${feature}/types"}, + // -------------------- 前端 - table -------------------- + // table.vue 文件 + new String[]{"/templates/orion-vue-views-components-table.vue.vm", "${feature}-table.vue", "vue/views/${module}/${feature}/components"}, // table.columns.ts 文件 new String[]{"/templates/orion-vue-views-types-table.columns.ts.vm", "table.columns.ts", "vue/views/${module}/${feature}/types"}, + // -------------------- 前端 - card -------------------- + // card-list.vue 文件 + new String[]{"/templates/orion-vue-views-components-card-list.vue.vm", "${feature}-card-list.vue", "vue/views/${module}/${feature}/components"}, // card.fields.ts 文件 new String[]{"/templates/orion-vue-views-types-card.fields.ts.vm", "card.fields.ts", "vue/views/${module}/${feature}/types"}, + // -------------------- sql -------------------- // menu.sql 文件 new String[]{"/templates/orion-sql-menu.sql.vm", "${tableName}-menu.sql", "sql"}, // dict.sql 文件 diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/core/DictParser.java b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/core/DictParser.java index e66a8487..10f163e8 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/core/DictParser.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/core/DictParser.java @@ -81,7 +81,7 @@ public class DictParser { meta.setComment(Strings.def(tableField.getComment(), meta.getField())); } // 设置额外参数 schema - if (meta.getExtraValues().size() > 0) { + if (!meta.getExtraValues().isEmpty()) { List> extraSchema = meta.getExtraValues().get(0) .keySet() .stream() diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/template/DictTemplate.java b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/template/DictTemplate.java index 376ca74b..4ddd1100 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/template/DictTemplate.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/java/org/dromara/visor/framework/mybatis/core/generator/template/DictTemplate.java @@ -165,6 +165,16 @@ public class DictTemplate extends Template { return this.extra(Const.COLOR, colors); } + /** + * 添加 loading + * + * @param loading loading + * @return this + */ + public DictTemplate loading(Object... loading) { + return this.extra(Const.LOADING, loading); + } + /** * 添加额外值 * diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-views-components-card-list.vue.vm b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-views-components-card-list.vue.vm index d0be119d..81142dbf 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-views-components-card-list.vue.vm +++ b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-views-components-card-list.vue.vm @@ -133,14 +133,14 @@ const cardColLayout = useCardColLayout(); const pagination = useCardPagination(); + const { loading, setLoading } = useLoading(); const queryOrder = useQueryOrder(TableName, ASC); const { cardFieldConfig, fieldsHook } = useCardFieldConfig(TableName, fieldConfig); - const { loading, setLoading } = useLoading(); #if($dictMap.entrySet().size() > 0) const { toOptions, getDictValue } = useDictStore(); #end - const list = ref<${vue.featureEntity}QueryResponse[]>([]); + const list = ref>([]); const formRef = ref(); const formModel = reactive<${vue.featureEntity}QueryRequest>({ searchValue: undefined, diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-views-components-table.vue.vm b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-views-components-table.vue.vm index 909163ed..0b0b2bce 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-views-components-table.vue.vm +++ b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-views-components-table.vue.vm @@ -172,9 +172,9 @@ const rowSelection = useRowSelection(); #end const pagination = useTablePagination(); + const { loading, setLoading } = useLoading(); const queryOrder = useQueryOrder(TableName, ASC); const { tableColumns, columnsHook } = useTableColumns(TableName, columns); - const { loading, setLoading } = useLoading(); #if($dictMap.entrySet().size() > 0) const { toOptions, getDictValue } = useDictStore(); #end diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-views-types-table.columns.ts.vm b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-views-types-table.columns.ts.vm index a33cfb03..94c7f49e 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-views-types-table.columns.ts.vm +++ b/orion-visor-framework/orion-visor-spring-boot-starter-mybatis/src/main/resources/templates/orion-vue-views-types-table.columns.ts.vm @@ -19,6 +19,8 @@ const columns = [ minWidth: 238, ellipsis: true, tooltip: true, + #elseif(${field.propertyType} == 'Integer' || ${field.propertyType} == 'Long') + width: 120, #elseif(${field.propertyType} == 'Date') width: 180, render: ({ record }) => { diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-redis/src/main/java/org/dromara/visor/framework/redis/core/utils/RedisStrings.java b/orion-visor-framework/orion-visor-spring-boot-starter-redis/src/main/java/org/dromara/visor/framework/redis/core/utils/RedisStrings.java index 5cc8a1cd..65c18d9f 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-redis/src/main/java/org/dromara/visor/framework/redis/core/utils/RedisStrings.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-redis/src/main/java/org/dromara/visor/framework/redis/core/utils/RedisStrings.java @@ -32,6 +32,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Collectors; /** @@ -49,6 +50,42 @@ public class RedisStrings extends RedisUtils { private RedisStrings() { } + /** + * 获取值 + * + * @param key key + * @return value + */ + public static String get(String key) { + return redisTemplate.opsForValue().get(key); + } + + /** + * 获取值 + * + * @param define define + * @return value + */ + public static String get(CacheKeyDefine define) { + return get(define.getKey()); + } + + /** + * 获取值 + * + * @param key key + * @param mapper mapper + * @param T + * @return value + */ + public static T get(String key, Function mapper) { + String value = redisTemplate.opsForValue().get(key); + if (value == null) { + return null; + } + return mapper.apply(value); + } + /** * 获取 json * @@ -56,11 +93,7 @@ public class RedisStrings extends RedisUtils { * @return JSONObject */ public static JSONObject getJson(String key) { - String value = redisTemplate.opsForValue().get(key); - if (value == null) { - return null; - } - return JSON.parseObject(value); + return get(key, JSON::parseObject); } /** @@ -95,57 +128,7 @@ public class RedisStrings extends RedisUtils { * @return T */ public static T getJson(String key, Class type) { - String value = redisTemplate.opsForValue().get(key); - if (value == null) { - return null; - } - return (T) JSON.parseObject(value, type); - } - - /** - * 获取 json 列表 - * - * @param keys keys - * @return cache - */ - public static List getJsonList(Collection keys) { - List values = redisTemplate.opsForValue().multiGet(keys); - if (values == null) { - return new ArrayList<>(); - } - return values.stream() - .map(JSON::parseObject) - .collect(Collectors.toList()); - } - - /** - * 获取 json 列表 - * - * @param keys keys - * @param define define - * @param T - * @return cache - */ - public static List getJsonList(Collection keys, CacheKeyDefine define) { - return getJsonList(keys, (Class) define.getType()); - } - - /** - * 获取 json 列表 - * - * @param keys keys - * @param type type - * @param T - * @return cache - */ - public static List getJsonList(Collection keys, Class type) { - List values = redisTemplate.opsForValue().multiGet(keys); - if (values == null) { - return new ArrayList<>(); - } - return values.stream() - .map(s -> JSON.parseObject(s, type)) - .collect(Collectors.toList()); + return get(key, s -> JSON.parseObject(s, type)); } /** @@ -155,11 +138,7 @@ public class RedisStrings extends RedisUtils { * @return JSONArray */ public static JSONArray getJsonArray(String key) { - String value = redisTemplate.opsForValue().get(key); - if (value == null) { - return null; - } - return JSON.parseArray(value); + return get(key, JSON::parseArray); } /** @@ -194,11 +173,69 @@ public class RedisStrings extends RedisUtils { * @return T */ public static List getJsonArray(String key, Class type) { - String value = redisTemplate.opsForValue().get(key); - if (value == null) { - return null; + return get(key, s -> JSON.parseArray(s, type)); + } + + /** + * 获取 json 列表 + * + * @param keys keys + * @return cache + */ + public static List getList(Collection keys) { + return getList(keys, Function.identity()); + } + + /** + * 获取 json 列表 + * + * @param keys keys + * @param mapper mapper + * @param T + * @return cache + */ + public static List getList(Collection keys, Function mapper) { + List values = redisTemplate.opsForValue().multiGet(keys); + if (values == null) { + return new ArrayList<>(); } - return JSON.parseArray(value, type); + return values.stream() + .map(mapper) + .collect(Collectors.toList()); + } + + /** + * 获取 json 列表 + * + * @param keys keys + * @return cache + */ + public static List getJsonList(Collection keys) { + return getList(keys, JSON::parseObject); + } + + /** + * 获取 json 列表 + * + * @param keys keys + * @param define define + * @param T + * @return cache + */ + public static List getJsonList(Collection keys, CacheKeyDefine define) { + return getList(keys, s -> JSON.parseObject(s, (Class) define.getType())); + } + + /** + * 获取 json 列表 + * + * @param keys keys + * @param type type + * @param T + * @return cache + */ + public static List getJsonList(Collection keys, Class type) { + return getList(keys, s -> JSON.parseObject(s, type)); } /** @@ -208,13 +245,7 @@ public class RedisStrings extends RedisUtils { * @return cache */ public static List getJsonArrayList(Collection keys) { - List values = redisTemplate.opsForValue().multiGet(keys); - if (values == null) { - return new ArrayList<>(); - } - return values.stream() - .map(JSON::parseArray) - .collect(Collectors.toList()); + return getList(keys, JSON::parseArray); } /** @@ -226,7 +257,7 @@ public class RedisStrings extends RedisUtils { * @return cache */ public static List> getJsonArrayList(Collection keys, CacheKeyDefine define) { - return getJsonArrayList(keys, (Class) define.getType()); + return getList(keys, s -> JSON.parseArray(s, (Class) define.getType())); } /** @@ -238,13 +269,7 @@ public class RedisStrings extends RedisUtils { * @return cache */ public static List> getJsonArrayList(Collection keys, Class type) { - List values = redisTemplate.opsForValue().multiGet(keys); - if (values == null) { - return new ArrayList<>(); - } - return values.stream() - .map(s -> JSON.parseArray(s, type)) - .collect(Collectors.toList()); + return getList(keys, s -> JSON.parseArray(s, type)); } /** diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-security/src/main/java/org/dromara/visor/framework/security/core/handler/AuthenticationEntryPointHandler.java b/orion-visor-framework/orion-visor-spring-boot-starter-security/src/main/java/org/dromara/visor/framework/security/core/handler/AuthenticationEntryPointHandler.java index 6e96dbf6..3f50e731 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-security/src/main/java/org/dromara/visor/framework/security/core/handler/AuthenticationEntryPointHandler.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-security/src/main/java/org/dromara/visor/framework/security/core/handler/AuthenticationEntryPointHandler.java @@ -46,6 +46,7 @@ public class AuthenticationEntryPointHandler implements AuthenticationEntryPoint @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException { + log.warn("AuthenticationEntryPoint-commence-401 {}", request.getRequestURI()); log.debug("AuthenticationEntryPoint-commence-unauthorized {}", request.getRequestURI(), e); Servlets.writeHttpWrapper(response, ErrorCode.UNAUTHORIZED.getWrapper()); } diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/configuration/OrionWebAutoConfiguration.java b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/configuration/OrionWebAutoConfiguration.java index 46b53817..3c90dcbe 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/configuration/OrionWebAutoConfiguration.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/configuration/OrionWebAutoConfiguration.java @@ -28,7 +28,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.dromara.visor.common.constant.AutoConfigureOrderConst; import org.dromara.visor.common.constant.FilterOrderConst; import org.dromara.visor.common.web.WebFilterCreator; +import org.dromara.visor.framework.web.configuration.config.ExposeApiConfig; import org.dromara.visor.framework.web.core.aspect.DemoDisableApiAspect; +import org.dromara.visor.framework.web.core.aspect.ExposeApiAspect; import org.dromara.visor.framework.web.core.filter.TraceIdFilter; import org.dromara.visor.framework.web.core.handler.GlobalExceptionHandler; import org.dromara.visor.framework.web.core.handler.WrapperResultHandler; @@ -37,6 +39,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.http.MediaType; @@ -50,6 +53,7 @@ import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.nio.charset.StandardCharsets; @@ -67,8 +71,12 @@ import java.util.List; */ @AutoConfiguration @AutoConfigureOrder(AutoConfigureOrderConst.FRAMEWORK_WEB) +@EnableConfigurationProperties(ExposeApiConfig.class) public class OrionWebAutoConfiguration implements WebMvcConfigurer { + @Value("${orion.prefix}") + private String orionPrefix; + @Value("${orion.api.prefix}") private String orionApiPrefix; @@ -77,7 +85,14 @@ public class OrionWebAutoConfiguration implements WebMvcConfigurer { // 公共 api 前缀 AntPathMatcher antPathMatcher = new AntPathMatcher("."); configurer.addPathPrefix(orionApiPrefix, clazz -> clazz.isAnnotationPresent(RestController.class) - && antPathMatcher.match("org.dromara.visor.**.controller.**", clazz.getPackage().getName())); + && antPathMatcher.match("org.dromara.visor.module.**.controller.**", clazz.getPackage().getName())); + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + // 公共模板前缀 + registry.addResourceHandler(orionPrefix + "/template/**") + .addResourceLocations("classpath:/public/template/"); } /** @@ -171,4 +186,13 @@ public class OrionWebAutoConfiguration implements WebMvcConfigurer { return new DemoDisableApiAspect(); } + /** + * @param config config + * @return 对外服务 api 切面 + */ + @Bean + public ExposeApiAspect exposeApiAspect(ExposeApiConfig config) { + return new ExposeApiAspect(config); + } + } diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/configuration/config/ExposeApiConfig.java b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/configuration/config/ExposeApiConfig.java new file mode 100644 index 00000000..49e39feb --- /dev/null +++ b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/configuration/config/ExposeApiConfig.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.framework.web.configuration.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 对外服务配置属性 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/22 19:57 + */ +@Data +@ConfigurationProperties("orion.api.expose") +public class ExposeApiConfig { + + /** + * 对外服务请求头 + */ + private String header; + + /** + * 对外服务请求值 + */ + private String token; + +} diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/annotation/ExposeApi.java b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/annotation/ExposeApi.java new file mode 100644 index 00000000..a51ea6c3 --- /dev/null +++ b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/annotation/ExposeApi.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.framework.web.core.annotation; + +import javax.annotation.security.PermitAll; +import java.lang.annotation.*; + +/** + * 对外服务 api 注解 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/22 9:59 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@PermitAll +public @interface ExposeApi { + + /** + * @return 请求来源 + */ + String source() default ""; + +} diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/aspect/DemoDisableApiAspect.java b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/aspect/DemoDisableApiAspect.java index 2dc45e96..54bf5724 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/aspect/DemoDisableApiAspect.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/aspect/DemoDisableApiAspect.java @@ -22,7 +22,6 @@ */ package org.dromara.visor.framework.web.core.aspect; -import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @@ -39,7 +38,6 @@ import org.springframework.core.annotation.Order; * @since 2024/5/21 16:52 */ @Aspect -@Slf4j @Order(BeanOrderConst.DEMO_DISABLE_API_ASPECT) public class DemoDisableApiAspect { diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/aspect/ExposeApiAspect.java b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/aspect/ExposeApiAspect.java new file mode 100644 index 00000000..d413438b --- /dev/null +++ b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/aspect/ExposeApiAspect.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.framework.web.core.aspect; + +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Before; +import org.aspectj.lang.annotation.Pointcut; +import org.dromara.visor.common.constant.BeanOrderConst; +import org.dromara.visor.common.constant.ErrorCode; +import org.dromara.visor.framework.web.configuration.config.ExposeApiConfig; +import org.dromara.visor.framework.web.core.annotation.ExposeApi; +import org.springframework.core.annotation.Order; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.util.Optional; + +/** + * 对外服务 api 切面 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/22 16:52 + */ +@Slf4j +@Aspect +@Order(BeanOrderConst.EXPOSE_API_ASPECT) +public class ExposeApiAspect { + + private final ExposeApiConfig config; + + public ExposeApiAspect(ExposeApiConfig config) { + this.config = config; + } + + @Pointcut("@annotation(e)") + public void exposeApi(ExposeApi e) { + } + + @Before(value = "exposeApi(e)", argNames = "e") + public void beforeExposeApi(ExposeApi e) { + // 获取请求 + HttpServletRequest request = Optional.ofNullable(RequestContextHolder.getRequestAttributes()) + .map(s -> (ServletRequestAttributes) s) + .map(ServletRequestAttributes::getRequest) + .orElse(null); + if (request == null) { + throw ErrorCode.EXPOSE_UNAUTHORIZED.exception(); + } + // 验证对外服务参数 + if (!config.getToken().equals(request.getHeader(config.getHeader()))) { + log.warn("expose api unauthorized, url: {}", request.getRequestURI()); + throw ErrorCode.EXPOSE_UNAUTHORIZED.exception(); + } + } + +} diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/handler/GlobalExceptionHandler.java b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/handler/GlobalExceptionHandler.java index 0a47cd58..cbfaf0b2 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/handler/GlobalExceptionHandler.java +++ b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/java/org/dromara/visor/framework/web/core/handler/GlobalExceptionHandler.java @@ -149,6 +149,7 @@ public class GlobalExceptionHandler { } @ExceptionHandler(value = { + LockException.class, TimeoutException.class, java.util.concurrent.TimeoutException.class }) diff --git a/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 996c79b1..ec187a88 100644 --- a/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/orion-visor-framework/orion-visor-spring-boot-starter-web/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,4 +1,11 @@ { + "groups": [ + { + "name": "orion.api.expose", + "type": "org.dromara.visor.framework.web.configuration.config.ExposeApiConfig", + "sourceType": "org.dromara.visor.framework.web.configuration.config.ExposeApiConfig" + } + ], "properties": [ { "name": "orion.version", @@ -25,6 +32,16 @@ "name": "orion.api.cors", "type": "java.lang.Boolean", "description": "是否开启 cors 过滤器." + }, + { + "name": "orion.api.expose.header", + "type": "java.lang.String", + "description": "对外服务请求头." + }, + { + "name": "orion.api.expose.token", + "type": "java.lang.String", + "description": "对外服务请求值." } ] } \ No newline at end of file diff --git a/orion-visor-framework/pom.xml b/orion-visor-framework/pom.xml index aab6e488..7cec0d7f 100644 --- a/orion-visor-framework/pom.xml +++ b/orion-visor-framework/pom.xml @@ -21,17 +21,18 @@ orion-visor-spring-boot-starter-swagger orion-visor-spring-boot-starter-datasource orion-visor-spring-boot-starter-mybatis + orion-visor-spring-boot-starter-cipher orion-visor-spring-boot-starter-config orion-visor-spring-boot-starter-job orion-visor-spring-boot-starter-websocket orion-visor-spring-boot-starter-redis orion-visor-spring-boot-starter-desensitize - orion-visor-spring-boot-starter-cipher orion-visor-spring-boot-starter-log orion-visor-spring-boot-starter-storage orion-visor-spring-boot-starter-security orion-visor-spring-boot-starter-monitor orion-visor-spring-boot-starter-test + orion-visor-spring-boot-starter-influxdb orion-visor-spring-boot-starter-biz-operator-log diff --git a/orion-visor-launch/pom.xml b/orion-visor-launch/pom.xml index a27591db..177d1b91 100644 --- a/orion-visor-launch/pom.xml +++ b/orion-visor-launch/pom.xml @@ -63,6 +63,11 @@ orion-visor-module-terminal-service ${revision} + + org.dromara.visor + orion-visor-module-monitor-service + ${revision} + @@ -125,6 +130,10 @@ org.dromara.visor orion-visor-spring-boot-starter-monitor + + org.dromara.visor + orion-visor-spring-boot-starter-influxdb + org.dromara.visor orion-visor-spring-boot-starter-biz-operator-log diff --git a/orion-visor-launch/src/main/java/org/dromara/visor/launch/LaunchApplication.java b/orion-visor-launch/src/main/java/org/dromara/visor/launch/LaunchApplication.java index fae60a26..a69d47ba 100644 --- a/orion-visor-launch/src/main/java/org/dromara/visor/launch/LaunchApplication.java +++ b/orion-visor-launch/src/main/java/org/dromara/visor/launch/LaunchApplication.java @@ -32,7 +32,9 @@ import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.stereotype.Component; +import java.util.Objects; import java.util.Optional; /** @@ -60,7 +62,7 @@ public class LaunchApplication { */ public static class CustomBeanNameGenerator implements BeanNameGenerator { - private static final String BEAN_ANNOTATION_CLASS_NAME = "org.springframework.stereotype.Component"; + private static final String BEAN_ANNOTATION_CLASS_NAME = Component.class.getName(); @Override public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { @@ -68,12 +70,12 @@ public class LaunchApplication { if (definition instanceof AnnotatedBeanDefinition) { AnnotationMetadata metadata = ((AnnotatedBeanDefinition) definition).getMetadata(); // 处理自定义 bean 名称 - return Optional.of(metadata) + return Objects.requireNonNull(Optional.of(metadata) .map(s -> s.getAnnotationAttributes(BEAN_ANNOTATION_CLASS_NAME)) .map(s -> s.get(Const.VALUE)) .map(Object::toString) .filter(Strings::isNotBlank) - .orElseGet(definition::getBeanClassName); + .orElseGet(definition::getBeanClassName)); } else { // 非注解形式默认使用默认名称 return BeanDefinitionReaderUtils.generateBeanName(definition, registry); diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/pom.xml b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/pom.xml index b9ddc97a..f8b19f9c 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/pom.xml +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/pom.xml @@ -20,6 +20,11 @@ org.dromara.visor orion-visor-common + + org.dromara.visor + orion-visor-module-infra-provider + ${revision} + \ No newline at end of file diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/api/HostAgentApi.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/api/HostAgentApi.java new file mode 100644 index 00000000..49c8cde6 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/api/HostAgentApi.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.api; + +import org.dromara.visor.module.asset.entity.dto.host.HostAgentLogDTO; + +import java.util.List; +import java.util.Map; + +/** + * 主机探针对外服务 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/9/1 21:14 + */ +public interface HostAgentApi { + + /** + * 查询主机探针安装日志 + * + * @param hostIdList hostIdList + * @return rows + */ + List selectAgentInstallLog(List hostIdList); + + /** + * 获取缓存名称 + * + * @param agentKeyList agentKeyList + * @return nameMap + */ + Map getCacheNameByAgentKey(List agentKeyList); + + /** + * 获取探针版本 + * + * @return version + */ + String getAgentVersion(); + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/api/HostApi.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/api/HostApi.java index 33a4dc1e..cc745ff4 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/api/HostApi.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/api/HostApi.java @@ -22,7 +22,9 @@ */ package org.dromara.visor.module.asset.api; +import cn.orionsec.kit.lang.define.wrapper.DataGrid; import org.dromara.visor.module.asset.entity.dto.host.HostDTO; +import org.dromara.visor.module.asset.entity.dto.host.HostQueryDTO; import java.util.List; @@ -51,4 +53,37 @@ public interface HostApi { */ List selectByIdList(List idList); + /** + * 通过 id 查询 agentKey + * + * @param id id + * @return agentKey + */ + String selectAgentKeyById(Long id); + + /** + * 分页查询主机信息 + * + * @param query query + * @return rows + */ + DataGrid getHostPage(HostQueryDTO query); + + + /** + * 通过 agentKey 查询 + * + * @param agentKey agentKey + * @return row + */ + HostDTO selectByAgentKey(String agentKey); + + /** + * 通过 agentKey 查询 + * + * @param agentKeys agentKeys + * @return row + */ + List selectByAgentKeys(List agentKeys); + } diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostAgentLogDTO.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostAgentLogDTO.java new file mode 100644 index 00000000..daeff621 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostAgentLogDTO.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.entity.dto.host; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Date; + +/** + * 主机探针安装日志 业务响应对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/9/1 17:34 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "HostAgentInstallLogDTO", description = "主机探针安装日志 业务响应对象") +public class HostAgentLogDTO implements Serializable { + + @Schema(description = "id") + private Long id; + + @Schema(description = "hostId") + private Long hostId; + + @Schema(description = "类型") + private String type; + + @Schema(description = "状态") + private String status; + + @Schema(description = "消息") + private String message; + + @Schema(description = "创建时间") + private Date createTime; + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostBaseDTO.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostBaseDTO.java index e9fba21f..6b0a3bf8 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostBaseDTO.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostBaseDTO.java @@ -67,7 +67,7 @@ public class HostBaseDTO implements Serializable { @Schema(description = "主机地址") private String address; - @Schema(description = "主机端口") - private Integer port; + @Schema(description = "agentKey") + private String agentKey; } diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostDTO.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostDTO.java index eaaf3346..06b6da2d 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostDTO.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostDTO.java @@ -27,9 +27,11 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.dromara.visor.module.infra.entity.dto.tag.TagDTO; import java.io.Serializable; import java.util.Date; +import java.util.List; import java.util.Set; /** @@ -69,12 +71,24 @@ public class HostDTO implements Serializable { @Schema(description = "主机地址") private String address; - @Schema(description = "主机端口") - private Integer port; - @Schema(description = "主机状态") private String status; + @Schema(description = "agentKey") + private String agentKey; + + @Schema(description = "探针版本") + private String agentVersion; + + @Schema(description = "探针安装状态") + private Integer agentInstallStatus; + + @Schema(description = "探针在线状态") + private Integer agentOnlineStatus; + + @Schema(description = "探针切换在线状态时间") + private Date agentOnlineChangeTime; + @Schema(description = "描述") private String description; @@ -93,6 +107,9 @@ public class HostDTO implements Serializable { @Schema(description = "是否收藏") private Boolean favorite; + @Schema(description = "tags") + private List tags; + @Schema(description = "分组 id") private Set groupIdList; @@ -114,7 +131,7 @@ public class HostDTO implements Serializable { .name(this.name) .code(this.code) .address(this.address) - .port(this.port) + .agentKey(this.agentKey) .build(); } diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostQueryDTO.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostQueryDTO.java new file mode 100644 index 00000000..126c0aa4 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/entity/dto/host/HostQueryDTO.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.entity.dto.host; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.visor.common.entity.BaseQueryRequest; + +import javax.validation.constraints.Size; +import java.util.List; + +/** + * 主机 查询请求对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023-9-11 14:16 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(name = "HostQueryDTO", description = "主机 查询请求对象") +public class HostQueryDTO extends BaseQueryRequest { + + @Schema(description = "搜索") + private String searchValue; + + @Schema(description = "id") + private Long id; + + @Schema(description = "id") + private List idList; + + @Size(max = 8) + @Schema(description = "主机类型") + private String type; + + @Size(max = 64) + @Schema(description = "主机名称") + private String name; + + @Size(max = 64) + @Schema(description = "主机编码") + private String code; + + @Size(max = 128) + @Schema(description = "主机地址") + private String address; + + @Size(max = 12) + @Schema(description = "系统类型") + private String osType; + + @Size(max = 12) + @Schema(description = "系统架构") + private String archType; + + @Size(max = 8) + @Schema(description = "主机状态") + private String status; + + @Size(max = 255) + @Schema(description = "描述") + private String description; + + @Schema(description = "agentKey") + private String agentKey; + + @Schema(description = "探针安装状态") + private Integer agentInstallStatus; + + @Schema(description = "探针在线状态") + private Integer agentOnlineStatus; + + @Schema(description = "通过探针排序") + private Boolean orderByAgent; + + @Schema(description = "tag") + private List tags; + + @Schema(description = "是否查询分组信息") + private Boolean queryGroup; + + @Schema(description = "是否查询 tag 信息") + private Boolean queryTag; + + @Schema(description = "是否查询规格信息") + private Boolean querySpec; + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/AgentInstallStatusEnum.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/AgentInstallStatusEnum.java new file mode 100644 index 00000000..69d07dfa --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/AgentInstallStatusEnum.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 探针安装状态 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/13 23:31 + */ +@Getter +@AllArgsConstructor +public enum AgentInstallStatusEnum { + + /** + * 未安装 + */ + NOT_INSTALL(0), + + /** + * 已安装 + */ + INSTALLED(1), + + ; + + private final Integer status; + + public static AgentInstallStatusEnum of(Integer status) { + if (status == null) { + return NOT_INSTALL; + } + for (AgentInstallStatusEnum value : AgentInstallStatusEnum.values()) { + if (value.status.equals(status)) { + return value; + } + } + return NOT_INSTALL; + } + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/AgentOnlineStatusEnum.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/AgentOnlineStatusEnum.java new file mode 100644 index 00000000..cd94e89c --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/AgentOnlineStatusEnum.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 探针在线状态 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/13 23:31 + */ +@Getter +@AllArgsConstructor +public enum AgentOnlineStatusEnum { + + /** + * 离线 + */ + OFFLINE(0), + + /** + * 在线 + */ + ONLINE(1), + + ; + + private final Integer value; + + public static AgentOnlineStatusEnum of(Integer value) { + if (value == null) { + return OFFLINE; + } + for (AgentOnlineStatusEnum e : AgentOnlineStatusEnum.values()) { + if (e.value.equals(value)) { + return e; + } + } + return OFFLINE; + } + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/HostOsTypeEnum.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/HostOsTypeEnum.java index ca4fc5a1..50051da4 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/HostOsTypeEnum.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/HostOsTypeEnum.java @@ -39,22 +39,24 @@ public enum HostOsTypeEnum { /** * linux */ - LINUX(".sh"), + LINUX(".sh", ""), /** * windows */ - WINDOWS(".cmd"), + WINDOWS(".cmd", ".exe"), /** * darwin */ - DARWIN(".sh"), + DARWIN(".sh", ""), ; private final String scriptSuffix; + private final String binarySuffix; + public boolean is(String type) { if (type == null) { return false; diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/HostTypeEnum.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/HostTypeEnum.java index e4bf6760..09765a0e 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/HostTypeEnum.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-provider/src/main/java/org/dromara/visor/module/asset/enums/HostTypeEnum.java @@ -76,6 +76,12 @@ public enum HostTypeEnum { return null; } + /** + * 获取类型 + * + * @param types types + * @return types + */ public static List split(String types) { if (types == null) { return new ArrayList<>(); @@ -87,6 +93,16 @@ public enum HostTypeEnum { .collect(Collectors.toList()); } + /** + * 是否包含此类型 + * + * @param types types + * @return contains + */ + public boolean contains(String types) { + return split(types).contains(this.name()); + } + @SuppressWarnings("unchecked") public T parse(String config) { return (T) JSON.parseObject(config, this.clazz); diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/pom.xml b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/pom.xml index 65bda5cb..c0e1beaf 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/pom.xml +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/pom.xml @@ -37,6 +37,11 @@ orion-visor-module-exec-provider ${revision} + + org.dromara.visor + orion-visor-module-monitor-provider + ${revision} + diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/api/impl/HostAgentApiImpl.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/api/impl/HostAgentApiImpl.java new file mode 100644 index 00000000..84a13b0c --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/api/impl/HostAgentApiImpl.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.api.impl; + +import cn.orionsec.kit.lang.define.cache.TimedCache; +import cn.orionsec.kit.lang.define.cache.TimedCacheBuilder; +import cn.orionsec.kit.lang.utils.Strings; +import cn.orionsec.kit.lang.utils.collect.Lists; +import org.dromara.visor.common.constant.Const; +import org.dromara.visor.framework.redis.core.utils.RedisStrings; +import org.dromara.visor.module.asset.api.HostAgentApi; +import org.dromara.visor.module.asset.convert.HostAgentLogProviderConvert; +import org.dromara.visor.module.asset.dao.HostAgentLogDAO; +import org.dromara.visor.module.asset.dao.HostDAO; +import org.dromara.visor.module.asset.define.cache.HostCacheKeyDefine; +import org.dromara.visor.module.asset.entity.domain.HostDO; +import org.dromara.visor.module.asset.entity.dto.host.HostAgentLogDTO; +import org.dromara.visor.module.asset.service.HostAgentService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 主机探针对外服务 实现 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/9/1 21:18 + */ +@Service +public class HostAgentApiImpl implements HostAgentApi { + + private static final TimedCache AGENT_NAME_CACHE = TimedCacheBuilder.create() + .expiredDelay(Const.MS_S_60 * 30) + .checkDelay(Const.MS_S_60) + .build(); + + @Resource + private HostDAO hostDAO; + + @Resource + private HostAgentLogDAO hostAgentLogDAO; + + @Resource + private HostAgentService hostAgentService; + + @Override + public List selectAgentInstallLog(List hostIdList) { + if (Lists.isEmpty(hostIdList)) { + return Lists.empty(); + } + // 查询缓存 + List keys = hostIdList.stream() + .map(HostCacheKeyDefine.HOST_INSTALL_LOG::format) + .collect(Collectors.toList()); + List logIdList = RedisStrings.getList(keys) + .stream() + .filter(Strings::isNotBlank) + .map(Long::parseLong) + .collect(Collectors.toList()); + // 查询数据库 + return hostAgentLogDAO.selectBatchIds(logIdList) + .stream() + .map(HostAgentLogProviderConvert.MAPPER::to) + .collect(Collectors.toList()); + } + + @Override + public Map getCacheNameByAgentKey(List agentKeyList) { + Map result = new HashMap<>(); + List queryList = new ArrayList<>(); + // 查询缓存 + for (String agentKey : agentKeyList) { + String name = AGENT_NAME_CACHE.get(agentKey); + if (name != null) { + result.put(agentKey, name); + } else { + queryList.add(agentKey); + } + } + // 查询数据库 + if (!queryList.isEmpty()) { + // 查询数据 + hostDAO.of() + .createWrapper() + .select(HostDO::getName, HostDO::getAgentKey) + .in(HostDO::getAgentKey, queryList) + .then() + .list() + .forEach(s -> result.put(s.getAgentKey(), s.getName())); + for (String agentKey : queryList) { + result.putIfAbsent(agentKey, Const.EMPTY); + AGENT_NAME_CACHE.put(agentKey, result.get(agentKey)); + } + } + return result; + } + + @Override + public String getAgentVersion() { + return hostAgentService.getAgentVersion(); + } + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/api/impl/HostApiImpl.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/api/impl/HostApiImpl.java index 419a98f6..b18b1407 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/api/impl/HostApiImpl.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/api/impl/HostApiImpl.java @@ -22,12 +22,17 @@ */ package org.dromara.visor.module.asset.api.impl; +import cn.orionsec.kit.lang.define.wrapper.DataGrid; import cn.orionsec.kit.lang.utils.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.dromara.visor.module.asset.api.HostApi; import org.dromara.visor.module.asset.convert.HostProviderConvert; import org.dromara.visor.module.asset.dao.HostDAO; +import org.dromara.visor.module.asset.entity.domain.HostDO; import org.dromara.visor.module.asset.entity.dto.host.HostDTO; +import org.dromara.visor.module.asset.entity.dto.host.HostQueryDTO; +import org.dromara.visor.module.asset.entity.request.host.HostQueryRequest; +import org.dromara.visor.module.asset.service.HostService; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -48,6 +53,9 @@ public class HostApiImpl implements HostApi { @Resource private HostDAO hostDAO; + @Resource + private HostService hostService; + @Override public HostDTO selectById(Long id) { return HostProviderConvert.MAPPER.to(hostDAO.selectById(id)); @@ -64,4 +72,40 @@ public class HostApiImpl implements HostApi { .collect(Collectors.toList()); } + @Override + public String selectAgentKeyById(Long id) { + return hostDAO.of() + .createWrapper() + .select(HostDO::getAgentKey) + .eq(HostDO::getId, id) + .then() + .getOne(HostDO::getAgentKey); + } + + @Override + public DataGrid getHostPage(HostQueryDTO query) { + // 转换 + HostQueryRequest queryRequest = HostProviderConvert.MAPPER.to(query); + // 查询 + return hostService.getHostPage(queryRequest).map(HostProviderConvert.MAPPER::to); + } + + @Override + public HostDTO selectByAgentKey(String agentKey) { + return hostDAO.of() + .createWrapper() + .eq(HostDO::getAgentKey, agentKey) + .then() + .getOne(HostProviderConvert.MAPPER::to); + } + + @Override + public List selectByAgentKeys(List agentKeys) { + return hostDAO.of() + .createWrapper() + .in(HostDO::getAgentKey, agentKeys) + .then() + .list(HostProviderConvert.MAPPER::to); + } + } diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/controller/HostAgentController.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/controller/HostAgentController.java new file mode 100644 index 00000000..e409bba3 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/controller/HostAgentController.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.framework.biz.operator.log.core.annotation.OperatorLog; +import org.dromara.visor.framework.log.core.annotation.IgnoreLog; +import org.dromara.visor.framework.log.core.enums.IgnoreLogMode; +import org.dromara.visor.framework.web.core.annotation.DemoDisableApi; +import org.dromara.visor.framework.web.core.annotation.RestWrapper; +import org.dromara.visor.module.asset.define.operator.HostOperatorType; +import org.dromara.visor.module.asset.entity.request.host.HostAgentInstallRequest; +import org.dromara.visor.module.asset.entity.request.host.HostAgentInstallStatusUpdateRequest; +import org.dromara.visor.module.asset.entity.vo.HostAgentLogVO; +import org.dromara.visor.module.asset.entity.vo.HostAgentStatusVO; +import org.dromara.visor.module.asset.service.HostAgentLogService; +import org.dromara.visor.module.asset.service.HostAgentService; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 主机探针端点 api + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/22 14:33 + */ +@Tag(name = "asset - 主机探针") +@Slf4j +@Validated +@RestWrapper +@RestController +@RequestMapping("/asset/host-agent") +public class HostAgentController { + + @Resource + private HostAgentService hostAgentService; + + @Resource + private HostAgentLogService hostAgentLogService; + + @IgnoreLog(IgnoreLogMode.ALL) + @GetMapping("/status") + @Operation(summary = "查询探针状态") + @Parameter(name = "idList", description = "idList", required = true) + @PreAuthorize("@ss.hasPermission('asset:host:query')") + public List getAgentStatus(@RequestParam("idList") List idList) { + return hostAgentService.getAgentStatus(idList); + } + + @IgnoreLog(IgnoreLogMode.ALL) + @GetMapping("/install-status") + @Operation(summary = "查询探针安装状态") + @Parameter(name = "idList", description = "idList", required = true) + @PreAuthorize("@ss.hasPermission('asset:host:query')") + public List getAgentInstallLogStatus(@RequestParam("idList") List idList) { + return hostAgentLogService.getAgentInstallLogStatus(idList); + } + + @DemoDisableApi + @OperatorLog(HostOperatorType.INSTALL_AGENT) + @PostMapping("/install") + @Operation(summary = "安装主机探针") + @PreAuthorize("@ss.hasPermission('asset:host:install-agent')") + public Boolean installAgent(@Validated @RequestBody HostAgentInstallRequest request) { + hostAgentService.installAgent(request); + return true; + } + + @DemoDisableApi + @OperatorLog(HostOperatorType.UPDATE_AGENT_INSTALL_STATUS) + @PutMapping("/update-install-status") + @Operation(summary = "修改探针安装状态") + @PreAuthorize("@ss.hasPermission('asset:host:install-agent')") + public Boolean updateAgentInstallStatus(@Validated @RequestBody HostAgentInstallStatusUpdateRequest request) { + hostAgentLogService.updateStatus(request.getId(), request.getStatus(), request.getMessage()); + return true; + } + + @DemoDisableApi + @OperatorLog(HostOperatorType.UPLOAD_AGENT_RELEASE) + @PostMapping("/upload-agent-release") + @Operation(summary = "上传探针发布包") + @PreAuthorize("@ss.hasPermission('asset:host:install-agent')") + public String uploadAgentRelease(@RequestParam("file") MultipartFile file) { + // 上传 + hostAgentService.uploadAgentRelease(file); + // 获取最新版本 + return hostAgentService.getAgentVersion(); + } + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/controller/HostAgentEndpointController.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/controller/HostAgentEndpointController.java new file mode 100644 index 00000000..14beda8d --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/controller/HostAgentEndpointController.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.controller; + +import com.alibaba.fastjson.JSONObject; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.common.constant.CustomHeaderConst; +import org.dromara.visor.common.constant.ExtraFieldConst; +import org.dromara.visor.framework.log.core.annotation.IgnoreLog; +import org.dromara.visor.framework.log.core.enums.IgnoreLogMode; +import org.dromara.visor.framework.web.core.annotation.ExposeApi; +import org.dromara.visor.framework.web.core.annotation.RestWrapper; +import org.dromara.visor.module.asset.entity.vo.HostOnlineAgentConfigVO; +import org.dromara.visor.module.asset.service.HostAgentEndpointService; +import org.dromara.visor.module.asset.service.HostExtraService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +/** + * 主机探针端点 api + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/22 14:33 + */ +@Tag(name = "asset - 主机探针端点") +@Slf4j +@Validated +@RestWrapper +@RestController +@RequestMapping("/host/agent-endpoint") +public class HostAgentEndpointController { + + @Resource + private HostExtraService hostExtraService; + + @Resource + private HostAgentEndpointService hostAgentEndpointService; + + @ExposeApi + @GetMapping("/set-online") + @Operation(summary = "设置探针已上线") + public HostOnlineAgentConfigVO setAgentOnline(@RequestHeader(CustomHeaderConst.AGENT_KEY_HEADER) String agentKey, + @RequestHeader(CustomHeaderConst.AGENT_VERSION_HEADER) String version) { + return hostAgentEndpointService.setAgentOnline(agentKey, version); + } + + @ExposeApi + @GetMapping("/set-offline") + @Operation(summary = "设置探针已下线") + public Boolean setAgentOffline(@RequestHeader(CustomHeaderConst.AGENT_KEY_HEADER) String agentKey) { + hostAgentEndpointService.setAgentOffline(agentKey); + return true; + } + + @ExposeApi + @IgnoreLog(IgnoreLogMode.RET) + @GetMapping("/heartbeat") + @Operation(summary = "设置探针心跳") + public Boolean setAgentHeartbeat(@RequestHeader(CustomHeaderConst.AGENT_KEY_HEADER) String key) { + hostAgentEndpointService.setAgentHeartbeat(key); + return true; + } + + @ExposeApi + @PostMapping("/sync-host-spec") + @Operation(summary = "同步主机规格") + public Boolean syncHostSpec(@RequestHeader(CustomHeaderConst.AGENT_KEY_HEADER) String key, + @RequestParam(ExtraFieldConst.TASK_ID) String taskId, + @RequestBody JSONObject spec) { + hostExtraService.syncHostSpec(key, taskId, spec); + return true; + } + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/controller/HostController.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/controller/HostController.java index ad09fc43..e8d13d33 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/controller/HostController.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/controller/HostController.java @@ -118,8 +118,9 @@ public class HostController { @Operation(summary = "通过 id 查询主机") @Parameter(name = "id", description = "id", required = true) @PreAuthorize("@ss.hasPermission('asset:host:query')") - public HostVO getHost(@RequestParam("id") Long id) { - return hostService.getHostById(id); + public HostVO getHost(@RequestParam("id") Long id, + @RequestParam(value = "base", required = false) Boolean base) { + return hostService.getHostById(id, base); } @IgnoreLog(IgnoreLogMode.RET) diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostAgentLogConvert.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostAgentLogConvert.java new file mode 100644 index 00000000..ca0f4744 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostAgentLogConvert.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.convert; + +import org.dromara.visor.module.asset.entity.domain.HostAgentLogDO; +import org.dromara.visor.module.asset.entity.vo.HostAgentLogVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 主机探针日志 对象转换器 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023-9-11 14:16 + */ +@Mapper +public interface HostAgentLogConvert { + + HostAgentLogConvert MAPPER = Mappers.getMapper(HostAgentLogConvert.class); + + HostAgentLogVO to(HostAgentLogDO domain); + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostAgentLogProviderConvert.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostAgentLogProviderConvert.java new file mode 100644 index 00000000..e828371c --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostAgentLogProviderConvert.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.convert; + +import org.dromara.visor.module.asset.entity.domain.HostAgentLogDO; +import org.dromara.visor.module.asset.entity.dto.host.HostAgentLogDTO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * 主机探针日志 对外对象转换器 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023-9-11 14:16 + */ +@Mapper +public interface HostAgentLogProviderConvert { + + HostAgentLogProviderConvert MAPPER = Mappers.getMapper(HostAgentLogProviderConvert.class); + + HostAgentLogDTO to(HostAgentLogDO domain); + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostConvert.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostConvert.java index 55fc70e1..1f4ff1ef 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostConvert.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostConvert.java @@ -28,6 +28,7 @@ import org.dromara.visor.module.asset.entity.dto.HostCacheDTO; import org.dromara.visor.module.asset.entity.request.host.HostCreateRequest; import org.dromara.visor.module.asset.entity.request.host.HostQueryRequest; import org.dromara.visor.module.asset.entity.request.host.HostUpdateRequest; +import org.dromara.visor.module.asset.entity.vo.HostAgentStatusVO; import org.dromara.visor.module.asset.entity.vo.HostBaseVO; import org.dromara.visor.module.asset.entity.vo.HostVO; import org.mapstruct.Mapper; @@ -61,6 +62,8 @@ public interface HostConvert { HostBaseVO toBase(HostDO domain); + HostAgentStatusVO toAgentStatus(HostDO domain); + HostCreateRequest toCreate(HostUpdateRequest request); List toList(List domain); diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostProviderConvert.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostProviderConvert.java index 13071c56..00f40637 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostProviderConvert.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/convert/HostProviderConvert.java @@ -26,6 +26,8 @@ import org.dromara.visor.common.mapstruct.StringConversion; import org.dromara.visor.module.asset.entity.domain.HostDO; import org.dromara.visor.module.asset.entity.dto.host.HostBaseDTO; import org.dromara.visor.module.asset.entity.dto.host.HostDTO; +import org.dromara.visor.module.asset.entity.dto.host.HostQueryDTO; +import org.dromara.visor.module.asset.entity.request.host.HostQueryRequest; import org.dromara.visor.module.asset.entity.vo.HostVO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -42,6 +44,8 @@ public interface HostProviderConvert { HostProviderConvert MAPPER = Mappers.getMapper(HostProviderConvert.class); + HostQueryRequest to(HostQueryDTO dto); + HostDO to(HostDTO host); HostDTO to(HostDO domain); diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/dao/HostAgentLogDAO.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/dao/HostAgentLogDAO.java new file mode 100644 index 00000000..4c8d4f84 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/dao/HostAgentLogDAO.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.dao; + +import org.apache.ibatis.annotations.Mapper; +import org.dromara.visor.framework.mybatis.core.mapper.IMapper; +import org.dromara.visor.module.asset.entity.domain.HostAgentLogDO; + +/** + * 主机探针日志 Mapper 接口 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-28 09:55 + */ +@Mapper +public interface HostAgentLogDAO extends IMapper { + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/dao/HostDAO.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/dao/HostDAO.java index 0a2e7916..80842317 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/dao/HostDAO.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/dao/HostDAO.java @@ -24,8 +24,10 @@ package org.dromara.visor.module.asset.dao; import org.apache.ibatis.annotations.Mapper; import org.dromara.visor.framework.mybatis.core.mapper.IMapper; +import org.dromara.visor.framework.mybatis.core.query.Conditions; import org.dromara.visor.module.asset.entity.domain.HostDO; +import java.util.Date; import java.util.List; /** @@ -57,4 +59,47 @@ public interface HostDAO extends IMapper { .list(HostDO::getId); } + /** + * 通过 agentKey 查询 id + * + * @param agentKey agentKey + * @return id + */ + default Long selectIdByAgentKey(String agentKey) { + return this.of() + .createWrapper() + .select(HostDO::getId) + .eq(HostDO::getAgentKey, agentKey) + .then() + .getOne(HostDO::getId); + } + + /** + * 通过 agentKey 查询 id + * + * @param agentKeys agentKeys + * @return id + */ + default List selectIdByAgentKeys(List agentKeys) { + return this.of() + .createWrapper() + .select(HostDO::getId, HostDO::getAgentKey) + .in(HostDO::getAgentKey, agentKeys) + .then() + .list(); + } + + /** + * 更新探针信息 + * + * @param keys agentKeyList + * @param update update + * @return effect + */ + default int updateByAgentKeys(List keys, HostDO update) { + update.setUpdateTime(new Date()); + // 更新 + return this.update(update, Conditions.in(HostDO::getAgentKey, keys)); + } + } diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/dao/HostIdentityDAO.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/dao/HostIdentityDAO.java index 7c36b924..83088e1d 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/dao/HostIdentityDAO.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/dao/HostIdentityDAO.java @@ -48,6 +48,7 @@ public interface HostIdentityDAO extends IMapper { */ default int setKeyWithNull(List keyIdList) { LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate() + .setSql("type = IF(type = 'KEY', 'PASSWORD', type)") .set(HostIdentityDO::getKeyId, null) .in(HostIdentityDO::getKeyId, keyIdList); return this.update(null, updateWrapper); diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/define/AssetThreadPools.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/define/AssetThreadPools.java new file mode 100644 index 00000000..b38fe855 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/define/AssetThreadPools.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.define; + +import cn.orionsec.kit.lang.define.thread.ExecutorBuilder; +import cn.orionsec.kit.lang.utils.Systems; +import org.dromara.visor.common.constant.Const; + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; + +/** + * 执行线程池 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2024/1/3 11:21 + */ +public interface AssetThreadPools { + + /** + * 批量执行主机命令线程池 + */ + ThreadPoolExecutor AGENT_INSTALL = ExecutorBuilder.create() + .namedThreadFactory("agent-install-") + .corePoolSize(Systems.PROCESS_NUM) + .maxPoolSize(Systems.PROCESS_NUM) + .keepAliveTime(Const.MS_S_60) + .workQueue(new LinkedBlockingQueue<>()) + .allowCoreThreadTimeout(true) + .build(); + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/define/cache/HostCacheKeyDefine.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/define/cache/HostCacheKeyDefine.java index 9d412b53..b7f4b10f 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/define/cache/HostCacheKeyDefine.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/define/cache/HostCacheKeyDefine.java @@ -64,4 +64,12 @@ public interface HostCacheKeyDefine { .timeout(8, TimeUnit.HOURS) .build(); + CacheKeyDefine HOST_INSTALL_LOG = new CacheKeyBuilder() + .key("host:inst-log:{}") + .desc("最新的主机安装记录 ${hostId}") + .noPrefix() + .type(Long.class) + .struct(RedisCacheStruct.STRING) + .build(); + } diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/define/operator/HostOperatorType.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/define/operator/HostOperatorType.java index f0e614ad..2b579eb7 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/define/operator/HostOperatorType.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/define/operator/HostOperatorType.java @@ -50,6 +50,12 @@ public class HostOperatorType extends InitializingOperatorTypes { public static final String UPDATE_SPEC = "host:update-spec"; + public static final String INSTALL_AGENT = "host:install-agent"; + + public static final String UPDATE_AGENT_INSTALL_STATUS = "host:update-install-status"; + + public static final String UPLOAD_AGENT_RELEASE = "host:upload-agent-release"; + @Override public OperatorType[] types() { return new OperatorType[]{ @@ -59,6 +65,9 @@ public class HostOperatorType extends InitializingOperatorTypes { new OperatorType(M, UPDATE_STATUS, "修改主机状态 ${name} - ${status}"), new OperatorType(M, UPDATE_CONFIG, "修改主机配置 ${name} - ${type}"), new OperatorType(M, UPDATE_SPEC, "修改主机规格信息 ${name}"), + new OperatorType(L, INSTALL_AGENT, "安装主机探针"), + new OperatorType(L, UPDATE_AGENT_INSTALL_STATUS, "修改探针安装状态为 ${status}"), + new OperatorType(H, UPLOAD_AGENT_RELEASE, "上传探针发布包 ${name} ${signShort}"), }; } diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/domain/HostAgentLogDO.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/domain/HostAgentLogDO.java new file mode 100644 index 00000000..7788ff23 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/domain/HostAgentLogDO.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.entity.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.dromara.visor.framework.mybatis.core.domain.BaseDO; + +/** + * 主机探针日志 实体对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-28 09:55 + */ +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@TableName(value = "host_agent_log", autoResultMap = true) +@Schema(name = "HostAgentLogDO", description = "主机探针日志 实体对象") +public class HostAgentLogDO extends BaseDO { + + private static final long serialVersionUID = 1L; + + @Schema(description = "主机id") + @TableField("host_id") + private Long hostId; + + @Schema(description = "agentKey") + @TableField("agent_key") + private String agentKey; + + @Schema(description = "类型") + @TableField("type") + private String type; + + @Schema(description = "状态") + @TableField("status") + private String status; + + @Schema(description = "消息") + @TableField("message") + private String message; + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/domain/HostDO.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/domain/HostDO.java index c12a40c1..79119828 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/domain/HostDO.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/domain/HostDO.java @@ -32,6 +32,8 @@ import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import org.dromara.visor.framework.mybatis.core.domain.BaseDO; +import java.util.Date; + /** * 主机 实体对象 * @@ -78,6 +80,26 @@ public class HostDO extends BaseDO { @TableField("status") private String status; + @Schema(description = "agentKey") + @TableField("agent_key") + private String agentKey; + + @Schema(description = "探针版本") + @TableField("agent_version") + private String agentVersion; + + @Schema(description = "探针安装状态") + @TableField("agent_install_status") + private Integer agentInstallStatus; + + @Schema(description = "探针在线状态") + @TableField("agent_online_status") + private Integer agentOnlineStatus; + + @Schema(description = "探针切换在线状态时间") + @TableField("agent_online_change_time") + private Date agentOnlineChangeTime; + @Schema(description = "主机描述") @TableField("description") private String description; diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/dto/HostCacheDTO.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/dto/HostCacheDTO.java index f82eda5c..2aafbe45 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/dto/HostCacheDTO.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/dto/HostCacheDTO.java @@ -66,12 +66,12 @@ public class HostCacheDTO implements LongCacheIdModel, Serializable { @Schema(description = "主机地址") private String address; - @Schema(description = "主机端口") - private Integer port; - @Schema(description = "主机状态") private String status; + @Schema(description = "agentKey") + private String agentKey; + @Schema(description = "主机描述") private String description; diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/request/host/HostAgentInstallRequest.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/request/host/HostAgentInstallRequest.java new file mode 100644 index 00000000..a6981f41 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/request/host/HostAgentInstallRequest.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.entity.request.host; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotEmpty; +import java.util.List; + +/** + * 主机 安装探针请求对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023-9-11 14:16 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "HostAgentInstallRequest", description = "主机 安装探针请求对象") +public class HostAgentInstallRequest { + + @NotEmpty + @Schema(description = "id") + private List idList; + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/request/host/HostAgentInstallStatusUpdateRequest.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/request/host/HostAgentInstallStatusUpdateRequest.java new file mode 100644 index 00000000..5bf821c9 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/request/host/HostAgentInstallStatusUpdateRequest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.entity.request.host; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * 主机安装探针更新状态请求 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023-9-11 14:16 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "HostAgentInstallStatusUpdateRequest", description = "主机安装探针更新状态请求") +public class HostAgentInstallStatusUpdateRequest { + + @NotNull + @Schema(description = "id") + private Long id; + + @NotNull + @Schema(description = "状态") + private String status; + + @Size(max = 1000) + @Schema(description = "消息") + private String message; + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/request/host/HostQueryRequest.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/request/host/HostQueryRequest.java index 0099ceaf..6bf632a6 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/request/host/HostQueryRequest.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/request/host/HostQueryRequest.java @@ -23,7 +23,8 @@ package org.dromara.visor.module.asset.entity.request.host; import io.swagger.v3.oas.annotations.media.Schema; -import lombok.*; +import lombok.Data; +import lombok.EqualsAndHashCode; import org.dromara.visor.common.entity.BaseQueryRequest; import javax.validation.constraints.Size; @@ -37,9 +38,6 @@ import java.util.List; * @since 2023-9-11 14:16 */ @Data -@Builder -@NoArgsConstructor -@AllArgsConstructor @EqualsAndHashCode(callSuper = true) @Schema(name = "HostQueryRequest", description = "主机 查询请求对象") public class HostQueryRequest extends BaseQueryRequest { @@ -50,6 +48,9 @@ public class HostQueryRequest extends BaseQueryRequest { @Schema(description = "id") private Long id; + @Schema(description = "id") + private List idList; + @Size(max = 8) @Schema(description = "主机类型") private String type; @@ -78,13 +79,25 @@ public class HostQueryRequest extends BaseQueryRequest { @Schema(description = "主机状态") private String status; - @Schema(description = "tag") - private List tags; - @Size(max = 255) @Schema(description = "描述") private String description; + @Schema(description = "agentKey") + private String agentKey; + + @Schema(description = "探针安装状态") + private Integer agentInstallStatus; + + @Schema(description = "探针在线状态") + private Integer agentOnlineStatus; + + @Schema(description = "通过探针排序") + private Boolean orderByAgent; + + @Schema(description = "tag") + private List tags; + @Schema(description = "是否查询分组信息") private Boolean queryGroup; diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/vo/HostAgentLogVO.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/vo/HostAgentLogVO.java new file mode 100644 index 00000000..32b90bae --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/vo/HostAgentLogVO.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Date; + +/** + * 主机探针日志 视图响应对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-28 09:55 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "HostAgentLogVO", description = "主机探针日志 视图响应对象") +public class HostAgentLogVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "主机id") + private Long hostId; + + @Schema(description = "agentKey") + private String agentKey; + + @Schema(description = "类型") + private String type; + + @Schema(description = "状态") + private String status; + + @Schema(description = "消息") + private String message; + + @Schema(description = "创建时间") + private Date createTime; + + @Schema(description = "修改时间") + private Date updateTime; + + @Schema(description = "创建人") + private String creator; + + @Schema(description = "修改人") + private String updater; + + @Schema(description = "探针状态") + private HostAgentStatusVO agentStatus; + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/vo/HostAgentStatusVO.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/vo/HostAgentStatusVO.java new file mode 100644 index 00000000..d0d0ceee --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/vo/HostAgentStatusVO.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 主机探针状态 视图响应对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-28 09:55 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "HostAgentStatusVO", description = "主机探针状态 视图响应对象") +public class HostAgentStatusVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "探针版本") + private String agentVersion; + + @Schema(description = "最新版本") + private String latestVersion; + + @Schema(description = "探针安装状态") + private Integer agentInstallStatus; + + @Schema(description = "探针在线状态") + private Integer agentOnlineStatus; + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/vo/HostOnlineAgentConfigVO.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/vo/HostOnlineAgentConfigVO.java new file mode 100644 index 00000000..84d5852d --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/entity/vo/HostOnlineAgentConfigVO.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 主机密钥 视图响应对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2023-9-20 11:55 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "HostOnlineAgentConfigVO", description = "主机上线探针配置 响应对象") +public class HostOnlineAgentConfigVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "是否已同步过规格") + private Boolean specSynced; + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/enums/AgentLogStatusEnum.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/enums/AgentLogStatusEnum.java new file mode 100644 index 00000000..629ba2d9 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/enums/AgentLogStatusEnum.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.enums; + +/** + * 探针日志状态 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/28 10:50 + */ +public enum AgentLogStatusEnum { + + /** + * 等待中 + */ + WAIT, + + /** + * 安装中 + */ + RUNNING, + + /** + * 成功 + */ + SUCCESS, + + /** + * 失败 + */ + FAILED, + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/enums/AgentLogTypeEnum.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/enums/AgentLogTypeEnum.java new file mode 100644 index 00000000..4a695033 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/enums/AgentLogTypeEnum.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.enums; + +/** + * 探针日志类型 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/28 10:50 + */ +public enum AgentLogTypeEnum { + + /** + * 下线 + */ + OFFLINE, + + /** + * 上线 + */ + ONLINE, + + /** + * 安装 + */ + INSTALL, + + /** + * 启动 + */ + START, + + /** + * 停止 + */ + STOP, + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/intstall/AbstractAgentInstaller.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/intstall/AbstractAgentInstaller.java new file mode 100644 index 00000000..6d1684c8 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/intstall/AbstractAgentInstaller.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.handler.agent.intstall; + +import cn.orionsec.kit.lang.utils.Strings; +import cn.orionsec.kit.lang.utils.Valid; +import cn.orionsec.kit.lang.utils.io.FileReaders; +import cn.orionsec.kit.lang.utils.io.Streams; +import cn.orionsec.kit.net.host.SessionStore; +import cn.orionsec.kit.net.host.sftp.SftpExecutor; +import cn.orionsec.kit.net.host.ssh.command.CommandExecutor; +import cn.orionsec.kit.spring.SpringHolder; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.common.constant.Const; +import org.dromara.visor.common.constant.ErrorMessage; +import org.dromara.visor.common.constant.FileConst; +import org.dromara.visor.common.session.config.SshConnectConfig; +import org.dromara.visor.common.session.ssh.SessionStores; +import org.dromara.visor.common.utils.PathUtils; +import org.dromara.visor.module.asset.entity.domain.HostAgentLogDO; +import org.dromara.visor.module.asset.enums.AgentLogStatusEnum; +import org.dromara.visor.module.asset.enums.HostOsTypeEnum; +import org.dromara.visor.module.asset.handler.agent.model.AgentInstallParams; +import org.dromara.visor.module.asset.service.HostAgentLogService; +import org.dromara.visor.module.asset.service.HostConnectService; + +import java.io.IOException; + +/** + * 探针安装器 基类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/29 11:12 + */ +@Slf4j +public abstract class AbstractAgentInstaller implements AgentInstaller { + + private static final String REPLACEMENT = "$$"; + + private static final HostAgentLogService hostAgentLogService = SpringHolder.getBean(HostAgentLogService.class); + + private static final HostConnectService hostConnectService = SpringHolder.getBean(HostConnectService.class); + + protected final Long logId; + + protected final AgentInstallParams params; + + protected final String startScriptName; + + protected final String uploadAgentName; + + protected String agentHomePath; + + protected HostAgentLogDO record; + + protected SshConnectConfig sshConfig; + + protected SessionStore sessionStore; + + protected CommandExecutor commandExecutor; + + protected SftpExecutor sftpExecutor; + + public AbstractAgentInstaller(AgentInstallParams params) { + this.params = params; + this.logId = params.getLogId(); + this.startScriptName = Const.START + HostOsTypeEnum.of(params.getOsType()).getScriptSuffix(); + this.uploadAgentName = FileConst.AGENT + HostOsTypeEnum.of(params.getOsType()).getBinarySuffix(); + } + + @Override + public void run() { + log.info("AgentInstaller install start {}", logId); + // 查询记录 + this.record = hostAgentLogService.selectById(logId); + Valid.notNull(record, "AgentInstaller record is null {}", logId); + Valid.eq(record.getStatus(), AgentLogStatusEnum.WAIT.name(), "AgentInstaller record status is not WAIT {}", logId); + try { + // 更新状态 + this.updateStatus(AgentLogStatusEnum.RUNNING, null); + // 打开会话 + this.initSession(); + log.info("AgentInstaller install session init {}", logId); + // 上传文件 + this.uploadFile(); + log.info("AgentInstaller install upload finish {}", logId); + // 启动探针 + this.startAgent(); + log.info("AgentInstaller install stated {}", logId); + // 更新状态 + this.updateStatus(AgentLogStatusEnum.SUCCESS, null); + } catch (Exception e) { + // 更新状态 + log.error("AgentInstaller install error {}", logId, e); + this.updateStatus(AgentLogStatusEnum.FAILED, ErrorMessage.getErrorMessage(e, 1000)); + } finally { + this.close(); + } + } + + /** + * 初始化会话 + */ + private void initSession() { + // 获取 ssh 配置 + this.sshConfig = hostConnectService.getSshConnectConfig(params.getHostId()); + // 设置探针家目录 + this.agentHomePath = this.getAgentHomePath(); + // 打开会话 + this.sessionStore = SessionStores.openSessionStore(sshConfig); + // 打开 sftp + this.sftpExecutor = sessionStore.getSftpExecutor(sshConfig.getFileNameCharset()); + sftpExecutor.connect(); + } + + /** + * 上传文件 + * + * @throws IOException IOException + */ + protected abstract void uploadFile() throws IOException; + + /** + * 启动 agent + */ + protected abstract void startAgent() throws IOException; + + /** + * 获取探针家目录 + * + * @return path + */ + protected String getAgentHomePath() { + return PathUtils.buildAppPath(HostOsTypeEnum.WINDOWS.name().equals(params.getOsType()), + sshConfig.getUsername(), + FileConst.AGENT) + Const.SLASH; + } + + /** + * 替换文件内容 + * + * @param path path + * @return content + */ + protected String replaceContent(String path) { + // 读取文件 + byte[] contentBytes = FileReaders.readAllBytesFast(path); + // 格式化文件 + return Strings.format(new String(contentBytes), REPLACEMENT, params.getReplaceVars()); + } + + /** + * 更新状态 + * + * @param status 状态 + * @param message 消息 + */ + protected void updateStatus(AgentLogStatusEnum status, String message) { + log.info("AgentInstaller update status {}, {}", logId, status); + hostAgentLogService.updateStatus(logId, status.name(), message); + } + + @Override + public void close() { + Streams.close(sftpExecutor); + Streams.close(commandExecutor); + Streams.close(sessionStore); + } + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/intstall/AgentInstaller.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/intstall/AgentInstaller.java new file mode 100644 index 00000000..0011da0e --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/intstall/AgentInstaller.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.handler.agent.intstall; + +import cn.orionsec.kit.lang.able.SafeCloseable; +import org.dromara.visor.module.asset.define.AssetThreadPools; +import org.dromara.visor.module.asset.enums.HostOsTypeEnum; +import org.dromara.visor.module.asset.handler.agent.model.AgentInstallParams; + +/** + * 探针安装器 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/29 10:28 + */ +public interface AgentInstaller extends Runnable, SafeCloseable { + + /** + * 启动安装 + * + * @param params params + */ + static void start(AgentInstallParams params) { + AgentInstaller installer; + if (HostOsTypeEnum.WINDOWS.name().equals(params.getOsType())) { + // windows 安装 + installer = new WindowsAgentInstaller(params); + } else { + // 其他安装 + installer = new LinuxAgentInstaller(params); + } + AssetThreadPools.AGENT_INSTALL.execute(installer); + } + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/intstall/LinuxAgentInstaller.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/intstall/LinuxAgentInstaller.java new file mode 100644 index 00000000..856a29bf --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/intstall/LinuxAgentInstaller.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.handler.agent.intstall; + +import cn.orionsec.kit.lang.utils.Exceptions; +import cn.orionsec.kit.net.host.ssh.command.CommandExecutors; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.common.constant.FileConst; +import org.dromara.visor.module.asset.handler.agent.model.AgentInstallParams; + +import java.io.IOException; + +/** + * linux 探针安装器 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/29 11:12 + */ +@Slf4j +public class LinuxAgentInstaller extends AbstractAgentInstaller { + + public LinuxAgentInstaller(AgentInstallParams params) { + super(params); + } + + @Override + protected void uploadFile() throws IOException { + // 写入配置文件 + sftpExecutor.write(agentHomePath + FileConst.CONFIG_YAML, this.replaceContent(params.getConfigFilePath())); + log.info("写入配置文件成功"); + // 写入启动脚本 + sftpExecutor.write(agentHomePath + startScriptName, this.replaceContent(params.getStartScriptPath())); + log.info("写入启动脚本成功"); + // 上传探针文件 + sftpExecutor.uploadFile(agentHomePath + uploadAgentName, params.getAgentFilePath()); + log.info("上传探针文件成功"); + // 脚本提权 + sftpExecutor.changeMode(agentHomePath + startScriptName, 777); + log.info("脚本提权成功"); + // 探针提权 + sftpExecutor.changeMode(agentHomePath + uploadAgentName, 777); + log.info("探针提权成功"); + } + + @Override + protected void startAgent() throws IOException { + String command = "cd " + agentHomePath + " && sh " + startScriptName; + log.info("LinuxAgentInstaller command: {}", command); + this.commandExecutor = sessionStore.getCommandExecutor(command); + this.commandExecutor.pty(false); + byte[] result = CommandExecutors.getCommandOutputResult(this.commandExecutor); + // 如果不是成功启动则抛异常 + if (!commandExecutor.isSuccessExit()) { + throw Exceptions.app("exit: " + commandExecutor.getExitCode() + ". " + new String(result)); + } + } + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/intstall/WindowsAgentInstaller.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/intstall/WindowsAgentInstaller.java new file mode 100644 index 00000000..a9fab0db --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/intstall/WindowsAgentInstaller.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.handler.agent.intstall; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.common.constant.Const; +import org.dromara.visor.common.constant.FileConst; +import org.dromara.visor.module.asset.handler.agent.model.AgentInstallParams; + +import java.io.IOException; + +/** + * windows 探针安装器 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/29 11:12 + */ +@Slf4j +public class WindowsAgentInstaller extends AbstractAgentInstaller { + + public WindowsAgentInstaller(AgentInstallParams params) { + super(params); + } + + @Override + protected void uploadFile() throws IOException { + // 写入配置文件 + sftpExecutor.write(Const.SLASH + agentHomePath + FileConst.CONFIG_YAML, this.replaceContent(params.getConfigFilePath())); + log.info("写入配置文件成功"); + // 写入启动脚本 + sftpExecutor.write(Const.SLASH + agentHomePath + startScriptName, this.replaceContent(params.getStartScriptPath())); + log.info("写入启动脚本成功"); + // 上传探针文件 + sftpExecutor.uploadFile(Const.SLASH + agentHomePath + uploadAgentName, params.getAgentFilePath()); + log.info("上传探针文件成功"); + } + + @Override + protected void startAgent() { + // TODO + } + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/model/AgentInstallParams.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/model/AgentInstallParams.java new file mode 100644 index 00000000..ff06fd29 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/agent/model/AgentInstallParams.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.handler.agent.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +/** + * 探针安装参数 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/28 18:01 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AgentInstallParams { + + /** + * logId + */ + private Long logId; + + /** + * hostId + */ + private Long hostId; + + /** + * 系统类型 + */ + private String osType; + + /** + * agentKey + */ + private String agentKey; + + /** + * 配置文件路径 + */ + private String configFilePath; + + /** + * 探针文件路径 + */ + private String agentFilePath; + + /** + * 启动脚本路径 + */ + private String startScriptPath; + + /** + * 替换变量 + */ + private Map replaceVars; + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/host/extra/model/HostSpecExtraModel.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/host/extra/model/HostSpecExtraModel.java index 5c85129d..42982e9a 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/host/extra/model/HostSpecExtraModel.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/host/extra/model/HostSpecExtraModel.java @@ -41,6 +41,11 @@ import java.util.List; @AllArgsConstructor public class HostSpecExtraModel implements GenericsDataModel { + /** + * 是否已同步 + */ + private Boolean synced; + /** * sn */ @@ -109,7 +114,7 @@ public class HostSpecExtraModel implements GenericsDataModel { /** * 负责人 */ - private String chargePerson; + private String ownerPerson; /** * 创建时间 diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/host/extra/strategy/HostSpecExtraStrategy.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/host/extra/strategy/HostSpecExtraStrategy.java index 5d4019c4..1b790973 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/host/extra/strategy/HostSpecExtraStrategy.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/handler/host/extra/strategy/HostSpecExtraStrategy.java @@ -45,4 +45,9 @@ public class HostSpecExtraStrategy extends AbstractGenericsDataStrategy getAgentInstallLogStatus(List idList); + + /** + * 更新日志状态 + * + * @param id id + * @param status status + * @param message message + */ + void updateStatus(Long id, String status, String message); + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/HostAgentService.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/HostAgentService.java new file mode 100644 index 00000000..72a7d9d4 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/HostAgentService.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.service; + +import org.dromara.visor.module.asset.entity.request.host.HostAgentInstallRequest; +import org.dromara.visor.module.asset.entity.vo.HostAgentStatusVO; +import org.springframework.web.multipart.MultipartFile; + +import java.util.List; + +/** + * 主机探针 服务类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/27 16:06 + */ +public interface HostAgentService { + + /** + * 获取探针状态 + * + * @param idList idList + * @return rows + */ + List getAgentStatus(List idList); + + /** + * 安装探针 + * + * @param request request + */ + void installAgent(HostAgentInstallRequest request); + + /** + * 上传探针发布包 + * + * @param file file + */ + void uploadAgentRelease(MultipartFile file); + + /** + * 获取探针版本 + * + * @return version + */ + String getAgentVersion(); + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/HostExtraService.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/HostExtraService.java index 6d9a2ae5..5a167bf3 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/HostExtraService.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/HostExtraService.java @@ -22,6 +22,7 @@ */ package org.dromara.visor.module.asset.service; +import com.alibaba.fastjson.JSONObject; import org.dromara.visor.common.handler.data.model.GenericsDataModel; import org.dromara.visor.module.asset.entity.request.host.HostExtraUpdateRequest; import org.dromara.visor.module.asset.handler.host.extra.HostExtraItemEnum; @@ -83,4 +84,13 @@ public interface HostExtraService { */ void copyHostExtra(Long originId, Long newId); + /** + * 同步主机规格 + * + * @param key key + * @param taskId taskId + * @param spec spec + */ + void syncHostSpec(String key, String taskId, JSONObject spec); + } diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/HostService.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/HostService.java index f9f33e10..13767252 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/HostService.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/HostService.java @@ -83,10 +83,11 @@ public interface HostService { /** * 通过 id 查询主机 * - * @param id id + * @param id id + * @param base base * @return row */ - HostVO getHostById(Long id); + HostVO getHostById(Long id, Boolean base); /** * 查询主机 diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostAgentEndpointServiceImpl.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostAgentEndpointServiceImpl.java new file mode 100644 index 00000000..a3cb9f1f --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostAgentEndpointServiceImpl.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.service.impl; + +import cn.orionsec.kit.lang.utils.Booleans; +import cn.orionsec.kit.lang.utils.Valid; +import cn.orionsec.kit.lang.utils.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.common.constant.Const; +import org.dromara.visor.common.constant.ErrorMessage; +import org.dromara.visor.module.asset.dao.HostAgentLogDAO; +import org.dromara.visor.module.asset.dao.HostDAO; +import org.dromara.visor.module.asset.entity.domain.HostAgentLogDO; +import org.dromara.visor.module.asset.entity.domain.HostDO; +import org.dromara.visor.module.asset.entity.vo.HostOnlineAgentConfigVO; +import org.dromara.visor.module.asset.enums.AgentInstallStatusEnum; +import org.dromara.visor.module.asset.enums.AgentLogStatusEnum; +import org.dromara.visor.module.asset.enums.AgentLogTypeEnum; +import org.dromara.visor.module.asset.enums.AgentOnlineStatusEnum; +import org.dromara.visor.module.asset.handler.host.extra.HostExtraItemEnum; +import org.dromara.visor.module.asset.handler.host.extra.model.HostSpecExtraModel; +import org.dromara.visor.module.asset.service.HostAgentEndpointService; +import org.dromara.visor.module.asset.service.HostExtraService; +import org.dromara.visor.module.monitor.api.MonitorHostApi; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * 监控探针端点 服务实现类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/27 16:07 + */ +@Slf4j +@Service +public class HostAgentEndpointServiceImpl implements HostAgentEndpointService { + + /** + * 标记离线阈值 + * 上报间隔(60s) * 2 + 5s + */ + private static final int MARK_OFFLINE_THRESHOLD = (60 * 2 + 5) * 1000; + + private static final ConcurrentHashMap ONLINE_STATUS_CACHE = new ConcurrentHashMap<>(); + + private static final ConcurrentHashMap HEARTBEAT_RECV_CACHE = new ConcurrentHashMap<>(); + + @Resource + private HostDAO hostDAO; + + @Resource + private HostAgentLogDAO hostAgentLogDAO; + + @Resource + private HostExtraService hostExtraService; + + @Resource + private MonitorHostApi monitorHostApi; + + /** + * 初始化主机在线状态 + */ + @PostConstruct + public void initHostOnlineStatus() { + List hosts = hostDAO.selectList(null); + for (HostDO host : hosts) { + Integer agentOnlineStatus = host.getAgentOnlineStatus(); + if (agentOnlineStatus != null) { + ONLINE_STATUS_CACHE.put(host.getAgentKey(), agentOnlineStatus); + } + } + } + + @Override + public HostOnlineAgentConfigVO setAgentOnline(String agentKey, String version) { + log.info("HostAgentEndpointService setAgentOnline agentKey: {}. version: {}", agentKey, version); + try { + // 查询主机信息 + Long hostId = hostDAO.selectIdByAgentKey(agentKey); + Valid.notNull(hostId, ErrorMessage.HOST_ABSENT); + // 查询主机规格信息 + HostSpecExtraModel spec = hostExtraService.getHostExtra(Const.SYSTEM_USER_ID, hostId, HostExtraItemEnum.SPEC); + Boolean synced = Optional.ofNullable(spec) + .map(HostSpecExtraModel::getSynced) + .map(Booleans::isTrue) + .orElse(false); + // 提前修正缓存 + ONLINE_STATUS_CACHE.put(agentKey, AgentOnlineStatusEnum.ONLINE.getValue()); + // 设置心跳 + this.setAgentHeartbeat(agentKey); + // 修改状态 + HostDO update = HostDO.builder() + .agentVersion(version) + .agentOnlineStatus(AgentOnlineStatusEnum.ONLINE.getValue()) + .agentOnlineChangeTime(new Date()) + .agentInstallStatus(AgentInstallStatusEnum.INSTALLED.getStatus()) + .build(); + hostDAO.updateByAgentKeys(Lists.singleton(agentKey), update); + // 插入日志 + HostAgentLogDO agentLog = HostAgentLogDO.builder() + .hostId(hostId) + .agentKey(agentKey) + .type(AgentLogTypeEnum.ONLINE.name()) + .status(AgentLogStatusEnum.SUCCESS.name()) + .build(); + hostAgentLogDAO.insert(agentLog); + // 返回 + return HostOnlineAgentConfigVO.builder() + .specSynced(synced) + .build(); + } catch (Exception e) { + // 由心跳修正 + ONLINE_STATUS_CACHE.put(agentKey, AgentOnlineStatusEnum.OFFLINE.getValue()); + throw e; + } + } + + @Override + public void setAgentOffline(String agentKey) { + log.info("HostAgentEndpointService setAgentOffline agentKey: {}", agentKey); + // 查询主机信息 + Long hostId = hostDAO.selectIdByAgentKey(agentKey); + Valid.notNull(hostId, ErrorMessage.HOST_ABSENT); + // 修改缓存 + ONLINE_STATUS_CACHE.put(agentKey, AgentOnlineStatusEnum.OFFLINE.getValue()); + HEARTBEAT_RECV_CACHE.put(agentKey, 0L); + // 修改状态 + HostDO update = HostDO.builder() + .agentOnlineStatus(AgentOnlineStatusEnum.OFFLINE.getValue()) + .agentOnlineChangeTime(new Date()) + .build(); + hostDAO.updateByAgentKeys(Lists.singleton(agentKey), update); + // 插入日志 + HostAgentLogDO agentLog = HostAgentLogDO.builder() + .hostId(hostId) + .agentKey(agentKey) + .type(AgentLogTypeEnum.OFFLINE.name()) + .status(AgentLogStatusEnum.SUCCESS.name()) + .build(); + hostAgentLogDAO.insert(agentLog); + // 设置监控上下文为已下线 + monitorHostApi.setAgentOffline(Lists.singleton(agentKey)); + } + + @Override + public void setAgentHeartbeat(String agentKey) { + // 设置心跳时间 + HEARTBEAT_RECV_CACHE.put(agentKey, System.currentTimeMillis()); + } + + @Override + public void checkHeartbeat() { + long now = System.currentTimeMillis(); + List markOnlineList = new ArrayList<>(); + List markOfflineList = new ArrayList<>(); + // 状态检查 + ONLINE_STATUS_CACHE.forEach((key, status) -> { + // 上次心跳时间 + Long lastHeartbeatTime = HEARTBEAT_RECV_CACHE.getOrDefault(key, 0L); + // 超过阈值标记离线 + if (now - lastHeartbeatTime > MARK_OFFLINE_THRESHOLD) { + // 如果当前状态是在线则标记离线 + if (AgentOnlineStatusEnum.ONLINE.getValue().equals(status)) { + markOfflineList.add(key); + } + } else { + // 如果当前状态是离线则标记在线 + if (AgentOnlineStatusEnum.OFFLINE.getValue().equals(status)) { + markOnlineList.add(key); + } + } + }); + // 更新在线状态 + if (!markOnlineList.isEmpty()) { + this.markOnlineStatus(markOnlineList, AgentOnlineStatusEnum.ONLINE); + } + // 更新离线状态 + if (!markOfflineList.isEmpty()) { + this.markOnlineStatus(markOfflineList, AgentOnlineStatusEnum.OFFLINE); + } + } + + /** + * 标记在线状态 + * + * @param agentKeyList agentKeyList + * @param status status + */ + private void markOnlineStatus(List agentKeyList, AgentOnlineStatusEnum status) { + if (Lists.isEmpty(agentKeyList)) { + return; + } + log.info("HostAgentEndpointService mark {}. count: {}, keys: {}", status, agentKeyList.size(), agentKeyList); + // 更新数据 + HostDO update = HostDO.builder() + .agentOnlineStatus(status.getValue()) + .agentOnlineChangeTime(new Date()) + .build(); + int effect = hostDAO.updateByAgentKeys(agentKeyList, update); + // 更新缓存 + agentKeyList.forEach(s -> ONLINE_STATUS_CACHE.put(s, status.getValue())); + log.info("HostAgentEndpointService mark {}. effect: {}", status, effect); + // 插入日志 + List logList = hostDAO.selectIdByAgentKeys(agentKeyList) + .stream() + .map(s -> { + HostAgentLogDO agentLog = HostAgentLogDO.builder() + .hostId(s.getId()) + .agentKey(s.getAgentKey()) + .status(AgentLogStatusEnum.SUCCESS.name()) + .build(); + if (AgentOnlineStatusEnum.ONLINE.equals(status)) { + agentLog.setType(AgentLogTypeEnum.ONLINE.name()); + } else { + agentLog.setType(AgentLogTypeEnum.OFFLINE.name()); + } + return agentLog; + }).collect(Collectors.toList()); + if (!logList.isEmpty()) { + hostAgentLogDAO.insertBatch(logList); + } + // 设置监控上下文为已下线 + if (AgentOnlineStatusEnum.OFFLINE.equals(status)) { + monitorHostApi.setAgentOffline(agentKeyList); + } + } + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostAgentLogServiceImpl.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostAgentLogServiceImpl.java new file mode 100644 index 00000000..e75ece0a --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostAgentLogServiceImpl.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.service.impl; + +import cn.orionsec.kit.lang.function.Functions; +import cn.orionsec.kit.lang.utils.collect.Lists; +import org.dromara.visor.module.asset.convert.HostAgentLogConvert; +import org.dromara.visor.module.asset.dao.HostAgentLogDAO; +import org.dromara.visor.module.asset.entity.domain.HostAgentLogDO; +import org.dromara.visor.module.asset.entity.vo.HostAgentLogVO; +import org.dromara.visor.module.asset.entity.vo.HostAgentStatusVO; +import org.dromara.visor.module.asset.enums.AgentLogStatusEnum; +import org.dromara.visor.module.asset.service.HostAgentLogService; +import org.dromara.visor.module.asset.service.HostAgentService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 主机探针日志 服务实现类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/9/2 16:31 + */ +@Service +public class HostAgentLogServiceImpl implements HostAgentLogService { + + @Resource + private HostAgentLogDAO hostAgentLogDAO; + + @Resource + private HostAgentService hostAgentService; + + @Override + public HostAgentLogDO selectById(Long id) { + return hostAgentLogDAO.selectById(id); + } + + @Override + public List getAgentInstallLogStatus(List idList) { + if (Lists.isEmpty(idList)) { + return Lists.empty(); + } + // 查询日志 + List records = hostAgentLogDAO.selectBatchIds(idList) + .stream() + .map(HostAgentLogConvert.MAPPER::to) + .collect(Collectors.toList()); + // 如果是已完成需要查询 + List successRecords = records.stream() + .filter(s -> AgentLogStatusEnum.SUCCESS.name().equals(s.getStatus())) + .collect(Collectors.toList()); + if (!successRecords.isEmpty()) { + // 完成后查询主机信息 + List hostIdList = successRecords.stream() + .map(HostAgentLogVO::getHostId) + .distinct() + .collect(Collectors.toList()); + // 查询状态信息 + Map agentStatusMap = hostAgentService.getAgentStatus(hostIdList) + .stream() + .collect(Collectors.toMap(HostAgentStatusVO::getId, + Function.identity(), + Functions.right())); + // 设置状态信息 + for (HostAgentLogVO successRecord : successRecords) { + successRecord.setAgentStatus(agentStatusMap.get(successRecord.getHostId())); + } + } + return records; + } + + @Override + public void updateStatus(Long id, String status, String message) { + HostAgentLogDO update = HostAgentLogDO.builder() + .id(id) + .status(status) + .message(message) + .build(); + hostAgentLogDAO.updateById(update); + } + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostAgentServiceImpl.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostAgentServiceImpl.java new file mode 100644 index 00000000..e4278506 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostAgentServiceImpl.java @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.service.impl; + +import cn.orionsec.kit.lang.utils.Exceptions; +import cn.orionsec.kit.lang.utils.Strings; +import cn.orionsec.kit.lang.utils.collect.Lists; +import cn.orionsec.kit.lang.utils.collect.Maps; +import cn.orionsec.kit.lang.utils.crypto.enums.HashDigest; +import cn.orionsec.kit.lang.utils.io.FileReaders; +import cn.orionsec.kit.lang.utils.io.Files1; +import cn.orionsec.kit.lang.utils.io.compress.CompressTypeEnum; +import cn.orionsec.kit.lang.utils.io.compress.FileDecompressor; +import cn.orionsec.kit.lang.utils.net.IPs; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.common.constant.Const; +import org.dromara.visor.common.constant.ErrorMessage; +import org.dromara.visor.common.constant.ExtraFieldConst; +import org.dromara.visor.common.constant.FileConst; +import org.dromara.visor.common.utils.PathUtils; +import org.dromara.visor.common.utils.Valid; +import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs; +import org.dromara.visor.framework.redis.core.utils.RedisStrings; +import org.dromara.visor.module.asset.convert.HostConvert; +import org.dromara.visor.module.asset.dao.HostAgentLogDAO; +import org.dromara.visor.module.asset.dao.HostDAO; +import org.dromara.visor.module.asset.define.cache.HostCacheKeyDefine; +import org.dromara.visor.module.asset.entity.domain.HostAgentLogDO; +import org.dromara.visor.module.asset.entity.domain.HostDO; +import org.dromara.visor.module.asset.entity.request.host.HostAgentInstallRequest; +import org.dromara.visor.module.asset.entity.vo.HostAgentStatusVO; +import org.dromara.visor.module.asset.enums.*; +import org.dromara.visor.module.asset.handler.agent.intstall.AgentInstaller; +import org.dromara.visor.module.asset.handler.agent.model.AgentInstallParams; +import org.dromara.visor.module.asset.service.HostAgentService; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 主机探针 服务实现类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/28 10:10 + */ +@Slf4j +@Service +public class HostAgentServiceImpl implements HostAgentService { + + private static final String AGENT_FILE_FORMAT = "agent_{}_{}{}"; + + private String localVersion; + + @Value("${orion.api.expose.token}") + private String exposeToken; + + @Resource + private HostDAO hostDAO; + + @Resource + private HostAgentLogDAO hostAgentLogDAO; + + /** + * 读取本地探针版本 + */ + @PostConstruct + public void readLocalAgentVersion() { + log.info("HostAgentService-readLocalAgentVersion start"); + // 文件路径 + String path = PathUtils.getOrionPath(FileConst.AGENT_RELEASE + Const.SLASH + FileConst.VERSION); + log.info("HostAgentService-readLocalAgentVersion path: {}", path); + try { + if (!Files1.isFile(path)) { + log.error("HostAgentService-readLocalAgentVersion not file"); + return; + } + // 读取文件内容 + byte[] bytes = FileReaders.readAllBytesFast(path); + this.localVersion = new String(bytes).trim(); + log.info("HostAgentService-readLocalAgentVersion version: {}", localVersion); + } catch (Exception e) { + log.error("HostAgentService-readLocalAgentVersion error", e); + } + } + + @Override + public List getAgentStatus(List idList) { + if (Lists.isEmpty(idList)) { + return Lists.empty(); + } + return hostDAO.of() + .createWrapper() + .select(HostDO::getId, + HostDO::getAgentVersion, + HostDO::getAgentInstallStatus, + HostDO::getAgentOnlineStatus) + .in(HostDO::getId, idList) + .then() + .stream() + .map(HostConvert.MAPPER::toAgentStatus) + .peek(s -> s.setLatestVersion(localVersion)) + .collect(Collectors.toList()); + } + + @Override + public void installAgent(HostAgentInstallRequest request) { + // 查询主机信息 + List idList = request.getIdList(); + List hosts = hostDAO.selectBatchIds(idList); + Valid.eq(hosts.size(), idList.size(), ErrorMessage.HOST_ABSENT); + + // 检查并创建安装任务参数 + List installTaskParams = this.createInstallTaskParams(hosts); + + // 查询当前状态 + boolean hasRunning = hostAgentLogDAO.of() + .createWrapper() + .in(HostAgentLogDO::getHostId, idList) + .eq(HostAgentLogDO::getType, AgentLogTypeEnum.INSTALL.name()) + .in(HostAgentLogDO::getStatus, AgentLogStatusEnum.WAIT.name(), AgentLogStatusEnum.RUNNING.name()) + .then() + .present(); + Valid.isFalse(hasRunning, ErrorMessage.ILLEGAL_STATUS); + + // 创建日志记录 + List agentLogs = hosts.stream() + .map(s -> HostAgentLogDO.builder() + .hostId(s.getId()) + .agentKey(s.getAgentKey()) + .type(AgentLogTypeEnum.INSTALL.name()) + .status(AgentLogStatusEnum.WAIT.name()) + .build()) + .collect(Collectors.toList()); + hostAgentLogDAO.insertBatch(agentLogs); + + // 设置缓存 + for (HostAgentLogDO agentLog : agentLogs) { + String key = HostCacheKeyDefine.HOST_INSTALL_LOG.format(agentLog.getHostId()); + RedisStrings.set(key, HostCacheKeyDefine.HOST_INSTALL_LOG, agentLog.getId()); + } + + // 获取替换变量 + Map replaceVars = this.getReplaceVars(); + + // 提交任务 + for (int i = 0; i < installTaskParams.size(); i++) { + AgentInstallParams params = installTaskParams.get(i); + HostAgentLogDO agentLog = agentLogs.get(i); + params.setLogId(agentLog.getId()); + params.setReplaceVars(this.getHostReplaceVars(replaceVars, params)); + // 执行任务 + AgentInstaller.start(params); + } + } + + @Override + public void uploadAgentRelease(MultipartFile file) { + // 检查文件名 + String fileName = Optional.of(file) + .map(MultipartFile::getOriginalFilename) + .map(String::toLowerCase) + .orElse(Const.EMPTY); + Valid.notBlank(fileName, ErrorMessage.FILE_EXTENSION_TYPE); + Valid.isTrue(fileName.endsWith(Const.SUFFIX_TAR_GZ), ErrorMessage.FILE_EXTENSION_TYPE); + // 保存文件 + String releaseDir = PathUtils.getOrionPath(FileConst.AGENT_RELEASE); + String releaseTempDir = PathUtils.getOrionPath(FileConst.AGENT_RELEASE_TEMP); + File releaseTempFile = new File(releaseTempDir + Const.SLASH + FileConst.AGENT_RELEASE_TAR_GZ); + log.info("HostAgentService.installAgent start releaseTempDir: {}, releaseTempFile: {}", releaseTempDir, releaseTempFile.getAbsolutePath()); + try { + // 创建目录 + Files1.mkdirs(releaseTempFile.getParentFile()); + // 传输文件 + file.transferTo(releaseTempFile); + } catch (IOException e) { + throw Exceptions.app(ErrorMessage.FILE_UPLOAD_ERROR, e); + } + // 计算签名 + try { + String sign = Files1.sign(releaseTempFile, HashDigest.SHA256); + OperatorLogs.add(ExtraFieldConst.SIGN, sign); + OperatorLogs.add(ExtraFieldConst.SIGN_SHORT, sign.substring(0, 8)); + log.error("HostAgentService.installAgent calc sha256 sign: {}", sign); + } catch (Exception e) { + log.error("HostAgentService.installAgent calc sha256 error", e); + throw Exceptions.app(ErrorMessage.CALC_SIGN_FAILED, e); + } + // 解压缩文件 + try { + FileDecompressor decompressor = CompressTypeEnum.TAR_GZ.decompressor().get(); + decompressor.setDecompressFile(releaseTempFile); + decompressor.setDecompressTargetPath(releaseTempDir); + decompressor.decompress(); + log.info("HostAgentService.installAgent decompress success"); + } catch (Exception e) { + log.error("HostAgentService.installAgent decompress error", e); + throw Exceptions.app(ErrorMessage.CALC_SIGN_FAILED, e); + } + // 获取全部文件 + List decompressFiles = Files1.listFiles(releaseTempDir); + log.info("HostAgentService.installAgent decompressFiles: {}", Lists.map(decompressFiles, File::getName)); + // 检查版本文件 + String versionFile = releaseTempDir + Const.SLASH + FileConst.VERSION; + Valid.isTrue(Files1.isFile(versionFile), ErrorMessage.DECOMPRESS_FILE_ABSENT + Const.SPACE + FileConst.VERSION); + // 移动文件 + for (File decompressFile : decompressFiles) { + String releaseFile = releaseDir + Const.SLASH + decompressFile.getName(); + // 删除原始文件 + Files1.deleteFile(releaseFile); + // 复制文件 + Files1.copy(decompressFile.getAbsolutePath(), releaseFile); + log.info("HostAgentService.installAgent move: {}", releaseFile); + } + // 删除临时文件夹 + Files1.delete(releaseTempDir); + // 重新加载版本 + this.readLocalAgentVersion(); + } + + @Override + public String getAgentVersion() { + return localVersion; + } + + /** + * 检查并创建安装任务参数 + * + * @param hosts hosts + * @return taskParams + */ + private List createInstallTaskParams(List hosts) { + List taskParams = new ArrayList<>(); + // 待检查的文件列表 + Set checkFileList = new HashSet<>(); + // 任务参数 + for (HostDO host : hosts) { + // 是否启用 + Valid.eq(HostStatusEnum.ENABLED.name(), host.getStatus(), ErrorMessage.HOST_NOT_ENABLED, host.getName()); + // 是否支持 ssh + boolean supportSsh = HostTypeEnum.SSH.contains(host.getTypes()); + Valid.isTrue(supportSsh, ErrorMessage.PLEASE_CHECK_HOST_SSH, host.getName()); + // 文件名称 + HostOsTypeEnum os = HostOsTypeEnum.of(host.getOsType()); + String agentFileName = Strings.format(AGENT_FILE_FORMAT, + os.name().toLowerCase(), + host.getArchType().toLowerCase(), + os.getBinarySuffix()); + // 安装参数 + AgentInstallParams params = AgentInstallParams.builder() + .hostId(host.getId()) + .osType(host.getOsType()) + .agentKey(host.getAgentKey()) + .agentFilePath(PathUtils.getOrionPath(FileConst.AGENT_RELEASE + Const.SLASH + agentFileName)) + .configFilePath(PathUtils.getOrionPath(FileConst.AGENT_RELEASE + Const.SLASH + FileConst.CONFIG_YAML)) + .startScriptPath(PathUtils.getOrionPath(FileConst.AGENT_RELEASE + Const.SLASH + Const.START + os.getScriptSuffix())) + .build(); + taskParams.add(params); + // 添加待检查文件 + checkFileList.add(params.getAgentFilePath()); + checkFileList.add(params.getStartScriptPath()); + checkFileList.add(params.getConfigFilePath()); + } + + // 检查文件是否存在 + for (String file : checkFileList) { + Valid.isTrue(Files1.isFile(file), ErrorMessage.FILE_ABSENT + Const.SPACE + file); + } + return taskParams; + } + + /** + * 获取替换变量 + * + * @return vars + */ + private Map getReplaceVars() { + Map map = new HashMap<>(); + map.put("SERVER_HOST", IPs.IP); + map.put("SERVER_TOKEN", exposeToken); + return map; + } + + /** + * 获取主机替换变量 + * + * @param vars vars + * @return vars + */ + private Map getHostReplaceVars(Map vars, AgentInstallParams params) { + vars = Maps.newMap(vars); + vars.put("AGENT_KEY", params.getAgentKey()); + return vars; + } + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostConnectServiceImpl.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostConnectServiceImpl.java index 647a5451..c369de68 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostConnectServiceImpl.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostConnectServiceImpl.java @@ -476,6 +476,7 @@ public class HostConnectServiceImpl implements HostConnectService { config.setHostName(host.getName()); config.setHostCode(host.getCode()); config.setHostAddress(host.getAddress()); + config.setAgentKey(host.getAgentKey()); } } diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostExtraServiceImpl.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostExtraServiceImpl.java index 3add637b..0e7cb714 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostExtraServiceImpl.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostExtraServiceImpl.java @@ -23,10 +23,15 @@ package org.dromara.visor.module.asset.service.impl; import cn.orionsec.kit.lang.utils.Strings; +import cn.orionsec.kit.lang.utils.collect.Lists; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import org.dromara.visor.common.constant.Const; +import org.dromara.visor.common.constant.ErrorMessage; import org.dromara.visor.common.handler.data.model.GenericsDataModel; import org.dromara.visor.common.utils.Valid; import org.dromara.visor.framework.security.core.utils.SecurityUtils; +import org.dromara.visor.module.asset.dao.HostDAO; import org.dromara.visor.module.asset.entity.request.host.HostExtraUpdateRequest; import org.dromara.visor.module.asset.handler.host.extra.HostExtraItemEnum; import org.dromara.visor.module.asset.handler.host.extra.model.HostSpecExtraModel; @@ -53,6 +58,9 @@ import java.util.stream.Collectors; @Service public class HostExtraServiceImpl implements HostExtraService { + @Resource + private HostDAO hostDAO; + @Resource private DataExtraApi dataExtraApi; @@ -146,6 +154,44 @@ public class HostExtraServiceImpl implements HostExtraService { dataExtraApi.addExtraItems(newItems, DataExtraTypeEnum.HOST); } + @Override + public void syncHostSpec(String key, String taskId, JSONObject spec) { + try { + // 查询主机id + Long id = hostDAO.selectIdByAgentKey(key); + Valid.notNull(id, ErrorMessage.HOST_ABSENT); + // 设置已同步标识 + spec.put(Const.SYNCED, true); + // 查询配置信息 + String newSpec; + HostSpecExtraModel beforeSpec = this.getHostSpecMap(Lists.singleton(id)).get(id); + if (beforeSpec == null) { + // 新增 + newSpec = spec.toString(); + } else { + // 合并 + JSONObject beforeSpecValue = JSON.parseObject(beforeSpec.serial()); + spec.forEach((k, v) -> { + if (v != null) { + beforeSpecValue.put(k, v); + } + }); + newSpec = beforeSpecValue.toJSONString(); + } + // 修改规格 + DataExtraSetDTO update = new DataExtraSetDTO(); + update.setUserId(Const.SYSTEM_USER_ID); + update.setRelId(id); + update.setItem(HostExtraItemEnum.SPEC.name()); + update.setValue(newSpec); + dataExtraApi.setExtraItem(update, DataExtraTypeEnum.HOST); + // 回调成功 + } catch (Exception e) { + // 回调失败 + throw e; + } + } + /** * 检查配置项并且转为视图 (不存在则初始化默认值) * diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostServiceImpl.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostServiceImpl.java index b5a2c178..4d10c694 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostServiceImpl.java +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/service/impl/HostServiceImpl.java @@ -23,6 +23,7 @@ package org.dromara.visor.module.asset.service.impl; import cn.orionsec.kit.lang.define.wrapper.DataGrid; +import cn.orionsec.kit.lang.id.UUIds; import cn.orionsec.kit.lang.utils.Booleans; import cn.orionsec.kit.lang.utils.Strings; import cn.orionsec.kit.lang.utils.collect.Lists; @@ -36,6 +37,7 @@ import org.dromara.visor.common.constant.ErrorMessage; import org.dromara.visor.common.enums.EnableStatus; import org.dromara.visor.common.utils.Valid; import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs; +import org.dromara.visor.framework.mybatis.core.query.DataQuery; import org.dromara.visor.framework.redis.core.utils.RedisMaps; import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers; import org.dromara.visor.module.asset.convert.HostConvert; @@ -46,6 +48,7 @@ import org.dromara.visor.module.asset.entity.domain.HostDO; import org.dromara.visor.module.asset.entity.dto.HostCacheDTO; import org.dromara.visor.module.asset.entity.request.host.*; import org.dromara.visor.module.asset.entity.vo.HostVO; +import org.dromara.visor.module.asset.enums.AgentInstallStatusEnum; import org.dromara.visor.module.asset.enums.HostStatusEnum; import org.dromara.visor.module.asset.handler.host.extra.HostExtraItemEnum; import org.dromara.visor.module.asset.handler.host.extra.model.HostSpecExtraModel; @@ -63,6 +66,7 @@ import org.dromara.visor.module.infra.enums.DataExtraTypeEnum; import org.dromara.visor.module.infra.enums.DataGroupTypeEnum; import org.dromara.visor.module.infra.enums.FavoriteTypeEnum; import org.dromara.visor.module.infra.enums.TagTypeEnum; +import org.dromara.visor.module.monitor.api.MonitorHostApi; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -116,13 +120,19 @@ public class HostServiceImpl implements HostService { @Resource private DataExtraApi dataExtraApi; + @Resource + private MonitorHostApi monitorHostApi; + @Override @Transactional(rollbackFor = Exception.class) public Long createHost(HostCreateRequest request) { log.info("HostService-createHost request: {}", JSON.toJSONString(request)); // 转换 HostDO record = HostConvert.MAPPER.to(request); + // 设置默认值 record.setStatus(HostStatusEnum.ENABLED.name()); + record.setAgentKey(UUIds.random32()); + record.setAgentInstallStatus(AgentInstallStatusEnum.NOT_INSTALL.getStatus()); // 查询数据是否冲突 this.checkHostNamePresent(record); this.checkHostCodePresent(record); @@ -230,7 +240,13 @@ public class HostServiceImpl implements HostService { @Override @SneakyThrows - public HostVO getHostById(Long id) { + public HostVO getHostById(Long id, Boolean base) { + // 查询主机基础信息 + if (Booleans.isTrue(base)) { + HostDO record = hostDAO.selectById(id); + Valid.notNull(record, ErrorMessage.HOST_ABSENT); + return HostConvert.MAPPER.to(record); + } // 查询 tag 信息 Future> tagFuture = tagRelApi.getRelTagsAsync(TagTypeEnum.HOST, id); // 查询分组信息 @@ -238,10 +254,13 @@ public class HostServiceImpl implements HostService { // 查询主机 HostDO record = hostDAO.selectById(id); Valid.notNull(record, ErrorMessage.HOST_ABSENT); + // 查询规格 + HostSpecExtraModel spec = hostExtraService.getHostExtra(Const.SYSTEM_USER_ID, id, HostExtraItemEnum.SPEC); // 转换 HostVO vo = HostConvert.MAPPER.to(record); vo.setTags(tagFuture.get()); vo.setGroupIdList(groupIdFuture.get()); + vo.setSpec(spec); return vo; } @@ -283,12 +302,20 @@ public class HostServiceImpl implements HostService { if (wrapper == null) { return DataGrid.of(Lists.empty()); } - // 查询 - DataGrid hosts = hostDAO.of() + // 完整条件 + DataQuery query = hostDAO.of() .wrapper(wrapper) - .page(request) - .order(request, HostDO::getId) - .dataGrid(HostConvert.MAPPER::to); + .page(request); + if (Booleans.isTrue(request.getOrderByAgent())) { + // 通过 agentInstallStatus 进行排序 + query.order(false, HostDO::getAgentInstallStatus); + query.order(false, HostDO::getAgentOnlineStatus); + } else { + // 通过 id 进行排序 + query.order(request, HostDO::getId); + } + // 查询数据 + DataGrid hosts = query.dataGrid(HostConvert.MAPPER::to); // 查询拓展信息 this.setExtraInfo(request, hosts.getRows()); return hosts; @@ -343,6 +370,8 @@ public class HostServiceImpl implements HostService { favoriteApi.deleteByRelIdList(FavoriteTypeEnum.HOST, idList); // 删除额外配置 dataExtraApi.deleteByRelIdList(DataExtraTypeEnum.HOST, idList); + // 删除监控主机 + monitorHostApi.deleteByHostIdList(idList); } @Override @@ -396,9 +425,13 @@ public class HostServiceImpl implements HostService { } // 基础条件 wrapper.eq(HostDO::getId, request.getId()) + .in(HostDO::getId, request.getIdList()) .eq(HostDO::getOsType, request.getOsType()) .eq(HostDO::getArchType, request.getArchType()) .eq(HostDO::getStatus, request.getStatus()) + .eq(HostDO::getAgentKey, request.getAgentKey()) + .eq(HostDO::getAgentInstallStatus, request.getAgentInstallStatus()) + .eq(HostDO::getAgentOnlineStatus, request.getAgentOnlineStatus()) .like(HostDO::getName, request.getName()) .like(HostDO::getCode, request.getCode()) .like(HostDO::getAddress, request.getAddress()) diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/task/AgentHeartbeatCheckTask.java b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/task/AgentHeartbeatCheckTask.java new file mode 100644 index 00000000..dbad8171 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/java/org/dromara/visor/module/asset/task/AgentHeartbeatCheckTask.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.asset.task; + +import org.dromara.visor.module.asset.service.HostAgentEndpointService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 探针心跳检查任务 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2024/4/15 23:50 + */ +@Component +public class AgentHeartbeatCheckTask { + + @Resource + private HostAgentEndpointService hostAgentEndpointService; + + /** + * 每分钟检测心跳 + */ + @Scheduled(initialDelay = 65000, fixedRate = 60000) + public void checkHeartbeat() { + hostAgentEndpointService.checkHeartbeat(); + } + +} diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/resources/mapper/HostAgentLogMapper.xml b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/resources/mapper/HostAgentLogMapper.xml new file mode 100644 index 00000000..003e5aeb --- /dev/null +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/resources/mapper/HostAgentLogMapper.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + id, host_id, agent_key, type, status, message, create_time, update_time, creator, updater, deleted + + + diff --git a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/resources/mapper/HostMapper.xml b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/resources/mapper/HostMapper.xml index 6e205c27..83e65934 100644 --- a/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/resources/mapper/HostMapper.xml +++ b/orion-visor-modules/orion-visor-module-asset/orion-visor-module-asset-service/src/main/resources/mapper/HostMapper.xml @@ -12,6 +12,11 @@ + + + + + @@ -22,7 +27,7 @@ - id, types, os_type, arch_type, name, code, address, status, description, create_time, update_time, creator, updater, deleted + id, types, os_type, arch_type, name, code, address, status, agent_key, agent_version, agent_install_status, agent_online_status, agent_online_change_time, description, create_time, update_time, creator, updater, deleted diff --git a/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/controller/UploadTaskController.java b/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/controller/UploadTaskController.java index d189fff1..eb622ca9 100644 --- a/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/controller/UploadTaskController.java +++ b/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/controller/UploadTaskController.java @@ -113,7 +113,8 @@ public class UploadTaskController { @Operation(summary = "查询上传状态") @Parameter(name = "id", description = "id", required = true) @PreAuthorize("@ss.hasPermission('exec:upload-task:query')") - public List getUploadTaskStatus(@RequestParam("idList") List idList, @RequestParam("queryFiles") Boolean queryFiles) { + public List getUploadTaskStatus(@RequestParam("idList") List idList, + @RequestParam("queryFiles") Boolean queryFiles) { return uploadTaskService.getUploadTaskStatus(idList, queryFiles); } diff --git a/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/define/ExecThreadPools.java b/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/define/ExecThreadPools.java index cfa7362b..81e78ae2 100644 --- a/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/define/ExecThreadPools.java +++ b/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/define/ExecThreadPools.java @@ -29,7 +29,7 @@ import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; /** - * 资产线程池 + * 执行线程池 * * @author Jiahang Li * @version 1.0.0 diff --git a/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/handler/exec/command/handler/BaseExecCommandHandler.java b/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/handler/exec/command/handler/BaseExecCommandHandler.java index 93d11313..1ae8fe8d 100644 --- a/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/handler/exec/command/handler/BaseExecCommandHandler.java +++ b/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/handler/exec/command/handler/BaseExecCommandHandler.java @@ -408,6 +408,8 @@ public abstract class BaseExecCommandHandler implements IExecCommandHandler { params.put("hostAddress", connectConfig.getHostAddress()); params.put("hostPort", connectConfig.getHostPort()); params.put("hostUsername", connectConfig.getUsername()); + // TODO 文档 + params.put("agentKey", connectConfig.getAgentKey()); params.put("hostUuid", uuid); params.put("hostUuidShort", uuid.replace("-", Strings.EMPTY)); params.put("osType", connectConfig.getOsType()); diff --git a/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/service/impl/UploadTaskServiceImpl.java b/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/service/impl/UploadTaskServiceImpl.java index 1ef5955f..072bb330 100644 --- a/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/service/impl/UploadTaskServiceImpl.java +++ b/orion-visor-modules/orion-visor-module-exec/orion-visor-module-exec-service/src/main/java/org/dromara/visor/module/exec/service/impl/UploadTaskServiceImpl.java @@ -372,10 +372,9 @@ public class UploadTaskServiceImpl implements UploadTaskService { // 检查主机数量 Valid.eq(hosts.size(), hostIdList.size(), ErrorMessage.HOST_ABSENT); // 检查主机状态 - boolean allEnabled = hosts.stream() - .map(HostDTO::getStatus) - .allMatch(s -> HostStatusEnum.ENABLED.name().equals(s)); - Valid.isTrue(allEnabled, ErrorMessage.HOST_NOT_ENABLED); + for (HostDTO host : hosts) { + Valid.eq(HostStatusEnum.ENABLED.name(), host.getStatus(), ErrorMessage.HOST_NOT_ENABLED, host.getName()); + } return hosts; } diff --git a/orion-visor-modules/orion-visor-module-infra/orion-visor-module-infra-provider/src/main/java/org/dromara/visor/module/infra/api/SystemUserApi.java b/orion-visor-modules/orion-visor-module-infra/orion-visor-module-infra-provider/src/main/java/org/dromara/visor/module/infra/api/SystemUserApi.java index 07bdc5e8..e705fb68 100644 --- a/orion-visor-modules/orion-visor-module-infra/orion-visor-module-infra-provider/src/main/java/org/dromara/visor/module/infra/api/SystemUserApi.java +++ b/orion-visor-modules/orion-visor-module-infra/orion-visor-module-infra-provider/src/main/java/org/dromara/visor/module/infra/api/SystemUserApi.java @@ -33,6 +33,14 @@ import org.dromara.visor.module.infra.entity.dto.user.SystemUserDTO; */ public interface SystemUserApi { + /** + * 通过用户名查询 id + * + * @param username username + * @return id + */ + Long getIdByUsername(String username); + /** * 通过 id 查询用户名 * diff --git a/orion-visor-modules/orion-visor-module-infra/orion-visor-module-infra-service/src/main/java/org/dromara/visor/module/infra/api/impl/SystemUserApiImpl.java b/orion-visor-modules/orion-visor-module-infra/orion-visor-module-infra-service/src/main/java/org/dromara/visor/module/infra/api/impl/SystemUserApiImpl.java index de95ba5a..2745c662 100644 --- a/orion-visor-modules/orion-visor-module-infra/orion-visor-module-infra-service/src/main/java/org/dromara/visor/module/infra/api/impl/SystemUserApiImpl.java +++ b/orion-visor-modules/orion-visor-module-infra/orion-visor-module-infra-service/src/main/java/org/dromara/visor/module/infra/api/impl/SystemUserApiImpl.java @@ -44,6 +44,16 @@ public class SystemUserApiImpl implements SystemUserApi { @Resource private SystemUserDAO systemUserDAO; + @Override + public Long getIdByUsername(String username) { + return systemUserDAO.of() + .createWrapper() + .select(SystemUserDO::getId) + .eq(SystemUserDO::getUsername, username) + .then() + .getOne(SystemUserDO::getId); + } + @Override public String getUsernameById(Long id) { return systemUserDAO.of() diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-provider/pom.xml b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-provider/pom.xml new file mode 100644 index 00000000..222fb39f --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-provider/pom.xml @@ -0,0 +1,26 @@ + + + + org.dromara.visor + orion-visor-module-monitor + ${revision} + + + 4.0.0 + orion-visor-module-monitor-provider + jar + + 项目监控模块 + https://github.com/dromara/orion-visor + + + + + org.dromara.visor + orion-visor-common + + + + \ No newline at end of file diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-provider/src/main/java/org/dromara/visor/module/monitor/api/MonitorHostApi.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-provider/src/main/java/org/dromara/visor/module/monitor/api/MonitorHostApi.java new file mode 100644 index 00000000..ecfd6898 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-provider/src/main/java/org/dromara/visor/module/monitor/api/MonitorHostApi.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.api; + +import java.util.List; + +/** + * 监控主机对外服务 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/19 15:48 + */ +public interface MonitorHostApi { + + /** + * 设置探针为下线状态 + * + * @param agentKeyList agentKeyList + */ + void setAgentOffline(List agentKeyList); + + /** + * 删除监控主机 + * + * @param hostIdList hostIdList + * @return effect + */ + Integer deleteByHostIdList(List hostIdList); + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-provider/src/main/java/org/dromara/visor/module/monitor/entity/dto/.gitkeep b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-provider/src/main/java/org/dromara/visor/module/monitor/entity/dto/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/pom.xml b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/pom.xml new file mode 100644 index 00000000..2c112e37 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/pom.xml @@ -0,0 +1,110 @@ + + + + org.dromara.visor + orion-visor-module-monitor + ${revision} + + + 4.0.0 + orion-visor-module-monitor-service + jar + + 项目监控模块 + https://github.com/dromara/orion-visor + + + + + org.dromara.visor + orion-visor-common + + + + + org.dromara.visor + orion-visor-module-common + ${revision} + + + + + org.dromara.visor + orion-visor-module-infra-provider + ${revision} + + + org.dromara.visor + orion-visor-module-asset-provider + ${revision} + + + org.dromara.visor + orion-visor-module-monitor-provider + ${revision} + + + + + org.dromara.visor + orion-visor-spring-boot-starter-web + + + org.dromara.visor + orion-visor-spring-boot-starter-websocket + + + org.dromara.visor + orion-visor-spring-boot-starter-log + + + org.dromara.visor + orion-visor-spring-boot-starter-biz-operator-log + + + org.dromara.visor + orion-visor-spring-boot-starter-desensitize + + + org.dromara.visor + orion-visor-spring-boot-starter-security + + + org.dromara.visor + orion-visor-spring-boot-starter-redis + + + org.dromara.visor + orion-visor-spring-boot-starter-mybatis + + + org.dromara.visor + orion-visor-spring-boot-starter-storage + + + org.dromara.visor + orion-visor-spring-boot-starter-job + + + org.dromara.visor + orion-visor-spring-boot-starter-test + + + org.dromara.visor + orion-visor-spring-boot-starter-influxdb + + + + + + + + com.github.wvengen + proguard-maven-plugin + + + + + \ No newline at end of file diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/api/impl/MonitorHostApiImpl.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/api/impl/MonitorHostApiImpl.java new file mode 100644 index 00000000..29c6a93d --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/api/impl/MonitorHostApiImpl.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.api.impl; + +import cn.orionsec.kit.lang.utils.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.common.constant.Const; +import org.dromara.visor.module.monitor.api.MonitorHostApi; +import org.dromara.visor.module.monitor.dao.MonitorHostDAO; +import org.dromara.visor.module.monitor.define.context.MonitorContext; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 监控主机对外服务实现 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/19 15:48 + */ +@Slf4j +@Service +public class MonitorHostApiImpl implements MonitorHostApi { + + @Resource + private MonitorHostDAO monitorHostDAO; + + @Resource + private MonitorContext monitorContext; + + @Override + public void setAgentOffline(List agentKeyList) { + // 下线后删除指标 + agentKeyList.forEach(s -> monitorContext.setAgentMetrics(s, null)); + } + + @Override + public Integer deleteByHostIdList(List hostIdList) { + log.info("MonitorHostApi.deleteByHostIdList start hostIdList: {}", hostIdList); + if (Lists.isEmpty(hostIdList)) { + return Const.N_0; + } + // 通过 hostId 删除 + int effect = monitorHostDAO.deleteByHostIdList(hostIdList); + log.info("MonitorHostApi.deleteByHostIdList finish effect: {}", effect); + return effect; + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/constant/MetricsConst.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/constant/MetricsConst.java new file mode 100644 index 00000000..d4b16946 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/constant/MetricsConst.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.constant; + +/** + * 指标常量 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/15 17:23 + */ +public interface MetricsConst { + + String CPU_USER_SECONDS_TOTAL = "cpu_user_seconds_total"; + String CPU_SYSTEM_SECONDS_TOTAL = "cpu_system_seconds_total"; + String CPU_TOTAL_SECONDS_TOTAL = "cpu_total_seconds_total"; + + String MEM_USED_BYTES_TOTAL = "mem_used_bytes_total"; + String MEM_USED_PERCENT = "mem_used_percent"; + String MEM_SWAP_USED_BYTES_TOTAL = "mem_swap_used_bytes_total"; + String MEM_SWAP_USED_PERCENT = "mem_swap_used_percent"; + + String LOAD1 = "load1"; + String LOAD5 = "load5"; + String LOAD15 = "load15"; + String LOAD1_CORE_RATIO = "load1_core_ratio"; + String LOAD5_CORE_RATIO = "load5_core_ratio"; + String LOAD15_CORE_RATIO = "load15_core_ratio"; + + String DISK_FS_USED_BYTES_TOTAL = "disk_fs_used_bytes_total"; + String DISK_FS_USED_PERCENT = "disk_fs_used_percent"; + String DISK_FS_INODES_USED_PERCENT = "disk_fs_inodes_used_percent"; + + String DISK_IO_READ_BYTES_TOTAL = "disk_io_read_bytes_total"; + String DISK_IO_WRITE_BYTES_TOTAL = "disk_io_write_bytes_total"; + String DISK_IO_READS_TOTAL = "disk_io_reads_total"; + String DISK_IO_WRITES_TOTAL = "disk_io_writes_total"; + String DISK_IO_READ_BYTES_PER_SECOND = "disk_io_read_bytes_per_second"; + String DISK_IO_WRITE_BYTES_PER_SECOND = "disk_io_write_bytes_per_second"; + String DISK_IO_READS_PER_SECOND = "disk_io_reads_per_second"; + String DISK_IO_WRITES_PER_SECOND = "disk_io_writes_per_second"; + + String NET_SENT_BYTES_TOTAL = "net_sent_bytes_total"; + String NET_RECV_BYTES_TOTAL = "net_recv_bytes_total"; + String NET_SENT_PACKETS_TOTAL = "net_sent_packets_total"; + String NET_RECV_PACKETS_TOTAL = "net_recv_packets_total"; + String NET_SENT_BYTES_PER_SECOND = "net_sent_bytes_per_second"; + String NET_RECV_BYTES_PER_SECOND = "net_recv_bytes_per_second"; + String NET_SENT_PACKETS_PER_SECOND = "net_sent_packets_per_second"; + String NET_RECV_PACKETS_PER_SECOND = "net_recv_packets_per_second"; + + String NET_TCP_CONNECTIONS = "net_tcp_connections"; + String NET_UDP_CONNECTIONS = "net_udp_connections"; + String NET_INET_CONNECTIONS = "net_inet_connections"; + String NET_ALL_CONNECTIONS = "net_all_connections"; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/controller/MonitorAgentEndpointController.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/controller/MonitorAgentEndpointController.java new file mode 100644 index 00000000..b1e5fba2 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/controller/MonitorAgentEndpointController.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.common.constant.CustomHeaderConst; +import org.dromara.visor.framework.log.core.annotation.IgnoreLog; +import org.dromara.visor.framework.log.core.enums.IgnoreLogMode; +import org.dromara.visor.framework.web.core.annotation.ExposeApi; +import org.dromara.visor.framework.web.core.annotation.RestWrapper; +import org.dromara.visor.module.monitor.entity.dto.HostMetaDTO; +import org.dromara.visor.module.monitor.entity.dto.MetricsDataDTO; +import org.dromara.visor.module.monitor.service.MonitorAgentEndpointService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +/** + * 监控探针端点 api + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/22 14:33 + */ +@Tag(name = "monitor - 监控探针端点") +@Slf4j +@Validated +@RestWrapper +@RestController +@RequestMapping("/monitor/agent-endpoint") +public class MonitorAgentEndpointController { + + @Resource + private MonitorAgentEndpointService monitorAgentEndpointService; + + @ExposeApi + @IgnoreLog(IgnoreLogMode.ALL) + @PostMapping("/metrics") + @Operation(summary = "上报指标数据") + public Boolean addMetrics(@RequestHeader(CustomHeaderConst.AGENT_KEY_HEADER) String key, + @RequestBody MetricsDataDTO data) { + monitorAgentEndpointService.addMetrics(key, data); + return true; + } + + @ExposeApi + @PostMapping("/sync-host-meta") + @Operation(summary = "上线时同步主机元数据") + public Boolean syncHostMeta(@RequestHeader(CustomHeaderConst.AGENT_KEY_HEADER) String key, + @RequestBody HostMetaDTO data) { + monitorAgentEndpointService.syncHostMeta(key, data); + return true; + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/controller/MonitorHostController.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/controller/MonitorHostController.java new file mode 100644 index 00000000..2e83692f --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/controller/MonitorHostController.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.controller; + +import cn.orionsec.kit.lang.define.wrapper.DataGrid; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.common.entity.chart.TimeChartSeries; +import org.dromara.visor.common.validator.group.Key; +import org.dromara.visor.common.validator.group.Page; +import org.dromara.visor.framework.biz.operator.log.core.annotation.OperatorLog; +import org.dromara.visor.framework.log.core.annotation.IgnoreLog; +import org.dromara.visor.framework.log.core.enums.IgnoreLogMode; +import org.dromara.visor.framework.web.core.annotation.DemoDisableApi; +import org.dromara.visor.framework.web.core.annotation.RestWrapper; +import org.dromara.visor.module.monitor.define.operator.MonitorHostOperatorType; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostChartRequest; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostQueryRequest; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostSwitchUpdateRequest; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostUpdateRequest; +import org.dromara.visor.module.monitor.entity.vo.MonitorHostMetricsDataVO; +import org.dromara.visor.module.monitor.entity.vo.MonitorHostVO; +import org.dromara.visor.module.monitor.service.MonitorHostService; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 监控主机 api + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +@Tag(name = "monitor - 监控主机服务") +@Slf4j +@Validated +@RestWrapper +@RestController +@RequestMapping("/monitor/monitor-host") +public class MonitorHostController { + + @Resource + private MonitorHostService monitorHostService; + + @IgnoreLog(IgnoreLogMode.RET) + @PostMapping("/query") + @Operation(summary = "分页查询监控主机") + @PreAuthorize("@ss.hasPermission('monitor:monitor-host:query')") + public DataGrid getMonitorHostPage(@Validated(Page.class) @RequestBody MonitorHostQueryRequest request) { + return monitorHostService.getMonitorHostPage(request); + } + + @IgnoreLog(IgnoreLogMode.RET) + @PostMapping("/metrics") + @Operation(summary = "查询监控指标") + @PreAuthorize("@ss.hasPermission('monitor:monitor-host:query')") + public List getMonitorHostMetrics(@Validated(Key.class) @RequestBody MonitorHostQueryRequest request) { + return monitorHostService.getMonitorHostMetrics(request.getAgentKeyList()); + } + + @IgnoreLog(IgnoreLogMode.RET) + @PostMapping("/chart") + @Operation(summary = "查询监控指标") + @PreAuthorize("@ss.hasPermission('monitor:monitor-host:query')") + public List getMonitorHostChart(@Validated @RequestBody MonitorHostChartRequest request) { + return monitorHostService.getMonitorHostChart(request); + } + + @DemoDisableApi + @OperatorLog(MonitorHostOperatorType.UPDATE) + @PutMapping("/update") + @Operation(summary = "更新监控主机") + @PreAuthorize("@ss.hasPermission('monitor:monitor-host:update')") + public Integer updateMonitorHost(@Validated @RequestBody MonitorHostUpdateRequest request) { + return monitorHostService.updateMonitorHostById(request); + } + + @DemoDisableApi + @OperatorLog(MonitorHostOperatorType.UPDATE_SWITCH) + @PutMapping("/update-switch") + @Operation(summary = "更新监控主机告警开关") + @PreAuthorize("@ss.hasAnyPermission('monitor:monitor-host:update', 'monitor:monitor-host:update-switch')") + public Integer updateMonitorHostAlarmSwitch(@Validated @RequestBody MonitorHostSwitchUpdateRequest request) { + return monitorHostService.updateMonitorHostAlarmSwitch(request); + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/controller/MonitorMetricsController.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/controller/MonitorMetricsController.java new file mode 100644 index 00000000..905c09b0 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/controller/MonitorMetricsController.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.controller; + +import cn.orionsec.kit.lang.define.wrapper.DataGrid; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.common.validator.group.Page; +import org.dromara.visor.framework.biz.operator.log.core.annotation.OperatorLog; +import org.dromara.visor.framework.log.core.annotation.IgnoreLog; +import org.dromara.visor.framework.log.core.enums.IgnoreLogMode; +import org.dromara.visor.framework.web.core.annotation.DemoDisableApi; +import org.dromara.visor.framework.web.core.annotation.RestWrapper; +import org.dromara.visor.module.monitor.define.operator.MonitorMetricsOperatorType; +import org.dromara.visor.module.monitor.entity.request.metrics.MonitorMetricsCreateRequest; +import org.dromara.visor.module.monitor.entity.request.metrics.MonitorMetricsQueryRequest; +import org.dromara.visor.module.monitor.entity.request.metrics.MonitorMetricsUpdateRequest; +import org.dromara.visor.module.monitor.entity.vo.MonitorMetricsVO; +import org.dromara.visor.module.monitor.service.MonitorMetricsService; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 监控指标 api + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-12 21:31 + */ +@Tag(name = "monitor - 监控指标服务") +@Slf4j +@Validated +@RestWrapper +@RestController +@RequestMapping("/monitor/monitor-metrics") +public class MonitorMetricsController { + + @Resource + private MonitorMetricsService monitorMetricsService; + + @DemoDisableApi + @OperatorLog(MonitorMetricsOperatorType.CREATE) + @PostMapping("/create") + @Operation(summary = "创建监控指标") + @PreAuthorize("@ss.hasPermission('monitor:monitor-metrics:create')") + public Long createMonitorMetrics(@Validated @RequestBody MonitorMetricsCreateRequest request) { + return monitorMetricsService.createMonitorMetrics(request); + } + + @DemoDisableApi + @OperatorLog(MonitorMetricsOperatorType.UPDATE) + @PutMapping("/update") + @Operation(summary = "更新监控指标") + @PreAuthorize("@ss.hasPermission('monitor:monitor-metrics:update')") + public Integer updateMonitorMetrics(@Validated @RequestBody MonitorMetricsUpdateRequest request) { + return monitorMetricsService.updateMonitorMetricsById(request); + } + + @IgnoreLog(IgnoreLogMode.RET) + @GetMapping("/list") + @Operation(summary = "查询全部监控指标") + @PreAuthorize("@ss.hasPermission('monitor:monitor-metrics:query')") + public List getMonitorMetricsList() { + return monitorMetricsService.getMonitorMetricsList(); + } + + @IgnoreLog(IgnoreLogMode.RET) + @PostMapping("/query") + @Operation(summary = "分页查询监控指标") + @PreAuthorize("@ss.hasPermission('monitor:monitor-metrics:query')") + public DataGrid getMonitorMetricsPage(@Validated(Page.class) @RequestBody MonitorMetricsQueryRequest request) { + return monitorMetricsService.getMonitorMetricsPage(request); + } + + @DemoDisableApi + @OperatorLog(MonitorMetricsOperatorType.DELETE) + @DeleteMapping("/delete") + @Operation(summary = "删除监控指标") + @Parameter(name = "id", description = "id", required = true) + @PreAuthorize("@ss.hasPermission('monitor:monitor-metrics:delete')") + public Integer deleteMonitorMetrics(@RequestParam("id") Long id) { + return monitorMetricsService.deleteMonitorMetricsById(id); + } + + @DemoDisableApi + @OperatorLog(MonitorMetricsOperatorType.DELETE) + @DeleteMapping("/batch-delete") + @Operation(summary = "批量删除监控指标") + @Parameter(name = "idList", description = "idList", required = true) + @PreAuthorize("@ss.hasPermission('monitor:monitor-metrics:delete')") + public Integer batchDeleteMonitorMetrics(@RequestParam("idList") List idList) { + return monitorMetricsService.deleteMonitorMetricsByIdList(idList); + } + +} + diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/convert/MonitorHostConvert.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/convert/MonitorHostConvert.java new file mode 100644 index 00000000..719be752 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/convert/MonitorHostConvert.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.convert; + +import org.dromara.visor.module.asset.entity.dto.host.HostDTO; +import org.dromara.visor.module.asset.entity.dto.host.HostQueryDTO; +import org.dromara.visor.module.monitor.entity.domain.MonitorHostDO; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostQueryRequest; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostUpdateRequest; +import org.dromara.visor.module.monitor.entity.vo.MonitorHostVO; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +/** + * 监控主机 内部对象转换器 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +@Mapper +public interface MonitorHostConvert { + + MonitorHostConvert MAPPER = Mappers.getMapper(MonitorHostConvert.class); + + MonitorHostDO to(MonitorHostUpdateRequest request); + + MonitorHostVO to(MonitorHostDO domain); + + @Mapping(target = "id", ignore = true) + @Mapping(target = "hostId", source = "id") + MonitorHostVO to(HostDTO dto); + + HostQueryDTO toHostQuery(MonitorHostQueryRequest request); + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/convert/MonitorMetricsConvert.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/convert/MonitorMetricsConvert.java new file mode 100644 index 00000000..a3e7f862 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/convert/MonitorMetricsConvert.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.convert; + +import org.dromara.visor.module.monitor.entity.domain.MonitorMetricsDO; +import org.dromara.visor.module.monitor.entity.dto.MonitorMetricsCacheDTO; +import org.dromara.visor.module.monitor.entity.request.metrics.MonitorMetricsCreateRequest; +import org.dromara.visor.module.monitor.entity.request.metrics.MonitorMetricsQueryRequest; +import org.dromara.visor.module.monitor.entity.request.metrics.MonitorMetricsUpdateRequest; +import org.dromara.visor.module.monitor.entity.vo.MonitorMetricsVO; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * 监控指标 内部对象转换器 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-12 21:31 + */ +@Mapper +public interface MonitorMetricsConvert { + + MonitorMetricsConvert MAPPER = Mappers.getMapper(MonitorMetricsConvert.class); + + MonitorMetricsDO to(MonitorMetricsCreateRequest request); + + MonitorMetricsDO to(MonitorMetricsUpdateRequest request); + + MonitorMetricsDO to(MonitorMetricsQueryRequest request); + + MonitorMetricsVO to(MonitorMetricsDO domain); + + List to(List list); + + MonitorMetricsVO to(MonitorMetricsCacheDTO cache); + + MonitorMetricsCacheDTO toCache(MonitorMetricsDO domain); + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/dao/MonitorHostDAO.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/dao/MonitorHostDAO.java new file mode 100644 index 00000000..bde3f647 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/dao/MonitorHostDAO.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.dao; + +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.apache.ibatis.annotations.Mapper; +import org.dromara.visor.framework.mybatis.core.mapper.IMapper; +import org.dromara.visor.framework.mybatis.core.query.Conditions; +import org.dromara.visor.module.monitor.entity.domain.MonitorHostDO; + +import java.util.List; + +/** + * 监控主机 Mapper 接口 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +@Mapper +public interface MonitorHostDAO extends IMapper { + + /** + * 通过 hostIdList 查询 + * + * @param hostIdList hostIdList + * @return rows + */ + default List selectByHostIdList(List hostIdList) { + return this.of() + .createWrapper() + .in(MonitorHostDO::getHostId, hostIdList) + .then() + .list(); + } + + /** + * 通过 agentKey 查询 + * + * @param agentKey agentKey + * @return row + */ + default MonitorHostDO selectByAgentKey(String agentKey) { + return this.of() + .createWrapper() + .eq(MonitorHostDO::getAgentKey, agentKey) + .then() + .getOne(); + } + + /** + * 通过 hostId 查询 + * + * @param hostId hostId + * @return row + */ + default MonitorHostDO selectByHostId(Long hostId) { + return this.of() + .createWrapper() + .eq(MonitorHostDO::getHostId, hostId) + .then() + .getOne(); + } + + /** + * 通过 hostIdList 删除 + * + * @param hostIdList hostIdList + * @return effect + */ + default int deleteByHostIdList(List hostIdList) { + return this.delete(Conditions.in(MonitorHostDO::getHostId, hostIdList)); + } + + /** + * 设置 policyId 为 null + * + * @param policyId policyId + * @return effect + */ + default int setPolicyIdWithNull(Long policyId) { + LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate() + .set(MonitorHostDO::getPolicyId, null) + .eq(MonitorHostDO::getPolicyId, policyId); + return this.update(null, updateWrapper); + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/dao/MonitorMetricsDAO.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/dao/MonitorMetricsDAO.java new file mode 100644 index 00000000..e956c5c4 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/dao/MonitorMetricsDAO.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.dao; + +import org.apache.ibatis.annotations.Mapper; +import org.dromara.visor.framework.mybatis.core.mapper.IMapper; +import org.dromara.visor.module.monitor.entity.domain.MonitorMetricsDO; + +/** + * 监控指标 Mapper 接口 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-12 21:31 + */ +@Mapper +public interface MonitorMetricsDAO extends IMapper { + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/define/cache/MonitorMetricsCacheKeyDefine.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/define/cache/MonitorMetricsCacheKeyDefine.java new file mode 100644 index 00000000..2bc2e58a --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/define/cache/MonitorMetricsCacheKeyDefine.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.define.cache; + +import cn.orionsec.kit.lang.define.cache.key.CacheKeyBuilder; +import cn.orionsec.kit.lang.define.cache.key.CacheKeyDefine; +import cn.orionsec.kit.lang.define.cache.key.struct.RedisCacheStruct; +import org.dromara.visor.module.monitor.entity.dto.MonitorMetricsCacheDTO; + +import java.util.concurrent.TimeUnit; + +/** + * 监控指标缓存 key + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-12 21:31 + */ +public interface MonitorMetricsCacheKeyDefine { + + CacheKeyDefine MONITOR_METRICS = new CacheKeyBuilder() + .key("monitor:metrics:list") + .desc("监控指标") + .type(MonitorMetricsCacheDTO.class) + .struct(RedisCacheStruct.HASH) + .timeout(8, TimeUnit.HOURS) + .build(); + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/define/context/MonitorContext.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/define/context/MonitorContext.java new file mode 100644 index 00000000..fbefa1b6 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/define/context/MonitorContext.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.define.context; + +import cn.orionsec.kit.lang.utils.Strings; +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.module.monitor.dao.MonitorHostDAO; +import org.dromara.visor.module.monitor.entity.domain.MonitorHostDO; +import org.dromara.visor.module.monitor.entity.dto.MetricsDataDTO; +import org.dromara.visor.module.monitor.entity.dto.MonitorHostConfigDTO; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 监控上下文 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/21 17:26 + */ +@Slf4j +@Component +public class MonitorContext { + + private static final int MAX_CACHE_TIME = 5 * 60 * 1000; // 5min + + private static final int CLEAN_INTERVAL = 60 * 1000; // 1min + + private static final ConcurrentHashMap LATEST_METRICS_CACHE = new ConcurrentHashMap<>(); + + private static final ConcurrentHashMap HOST_CONFIG_CACHE = new ConcurrentHashMap<>(); + + private long lastCleanTime; + + @Resource + private MonitorHostDAO monitorHostDAO; + + /** + * 初始化监控主机配置 + */ + @PostConstruct + public void initMonitorHostConfig() { + List hosts = monitorHostDAO.selectList(null); + for (MonitorHostDO host : hosts) { + String config = host.getMonitorConfig(); + if (Strings.isBlank(config)) { + continue; + } + // 设置配置缓存 + this.setMonitorHostConfig(host.getAgentKey(), JSON.parseObject(config, MonitorHostConfigDTO.class)); + } + } + + /** + * 设置指标信息 + * + * @param key key + * @param metrics metrics + */ + public void setAgentMetrics(String key, MetricsDataDTO metrics) { + if (metrics == null) { + LATEST_METRICS_CACHE.remove(key); + } else { + LATEST_METRICS_CACHE.put(key, metrics); + } + } + + /** + * 获取指标信息 + * + * @param key key + * @return metrics + */ + public MetricsDataDTO getAgentMetrics(String key) { + // 删除过期缓存 + long current = System.currentTimeMillis(); + if (current - lastCleanTime > CLEAN_INTERVAL) { + this.lastCleanTime = current; + LATEST_METRICS_CACHE.forEach((k, v) -> { + if (current - v.getTimestamp() > MAX_CACHE_TIME) { + LATEST_METRICS_CACHE.remove(k, v); + } + }); + } + return LATEST_METRICS_CACHE.get(key); + } + + /** + * 设置监控主机配置 + * + * @param agentKey agentKey + * @param config config + */ + public void setMonitorHostConfig(String agentKey, MonitorHostConfigDTO config) { + HOST_CONFIG_CACHE.put(agentKey, config); + } + + /** + * 获取监控主机配置 + * + * @param agentKey agentKey + * @return config + */ + public MonitorHostConfigDTO getMonitorHostConfig(String agentKey) { + return HOST_CONFIG_CACHE.get(agentKey); + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/define/operator/MonitorHostOperatorType.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/define/operator/MonitorHostOperatorType.java new file mode 100644 index 00000000..25850dc4 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/define/operator/MonitorHostOperatorType.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.define.operator; + +import org.dromara.visor.framework.biz.operator.log.core.annotation.Module; +import org.dromara.visor.framework.biz.operator.log.core.factory.InitializingOperatorTypes; +import org.dromara.visor.framework.biz.operator.log.core.model.OperatorType; + +import static org.dromara.visor.framework.biz.operator.log.core.enums.OperatorRiskLevel.M; + +/** + * 监控主机 操作日志类型 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +@Module("monitor:monitor-host") +public class MonitorHostOperatorType extends InitializingOperatorTypes { + + public static final String UPDATE = "monitor-host:update"; + + public static final String UPDATE_SWITCH = "monitor-host:update-switch"; + + @Override + public OperatorType[] types() { + return new OperatorType[]{ + new OperatorType(M, UPDATE, "更新监控配置 ${name}"), + new OperatorType(M, UPDATE_SWITCH, "更新监控开关 ${name}${switch}"), + }; + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/define/operator/MonitorMetricsOperatorType.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/define/operator/MonitorMetricsOperatorType.java new file mode 100644 index 00000000..c50e902b --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/define/operator/MonitorMetricsOperatorType.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.define.operator; + +import org.dromara.visor.framework.biz.operator.log.core.annotation.Module; +import org.dromara.visor.framework.biz.operator.log.core.factory.InitializingOperatorTypes; +import org.dromara.visor.framework.biz.operator.log.core.model.OperatorType; + +import static org.dromara.visor.framework.biz.operator.log.core.enums.OperatorRiskLevel.*; + +/** + * 监控指标 操作日志类型 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-12 21:31 + */ +@Module("monitor:monitor-metrics") +public class MonitorMetricsOperatorType extends InitializingOperatorTypes { + + public static final String CREATE = "monitor-metrics:create"; + + public static final String UPDATE = "monitor-metrics:update"; + + public static final String DELETE = "monitor-metrics:delete"; + + @Override + public OperatorType[] types() { + return new OperatorType[]{ + new OperatorType(L, CREATE, "创建监控指标 ${name}"), + new OperatorType(M, UPDATE, "更新监控指标 ${name}"), + new OperatorType(H, DELETE, "删除监控指标 ${count} 条"), + }; + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/domain/MonitorHostDO.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/domain/MonitorHostDO.java new file mode 100644 index 00000000..8216eb9d --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/domain/MonitorHostDO.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.dromara.visor.framework.mybatis.core.domain.BaseDO; + +/** + * 监控主机 实体对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@TableName(value = "monitor_host", autoResultMap = true) +@Schema(name = "MonitorHostDO", description = "监控主机 实体对象") +public class MonitorHostDO extends BaseDO { + + private static final long serialVersionUID = 1L; + + @Schema(description = "主机id") + @TableField("host_id") + private Long hostId; + + @Schema(description = "策略id") + @TableField("policy_id") + private Long policyId; + + @Schema(description = "agentKey") + @TableField("agent_key") + private String agentKey; + + @Schema(description = "告警开关") + @TableField("alarm_switch") + private Integer alarmSwitch; + + @Schema(description = "负责人id") + @TableField("owner_user_id") + private Long ownerUserId; + + @Schema(description = "负责人用户名") + @TableField("owner_username") + private String ownerUsername; + + @Schema(description = "监控元数据") + @TableField("monitor_meta") + private String monitorMeta; + + @Schema(description = "监控配置") + @TableField("monitor_config") + private String monitorConfig; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/domain/MonitorMetricsDO.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/domain/MonitorMetricsDO.java new file mode 100644 index 00000000..01b6cd6f --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/domain/MonitorMetricsDO.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.domain; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.dromara.visor.framework.mybatis.core.domain.BaseDO; + +/** + * 监控指标 实体对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-12 21:31 + */ +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@TableName(value = "monitor_metrics", autoResultMap = true) +@Schema(name = "MonitorMetricsDO", description = "监控指标 实体对象") +public class MonitorMetricsDO extends BaseDO { + + private static final long serialVersionUID = 1L; + + @Schema(description = "指标名称") + @TableField("name") + private String name; + + @Schema(description = "数据集") + @TableField("measurement") + private String measurement; + + @Schema(description = "指标项") + @TableField("value") + private String value; + + @Schema(description = "单位") + @TableField("unit") + private String unit; + + @Schema(description = "后缀") + @TableField("suffix") + private String suffix; + + @Schema(description = "指标描述") + @TableField("description") + private String description; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/HostMetaDTO.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/HostMetaDTO.java new file mode 100644 index 00000000..0a40a6e1 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/HostMetaDTO.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 主机元数据 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/11 22:01 + */ +@Data +public class HostMetaDTO implements Serializable { + + /** + * CPU 列表 + */ + private List cpus; + + /** + * 磁盘名称列表 + */ + private List disks; + + /** + * 网卡名称列表 + */ + private List nets; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MetricsDTO.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MetricsDTO.java new file mode 100644 index 00000000..9419ca0c --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MetricsDTO.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.dto; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import java.io.Serializable; +import java.util.Map; + +/** + * 指标信息 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/11 22:00 + */ +@Data +public class MetricsDTO implements Serializable { + + /** + * 指标类型 + */ + private String type; + + /** + * 标签 + */ + private Map tags; + + /** + * 指标值 + */ + private JSONObject values; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MetricsDataDTO.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MetricsDataDTO.java new file mode 100644 index 00000000..3d7a81a9 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MetricsDataDTO.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 指标数据 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/11 21:59 + */ +@Data +public class MetricsDataDTO implements Serializable { + + /** + * 时间戳 + */ + private Long timestamp; + + /** + * 指标 + */ + private List metrics; + +} + diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MonitorHostConfigDTO.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MonitorHostConfigDTO.java new file mode 100644 index 00000000..b1e4ec16 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MonitorHostConfigDTO.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 监控配置业务对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/13 23:34 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "MonitorHostConfigDTO", description = "监控配置业务对象") +public class MonitorHostConfigDTO implements Serializable { + + @Schema(description = "cpu索引名称") + private String cpuName; + + @Schema(description = "磁盘名称") + private String diskName; + + @Schema(description = "网卡名称") + private String networkName; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MonitorHostMetaDTO.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MonitorHostMetaDTO.java new file mode 100644 index 00000000..a240c225 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MonitorHostMetaDTO.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.List; + +/** + * 监控元数据业务对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/13 23:34 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "MonitorHostMetaDTO", description = "监控元数据业务对象") +public class MonitorHostMetaDTO implements Serializable { + + @Schema(description = "cpu") + private List cpus; + + @Schema(description = "磁盘") + private List disks; + + @Schema(description = "网卡") + private List nets; + + @Schema(description = "内存大小") + private Long memoryBytes; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MonitorMetricsCacheDTO.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MonitorMetricsCacheDTO.java new file mode 100644 index 00000000..acf2aec2 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/dto/MonitorMetricsCacheDTO.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.dto; + +import cn.orionsec.kit.lang.define.cache.key.model.LongCacheIdModel; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Date; + +/** + * 监控指标 缓存对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-12 21:31 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "MonitorMetricsCacheDTO", description = "监控指标 缓存对象") +public class MonitorMetricsCacheDTO implements LongCacheIdModel, Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "指标名称") + private String name; + + @Schema(description = "数据集") + private String measurement; + + @Schema(description = "指标项") + private String value; + + @Schema(description = "单位") + private String unit; + + @Schema(description = "后缀") + private String suffix; + + @Schema(description = "指标描述") + private String description; + + @Schema(description = "创建时间") + private Date createTime; + + @Schema(description = "修改时间") + private Date updateTime; + + @Schema(description = "创建人") + private String creator; + + @Schema(description = "修改人") + private String updater; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostAgentConfigUpdateRequest.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostAgentConfigUpdateRequest.java new file mode 100644 index 00000000..0a5bc583 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostAgentConfigUpdateRequest.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.request.host; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 监控主机配置更新请求 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/13 23:34 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "MonitorHostAgentConfigUpdateRequest", description = "监控主机配置更新请求") +public class MonitorHostAgentConfigUpdateRequest implements Serializable { + + @Schema(description = "cpu索引名称") + private String cpuName; + + @Schema(description = "磁盘名称") + private String diskName; + + @Schema(description = "网卡名称") + private String networkName; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostChartRequest.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostChartRequest.java new file mode 100644 index 00000000..a16903db --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostChartRequest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.request.host; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.visor.common.entity.BaseQueryRequest; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import java.util.List; + +/** + * 监控主机图表 查询请求对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(name = "MonitorHostChartRequest", description = "监控主机图表 查询请求对象") +public class MonitorHostChartRequest extends BaseQueryRequest { + + @NotEmpty + @Schema(description = "agentKey") + private List agentKeys; + + @NotBlank + @Schema(description = "表") + private String measurement; + + @NotEmpty + @Schema(description = "字段") + private List fields; + + @NotBlank + @Schema(description = "时间窗口") + private String window; + + @NotBlank + @Schema(description = "聚合参数") + private String aggregate; + + @Schema(description = "聚合参数") + private Long start; + + @Schema(description = "聚合参数") + private Long end; + + @Schema(description = "区间") + private String range; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostMetaSyncRequest.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostMetaSyncRequest.java new file mode 100644 index 00000000..542baf81 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostMetaSyncRequest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.request.host; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * 监控主机 同步元数据请求对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "MonitorHostMetaSyncRequest", description = "监控主机 同步元数据请求对象") +public class MonitorHostMetaSyncRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotNull + @Schema(description = "hostId") + private Long hostId; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostQueryRequest.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostQueryRequest.java new file mode 100644 index 00000000..d920e405 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostQueryRequest.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.request.host; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.visor.common.entity.BaseQueryRequest; +import org.dromara.visor.common.validator.group.Key; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.Size; +import java.util.List; + +/** + * 监控主机 查询请求对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(name = "MonitorHostQueryRequest", description = "监控主机 查询请求对象") +public class MonitorHostQueryRequest extends BaseQueryRequest { + + @NotEmpty(groups = Key.class) + @Schema(description = "agentKey") + private List agentKeyList; + + @Schema(description = "搜索") + private String searchValue; + + @Schema(description = "告警开关") + private Integer alarmSwitch; + + @Schema(description = "策略id") + private Long policyId; + + @Schema(description = "负责人id") + private Long ownerUserId; + + @Size(max = 64) + @Schema(description = "主机名称") + private String name; + + @Size(max = 64) + @Schema(description = "主机编码") + private String code; + + @Size(max = 128) + @Schema(description = "主机地址") + private String address; + + @Schema(description = "探针安装状态") + private Integer agentInstallStatus; + + @Schema(description = "探针在线状态") + private Integer agentOnlineStatus; + + @Size(max = 255) + @Schema(description = "描述") + private String description; + + @Schema(description = "tag") + private List tags; + + @Schema(description = "是否查询分组信息") + private Boolean queryGroup; + + @Schema(description = "是否查询 tag 信息") + private Boolean queryTag; + + @Schema(description = "是否查询规格信息") + private Boolean querySpec; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostSwitchUpdateRequest.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostSwitchUpdateRequest.java new file mode 100644 index 00000000..1a4b2453 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostSwitchUpdateRequest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.request.host; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * 监控主机 更新告警开关请求对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "MonitorHostSwitchUpdateRequest", description = "监控主机 更新告警开关请求对象") +public class MonitorHostSwitchUpdateRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotNull + @Schema(description = "id") + private Long id; + + @NotNull + @Schema(description = "告警开关") + private Integer alarmSwitch; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostUpdatePolicyRequest.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostUpdatePolicyRequest.java new file mode 100644 index 00000000..8586f0c7 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostUpdatePolicyRequest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.request.host; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * 监控主机 更新策略请求对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "MonitorHostUpdatePolicyRequest", description = "监控主机 更新策略请求对象") +public class MonitorHostUpdatePolicyRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotNull + @Schema(description = "id") + private Long id; + + @NotNull + @Schema(description = "策略id") + private Long policyId; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostUpdateRequest.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostUpdateRequest.java new file mode 100644 index 00000000..af90a9eb --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/host/MonitorHostUpdateRequest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.request.host; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + +/** + * 监控主机 更新请求对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "MonitorHostUpdateRequest", description = "监控主机 更新请求对象") +public class MonitorHostUpdateRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotNull + @Schema(description = "id") + private Long id; + + @Schema(description = "策略id") + private Long policyId; + + @Schema(description = "告警开关") + private Integer alarmSwitch; + + @Schema(description = "负责人id") + private Long ownerUserId; + + @Schema(description = "负责人用户名") + private String ownerUsername; + + @Schema(description = "元数据-cpu索引名称") + private String cpuName; + + @Schema(description = "元数据-磁盘名称") + private String diskName; + + @Schema(description = "元数据-网卡名称") + private String networkName; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/metrics/MonitorMetricsCreateRequest.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/metrics/MonitorMetricsCreateRequest.java new file mode 100644 index 00000000..27ab3300 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/metrics/MonitorMetricsCreateRequest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.request.metrics; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.io.Serializable; + +/** + * 监控指标 创建请求对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-12 21:31 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "MonitorMetricsCreateRequest", description = "监控指标 创建请求对象") +public class MonitorMetricsCreateRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotBlank + @Size(max = 64) + @Schema(description = "指标名称") + private String name; + + @NotBlank + @Size(max = 64) + @Schema(description = "数据集") + private String measurement; + + @NotBlank + @Size(max = 128) + @Schema(description = "指标项") + private String value; + + @NotBlank + @Size(max = 8) + @Schema(description = "单位") + private String unit; + + @Size(max = 32) + @Schema(description = "后缀") + private String suffix; + + @Size(max = 128) + @Schema(description = "指标描述") + private String description; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/metrics/MonitorMetricsQueryRequest.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/metrics/MonitorMetricsQueryRequest.java new file mode 100644 index 00000000..10c6296c --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/metrics/MonitorMetricsQueryRequest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.request.metrics; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.dromara.visor.common.entity.BaseQueryRequest; + +import javax.validation.constraints.Size; + +/** + * 监控指标 查询请求对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-12 21:31 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(callSuper = true) +@Schema(name = "MonitorMetricsQueryRequest", description = "监控指标 查询请求对象") +public class MonitorMetricsQueryRequest extends BaseQueryRequest { + + @Size(max = 64) + @Schema(description = "指标名称") + private String name; + + @Size(max = 64) + @Schema(description = "数据集") + private String measurement; + + @Size(max = 128) + @Schema(description = "指标项") + private String value; + + @Size(max = 8) + @Schema(description = "单位") + private String unit; + + @Size(max = 32) + @Schema(description = "后缀") + private String suffix; + + @Size(max = 128) + @Schema(description = "指标描述") + private String description; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/metrics/MonitorMetricsUpdateRequest.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/metrics/MonitorMetricsUpdateRequest.java new file mode 100644 index 00000000..d81a0bff --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/request/metrics/MonitorMetricsUpdateRequest.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.request.metrics; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; + +/** + * 监控指标 更新请求对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-12 21:31 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "MonitorMetricsUpdateRequest", description = "监控指标 更新请求对象") +public class MonitorMetricsUpdateRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotNull + @Schema(description = "id") + private Long id; + + @NotBlank + @Size(max = 64) + @Schema(description = "指标名称") + private String name; + + @NotBlank + @Size(max = 64) + @Schema(description = "数据集") + private String measurement; + + @NotBlank + @Size(max = 128) + @Schema(description = "指标项") + private String value; + + @NotBlank + @Size(max = 8) + @Schema(description = "单位") + private String unit; + + @Size(max = 32) + @Schema(description = "后缀") + private String suffix; + + @Size(max = 128) + @Schema(description = "指标描述") + private String description; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/vo/MonitorHostMetricsDataVO.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/vo/MonitorHostMetricsDataVO.java new file mode 100644 index 00000000..965313de --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/vo/MonitorHostMetricsDataVO.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 监控主机指标数据 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/15 16:34 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "MonitorHostMetricsDataVO", description = "监控主机指标数据 视图响应对象") +public class MonitorHostMetricsDataVO { + + @Schema(description = "agentKey") + private String agentKey; + + @Schema(description = "是否无数据") + private Boolean noData; + + @Schema(description = "采集时间") + private Long timestamp; + + @Schema(description = "cpu名称") + private String cpuName; + + @Schema(description = "磁盘名称") + private String diskName; + + @Schema(description = "网卡名称") + private String networkName; + + @Schema(description = "cpu 使用率") + private Double cpuUsagePercent; + + @Schema(description = "内存使用率") + private Double memoryUsagePercent; + + @Schema(description = "内存使用量") + private Long memoryUsageBytes; + + @Schema(description = "load1") + private Double load1; + + @Schema(description = "load5") + private Double load5; + + @Schema(description = "load15") + private Double load15; + + @Schema(description = "磁盘使用率") + private Double diskUsagePercent; + + @Schema(description = "磁盘使用量") + private Long diskUsageBytes; + + @Schema(description = "网卡上行带宽速度") + private Double networkSentPreBytes; + + @Schema(description = "网卡下行带宽速度") + private Double networkRecvPreBytes; + + public static MonitorHostMetricsDataVO noData(String agentKey) { + return MonitorHostMetricsDataVO.builder() + .noData(true) + .agentKey(agentKey) + .build(); + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/vo/MonitorHostVO.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/vo/MonitorHostVO.java new file mode 100644 index 00000000..320bd34b --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/vo/MonitorHostVO.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.dromara.visor.module.asset.entity.dto.host.HostAgentLogDTO; +import org.dromara.visor.module.infra.entity.dto.tag.TagDTO; +import org.dromara.visor.module.monitor.entity.dto.MonitorHostConfigDTO; +import org.dromara.visor.module.monitor.entity.dto.MonitorHostMetaDTO; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * 监控主机 视图响应对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "MonitorHostVO", description = "监控主机 视图响应对象") +public class MonitorHostVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "主机id") + private Long hostId; + + @Schema(description = "策略id") + private Long policyId; + + @Schema(description = "策略名称") + private String policyName; + + @Schema(description = "系统类型") + private String osType; + + @Schema(description = "主机名称") + private String name; + + @Schema(description = "主机编码") + private String code; + + @Schema(description = "主机地址") + private String address; + + @Schema(description = "主机状态") + private String status; + + @Schema(description = "agentKey") + private String agentKey; + + @Schema(description = "探针版本") + private String agentVersion; + + @Schema(description = "最新版本") + private String latestVersion; + + @Schema(description = "探针安装状态") + private Integer agentInstallStatus; + + @Schema(description = "探针在线状态") + private Integer agentOnlineStatus; + + @Schema(description = "上次切换在线状态时间") + private Date lastChangeOnlineTime; + + @Schema(description = "告警开关") + private Integer alarmSwitch; + + @Schema(description = "负责人id") + private Long ownerUserId; + + @Schema(description = "负责人用户名") + private String ownerUsername; + + @Schema(description = "tags") + private List tags; + + @Schema(description = "监控元数据") + private MonitorHostMetaDTO meta; + + @Schema(description = "监控配置") + private MonitorHostConfigDTO config; + + @Schema(description = "监控数据") + private MonitorHostMetricsDataVO metricsData; + + @Schema(description = "安装日志") + private HostAgentLogDTO installLog; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/vo/MonitorMetricsVO.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/vo/MonitorMetricsVO.java new file mode 100644 index 00000000..be2b0dbb --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/entity/vo/MonitorMetricsVO.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.entity.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.util.Date; + +/** + * 监控指标 视图响应对象 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-12 21:31 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(name = "MonitorMetricsVO", description = "监控指标 视图响应对象") +public class MonitorMetricsVO implements Serializable { + + private static final long serialVersionUID = 1L; + + @Schema(description = "id") + private Long id; + + @Schema(description = "指标名称") + private String name; + + @Schema(description = "数据集") + private String measurement; + + @Schema(description = "指标项") + private String value; + + @Schema(description = "单位") + private String unit; + + @Schema(description = "后缀") + private String suffix; + + @Schema(description = "指标描述") + private String description; + + @Schema(description = "创建时间") + private Date createTime; + + @Schema(description = "修改时间") + private Date updateTime; + + @Schema(description = "创建人") + private String creator; + + @Schema(description = "修改人") + private String updater; + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/enums/MeasurementFieldEnum.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/enums/MeasurementFieldEnum.java new file mode 100644 index 00000000..c8936655 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/enums/MeasurementFieldEnum.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.enums; + +import lombok.Getter; +import org.apache.commons.collections4.map.HashedMap; +import org.dromara.visor.module.monitor.constant.MetricsConst; + +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +/** + * 指标度量类型 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/14 10:27 + */ +@Getter +public enum MeasurementFieldEnum { + + /** + * cpu + */ + CPU("cpu", (s) -> { + s.accept(MetricsConst.CPU_USER_SECONDS_TOTAL, double.class); + s.accept(MetricsConst.CPU_SYSTEM_SECONDS_TOTAL, double.class); + s.accept(MetricsConst.CPU_TOTAL_SECONDS_TOTAL, double.class); + }), + + /** + * 内存 + */ + MEMORY("memory", s -> { + s.accept(MetricsConst.MEM_USED_BYTES_TOTAL, long.class); + s.accept(MetricsConst.MEM_USED_PERCENT, double.class); + s.accept(MetricsConst.MEM_SWAP_USED_BYTES_TOTAL, long.class); + s.accept(MetricsConst.MEM_SWAP_USED_PERCENT, double.class); + }), + + /** + * 负载 + */ + LOAD("load", s -> { + s.accept(MetricsConst.LOAD1, double.class); + s.accept(MetricsConst.LOAD5, double.class); + s.accept(MetricsConst.LOAD15, double.class); + s.accept(MetricsConst.LOAD1_CORE_RATIO, double.class); + s.accept(MetricsConst.LOAD5_CORE_RATIO, double.class); + s.accept(MetricsConst.LOAD15_CORE_RATIO, double.class); + }), + + /** + * 磁盘 + */ + DISK("disk", s -> { + s.accept(MetricsConst.DISK_FS_USED_BYTES_TOTAL, long.class); + s.accept(MetricsConst.DISK_FS_USED_PERCENT, double.class); + s.accept(MetricsConst.DISK_FS_INODES_USED_PERCENT, double.class); + }), + + /** + * io + */ + IO("io", s -> { + s.accept(MetricsConst.DISK_IO_READ_BYTES_TOTAL, long.class); + s.accept(MetricsConst.DISK_IO_WRITE_BYTES_TOTAL, long.class); + s.accept(MetricsConst.DISK_IO_READS_TOTAL, long.class); + s.accept(MetricsConst.DISK_IO_WRITES_TOTAL, long.class); + s.accept(MetricsConst.DISK_IO_READ_BYTES_PER_SECOND, double.class); + s.accept(MetricsConst.DISK_IO_WRITE_BYTES_PER_SECOND, double.class); + s.accept(MetricsConst.DISK_IO_READS_PER_SECOND, double.class); + s.accept(MetricsConst.DISK_IO_WRITES_PER_SECOND, double.class); + }), + + /** + * 网络 + */ + NETWORK("network", s -> { + s.accept(MetricsConst.NET_SENT_BYTES_TOTAL, long.class); + s.accept(MetricsConst.NET_RECV_BYTES_TOTAL, long.class); + s.accept(MetricsConst.NET_SENT_PACKETS_TOTAL, long.class); + s.accept(MetricsConst.NET_RECV_PACKETS_TOTAL, long.class); + s.accept(MetricsConst.NET_SENT_BYTES_PER_SECOND, double.class); + s.accept(MetricsConst.NET_RECV_BYTES_PER_SECOND, double.class); + s.accept(MetricsConst.NET_SENT_PACKETS_PER_SECOND, double.class); + s.accept(MetricsConst.NET_RECV_PACKETS_PER_SECOND, double.class); + }), + + /** + * 连接数 + */ + CONNECTIONS("connections", s -> { + s.accept(MetricsConst.NET_TCP_CONNECTIONS, int.class); + s.accept(MetricsConst.NET_UDP_CONNECTIONS, int.class); + s.accept(MetricsConst.NET_INET_CONNECTIONS, int.class); + s.accept(MetricsConst.NET_ALL_CONNECTIONS, int.class); + }), + + ; + + private final String measurement; + private final Map> fields; + + MeasurementFieldEnum(String measurement, Consumer>> register) { + this.measurement = measurement; + this.fields = new HashedMap<>(); + register.accept(this.fields::put); + } + + public static MeasurementFieldEnum of(String measurement) { + if (measurement == null) { + return null; + } + for (MeasurementFieldEnum e : values()) { + if (e.measurement.equals(measurement)) { + return e; + } + } + return null; + } + + /** + * 获取度量值类型 + * + * @param measurement measurement + * @param field field + * @return type + */ + public static Class getMetricsValueType(String measurement, String field) { + MeasurementFieldEnum m = of(measurement); + if (m == null) { + return null; + } + return m.getFields().get(field); + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/enums/MetricsAggregateEnum.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/enums/MetricsAggregateEnum.java new file mode 100644 index 00000000..edc58079 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/enums/MetricsAggregateEnum.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 监控指标聚合函数 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/14 10:15 + */ +@Getter +@AllArgsConstructor +public enum MetricsAggregateEnum { + + /** + * 平均值 + */ + MEAN("mean"), + + /** + * 最大值 + */ + MAX("max"), + + /** + * 最小值 + */ + MIN("min"), + + /** + * 总和 + */ + SUM("sum"), + + ; + + private final String fn; + + public static MetricsAggregateEnum of(String fn) { + if (fn == null) { + return MEAN; + } + for (MetricsAggregateEnum e : values()) { + if (e.fn.equals(fn)) { + return e; + } + } + return MEAN; + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/enums/MetricsUnitEnum.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/enums/MetricsUnitEnum.java new file mode 100644 index 00000000..dd6fed4a --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/enums/MetricsUnitEnum.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.enums; + +/** + * 指标单位枚举 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/14 10:15 + */ +public enum MetricsUnitEnum { + + /** + * 字节 + */ + BYTES, + + /** + * 比特 + */ + BITS, + + /** + * 次 + */ + COUNT, + + /** + * 秒 + */ + SECONDS, + + /** + * 百分比 + */ + PER, + + /** + * 字节/秒 + */ + BYTES_S, + + /** + * 比特/秒 + */ + BITS_S, + + /** + * 次/秒 + */ + COUNT_S, + + /** + * 文本 + */ + TEXT, + + /** + * 无 + */ + NONE, + + ; + + public static MetricsUnitEnum of(String name) { + if (name == null) { + return NONE; + } + for (MetricsUnitEnum unit : values()) { + if (unit.name().equals(name)) { + return unit; + } + } + return NONE; + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/enums/MonitorAlarmSwitchEnum.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/enums/MonitorAlarmSwitchEnum.java new file mode 100644 index 00000000..6d6f50e4 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/enums/MonitorAlarmSwitchEnum.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 监控告警开关枚举 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/14 11:23 + */ +@Getter +@AllArgsConstructor +public enum MonitorAlarmSwitchEnum { + + /** + * 关闭 + */ + OFF(0), + + /** + * 开启 + */ + ON(1), + + ; + + private final Integer value; + + public static MonitorAlarmSwitchEnum of(Integer value) { + if (value == null) { + return OFF; + } + for (MonitorAlarmSwitchEnum e : MonitorAlarmSwitchEnum.values()) { + if (value.equals(e.value)) { + return e; + } + } + return OFF; + } + + /** + * 是否开启 + * + * @param value value + * @return on + */ + public static boolean isOn(Integer value) { + return ON.value.equals(value); + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/MonitorAgentEndpointService.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/MonitorAgentEndpointService.java new file mode 100644 index 00000000..8bfe4dc5 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/MonitorAgentEndpointService.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.service; + +import org.dromara.visor.module.monitor.entity.dto.HostMetaDTO; +import org.dromara.visor.module.monitor.entity.dto.MetricsDataDTO; + +/** + * 监控探针端点 服务类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/22 14:42 + */ +public interface MonitorAgentEndpointService { + + /** + * 添加监控指标 + * + * @param agentKey agentKey + * @param data data + */ + void addMetrics(String agentKey, MetricsDataDTO data); + + /** + * 上线时同步元数据 + * + * @param agentKey agentKey + * @param meta meta + */ + void syncHostMeta(String agentKey, HostMetaDTO meta); + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/MonitorHostService.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/MonitorHostService.java new file mode 100644 index 00000000..f998bd7b --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/MonitorHostService.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.service; + +import cn.orionsec.kit.lang.define.wrapper.DataGrid; +import org.dromara.visor.common.entity.chart.TimeChartSeries; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostChartRequest; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostQueryRequest; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostSwitchUpdateRequest; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostUpdateRequest; +import org.dromara.visor.module.monitor.entity.vo.MonitorHostMetricsDataVO; +import org.dromara.visor.module.monitor.entity.vo.MonitorHostVO; + +import java.util.List; + +/** + * 监控主机 服务类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +public interface MonitorHostService { + + /** + * 分页查询监控主机 + * + * @param request request + * @return rows + */ + DataGrid getMonitorHostPage(MonitorHostQueryRequest request); + + /** + * 获取监控主机指标数据 + * + * @param agentKeyList agentKeyList + * @return metrics + */ + List getMonitorHostMetrics(List agentKeyList); + + /** + * 获取监控主机图表数据 + * + * @param request request + * @return series + */ + List getMonitorHostChart(MonitorHostChartRequest request); + + /** + * 更新监控主机 + * + * @param request request + * @return effect + */ + Integer updateMonitorHostById(MonitorHostUpdateRequest request); + + /** + * 更新监控主机告警开关 + * + * @param request request + * @return effect + */ + Integer updateMonitorHostAlarmSwitch(MonitorHostSwitchUpdateRequest request); + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/MonitorMetricsService.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/MonitorMetricsService.java new file mode 100644 index 00000000..6d57af05 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/MonitorMetricsService.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.service; + +import cn.orionsec.kit.lang.define.wrapper.DataGrid; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.dromara.visor.module.monitor.entity.domain.MonitorMetricsDO; +import org.dromara.visor.module.monitor.entity.request.metrics.MonitorMetricsCreateRequest; +import org.dromara.visor.module.monitor.entity.request.metrics.MonitorMetricsQueryRequest; +import org.dromara.visor.module.monitor.entity.request.metrics.MonitorMetricsUpdateRequest; +import org.dromara.visor.module.monitor.entity.vo.MonitorMetricsVO; + +import java.util.List; + +/** + * 监控指标 服务类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-12 21:31 + */ +public interface MonitorMetricsService { + + /** + * 创建监控指标 + * + * @param request request + * @return id + */ + Long createMonitorMetrics(MonitorMetricsCreateRequest request); + + /** + * 更新监控指标 + * + * @param request request + * @return effect + */ + Integer updateMonitorMetricsById(MonitorMetricsUpdateRequest request); + + /** + * 通过缓存查询监控指标 + * + * @return rows + */ + List getMonitorMetricsList(); + + /** + * 分页查询监控指标 + * + * @param request request + * @return rows + */ + DataGrid getMonitorMetricsPage(MonitorMetricsQueryRequest request); + + /** + * 通过值获取监控指标名称 + * + * @param value value + * @return name + */ + String getMetricName(String value); + + /** + * 删除监控指标 + * + * @param id id + * @return effect + */ + Integer deleteMonitorMetricsById(Long id); + + /** + * 批量删除监控指标 + * + * @param idList idList + * @return effect + */ + Integer deleteMonitorMetricsByIdList(List idList); + + /** + * 构建查询 wrapper + * + * @param request request + * @return wrapper + */ + LambdaQueryWrapper buildQueryWrapper(MonitorMetricsQueryRequest request); + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/impl/MonitorAgentEndpointServiceImpl.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/impl/MonitorAgentEndpointServiceImpl.java new file mode 100644 index 00000000..bb50261d --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/impl/MonitorAgentEndpointServiceImpl.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.service.impl; + +import cn.orionsec.kit.lang.able.Executable; +import cn.orionsec.kit.lang.utils.Strings; +import cn.orionsec.kit.lang.utils.collect.Lists; +import cn.orionsec.kit.lang.utils.collect.Maps; +import com.alibaba.fastjson.JSON; +import com.influxdb.client.domain.WritePrecision; +import com.influxdb.client.write.Point; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.common.constant.Const; +import org.dromara.visor.common.constant.ErrorMessage; +import org.dromara.visor.common.utils.LockerUtils; +import org.dromara.visor.common.utils.Valid; +import org.dromara.visor.framework.influxdb.core.utils.InfluxdbUtils; +import org.dromara.visor.module.asset.api.HostApi; +import org.dromara.visor.module.asset.entity.dto.host.HostDTO; +import org.dromara.visor.module.infra.api.SystemUserApi; +import org.dromara.visor.module.monitor.dao.MonitorHostDAO; +import org.dromara.visor.module.monitor.define.context.MonitorContext; +import org.dromara.visor.module.monitor.entity.domain.MonitorHostDO; +import org.dromara.visor.module.monitor.entity.dto.HostMetaDTO; +import org.dromara.visor.module.monitor.entity.dto.MetricsDataDTO; +import org.dromara.visor.module.monitor.entity.dto.MonitorHostConfigDTO; +import org.dromara.visor.module.monitor.enums.MonitorAlarmSwitchEnum; +import org.dromara.visor.module.monitor.service.MonitorAgentEndpointService; +import org.dromara.visor.module.monitor.utils.MetricsUtils; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 监控探针端点 服务实现类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/22 14:42 + */ +@Slf4j +@Service +public class MonitorAgentEndpointServiceImpl implements MonitorAgentEndpointService { + + private static final String LOCK_KEY_PREFIX = "monitor:online:"; + + @Resource + private MonitorHostDAO monitorHostDAO; + + @Resource + private HostApi hostApi; + + @Resource + private SystemUserApi systemUserApi; + + @Resource + private MonitorContext monitorContext; + + @Override + @Async("metricsExecutor") + public void addMetrics(String agentKey, MetricsDataDTO data) { + log.info("MonitorAgentEndpointService.addMetrics start agentKey: {}", agentKey); + // 设置数据缓存 + monitorContext.setAgentMetrics(agentKey, data); + // 数据点 + List points = data.getMetrics() + .stream() + .map(s -> MetricsUtils.createPoint(s.getType(), s.getValues()) + .addTag(Const.KEY, agentKey) + .addTags(Maps.def(s.getTags(), Maps.empty())) + .time(data.getTimestamp(), WritePrecision.MS)) + .collect(Collectors.toList()); + // 写入数据点 + InfluxdbUtils.writePoints(points); + // TODO 告警 + + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void syncHostMeta(String agentKey, HostMetaDTO meta) { + // 同步逻辑 + Executable exec = () -> { + // 查询主机是否存在 + HostDTO host = hostApi.selectByAgentKey(agentKey); + Valid.notNull(host, ErrorMessage.HOST_ABSENT); + // 查询数据 + MonitorHostDO monitorHost = monitorHostDAO.selectByAgentKey(agentKey); + MonitorHostConfigDTO newConfig = null; + if (monitorHost == null) { + // 不存在则新增 + newConfig = this.getDefaultMonitorConfig(meta); + monitorHost = MonitorHostDO.builder() + .hostId(host.getId()) + .agentKey(agentKey) + .alarmSwitch(MonitorAlarmSwitchEnum.OFF.getValue()) + .monitorMeta(JSON.toJSONString(meta)) + .monitorConfig(JSON.toJSONString(newConfig)) + .creator(host.getCreator()) + .updater(host.getCreator()) + .build(); + // 设置负责人信息 + Long userId = systemUserApi.getIdByUsername(host.getCreator()); + if (userId != null) { + monitorHost.setOwnerUserId(userId); + monitorHost.setOwnerUsername(host.getCreator()); + } + monitorHostDAO.insert(monitorHost); + } else { + // 更新数据 + MonitorHostDO update = new MonitorHostDO(); + update.setId(monitorHost.getId()); + update.setMonitorMeta(JSON.toJSONString(meta)); + // 设置默认配置 + if (Strings.isBlank(monitorHost.getMonitorConfig())) { + newConfig = this.getDefaultMonitorConfig(meta); + update.setMonitorConfig(JSON.toJSONString(newConfig)); + } + monitorHostDAO.updateById(update); + } + // 设置配置缓存 + if (newConfig != null) { + monitorContext.setMonitorHostConfig(agentKey, newConfig); + } + }; + // 获取锁并执行同步逻辑 + LockerUtils.lockExecute(LOCK_KEY_PREFIX + agentKey, Const.MS_S_10, exec); + } + + /** + * 获取默认监控配置 + * + * @param meta meta + * @return config + */ + private MonitorHostConfigDTO getDefaultMonitorConfig(HostMetaDTO meta) { + return MonitorHostConfigDTO.builder() + .cpuName(Lists.first(meta.getCpus())) + .diskName(Lists.first(meta.getDisks())) + .networkName(Lists.first(meta.getNets())) + .build(); + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/impl/MonitorHostServiceImpl.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/impl/MonitorHostServiceImpl.java new file mode 100644 index 00000000..a87abc60 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/impl/MonitorHostServiceImpl.java @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.service.impl; + +import cn.orionsec.kit.lang.define.wrapper.DataGrid; +import cn.orionsec.kit.lang.function.Functions; +import cn.orionsec.kit.lang.utils.Objects1; +import cn.orionsec.kit.lang.utils.Strings; +import cn.orionsec.kit.lang.utils.collect.Lists; +import cn.orionsec.kit.lang.utils.collect.Maps; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.common.constant.Const; +import org.dromara.visor.common.constant.ErrorMessage; +import org.dromara.visor.common.constant.ExtraFieldConst; +import org.dromara.visor.common.entity.chart.TimeChartSeries; +import org.dromara.visor.common.utils.Valid; +import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs; +import org.dromara.visor.framework.influxdb.core.query.FluxQueryBuilder; +import org.dromara.visor.framework.influxdb.core.utils.InfluxdbUtils; +import org.dromara.visor.module.asset.api.HostAgentApi; +import org.dromara.visor.module.asset.api.HostApi; +import org.dromara.visor.module.asset.entity.dto.host.HostAgentLogDTO; +import org.dromara.visor.module.asset.entity.dto.host.HostDTO; +import org.dromara.visor.module.asset.entity.dto.host.HostQueryDTO; +import org.dromara.visor.module.asset.enums.AgentOnlineStatusEnum; +import org.dromara.visor.module.infra.api.SystemUserApi; +import org.dromara.visor.module.monitor.constant.MetricsConst; +import org.dromara.visor.module.monitor.convert.MonitorHostConvert; +import org.dromara.visor.module.monitor.dao.MonitorHostDAO; +import org.dromara.visor.module.monitor.define.context.MonitorContext; +import org.dromara.visor.module.monitor.entity.domain.MonitorHostDO; +import org.dromara.visor.module.monitor.entity.dto.MetricsDTO; +import org.dromara.visor.module.monitor.entity.dto.MetricsDataDTO; +import org.dromara.visor.module.monitor.entity.dto.MonitorHostConfigDTO; +import org.dromara.visor.module.monitor.entity.dto.MonitorHostMetaDTO; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostChartRequest; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostQueryRequest; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostSwitchUpdateRequest; +import org.dromara.visor.module.monitor.entity.request.host.MonitorHostUpdateRequest; +import org.dromara.visor.module.monitor.entity.vo.MonitorHostMetricsDataVO; +import org.dromara.visor.module.monitor.entity.vo.MonitorHostVO; +import org.dromara.visor.module.monitor.enums.MeasurementFieldEnum; +import org.dromara.visor.module.monitor.enums.MonitorAlarmSwitchEnum; +import org.dromara.visor.module.monitor.service.MonitorHostService; +import org.dromara.visor.module.monitor.service.MonitorMetricsService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.*; +import java.util.function.BiFunction; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 监控主机 服务实现类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-14 16:27 + */ +@Slf4j +@Service +public class MonitorHostServiceImpl implements MonitorHostService { + + @Resource + private MonitorHostDAO monitorHostDAO; + + @Resource + private HostApi hostApi; + + @Resource + private HostAgentApi hostAgentApi; + + @Resource + private SystemUserApi systemUserApi; + + @Resource + private MonitorMetricsService monitorMetricsService; + + @Resource + private MonitorContext monitorContext; + + @Override + public DataGrid getMonitorHostPage(MonitorHostQueryRequest request) { + // 转换查询条件 + HostQueryDTO hostQuery = MonitorHostConvert.MAPPER.toHostQuery(request); + hostQuery.setQueryTag(true); + hostQuery.setOrderByAgent(true); + List monitorHosts = null; + // 查询监控主机数据 + Integer alarmSwitch = request.getAlarmSwitch(); + Long ownerUserId = request.getOwnerUserId(); + Long policyId = request.getPolicyId(); + if (!Objects1.isAllNull(alarmSwitch, ownerUserId, policyId)) { + monitorHosts = monitorHostDAO.of() + .createValidateWrapper() + .eq(MonitorHostDO::getAlarmSwitch, alarmSwitch) + .eq(MonitorHostDO::getOwnerUserId, ownerUserId) + .eq(MonitorHostDO::getPolicyId, policyId) + .then() + .list(); + if (monitorHosts.isEmpty()) { + return new DataGrid<>(); + } + hostQuery.setIdList(Lists.map(monitorHosts, MonitorHostDO::getHostId)); + } + // 查询主机 + DataGrid hosts = hostApi.getHostPage(hostQuery); + if (hosts.isEmpty()) { + return new DataGrid<>(Lists.empty(), hosts.getTotal()); + } + List hostIdList = hosts.stream() + .map(HostDTO::getId) + .collect(Collectors.toList()); + // 若未查询过监控主机表则查询 + if (monitorHosts == null) { + monitorHosts = monitorHostDAO.selectByHostIdList(hostIdList); + } + Map monitorHostMap = monitorHosts.stream() + .collect(Collectors.toMap(MonitorHostDO::getHostId, + Function.identity(), + Functions.right())); + // TODO 查询策略名称 + + // 查询安装日志 + Map agentInstallLogMap = hostAgentApi.selectAgentInstallLog(hostIdList) + .stream() + .collect(Collectors.toMap(HostAgentLogDTO::getHostId, + Function.identity(), + Functions.right())); + String latestVersion = hostAgentApi.getAgentVersion(); + // 给主机进行赋值 + return hosts.map(s -> { + MonitorHostVO vo = MonitorHostConvert.MAPPER.to(s); + // 设置监控信息 + MonitorHostDO monitorHost = monitorHostMap.get(s.getId()); + if (monitorHost != null) { + vo.setId(monitorHost.getId()); + vo.setPolicyId(monitorHost.getPolicyId()); + vo.setAlarmSwitch(monitorHost.getAlarmSwitch()); + vo.setOwnerUserId(monitorHost.getOwnerUserId()); + vo.setOwnerUsername(monitorHost.getOwnerUsername()); + // 反序列化元数据 + vo.setMeta(JSON.parseObject(monitorHost.getMonitorMeta(), MonitorHostMetaDTO.class)); + // 反序列化配置 + vo.setConfig(JSON.parseObject(monitorHost.getMonitorConfig(), MonitorHostConfigDTO.class)); + } + // 设置安装日志 + vo.setInstallLog(agentInstallLogMap.get(s.getId())); + // 设置最新版本 + vo.setLatestVersion(latestVersion); + // 设置指标信息 + if (AgentOnlineStatusEnum.ONLINE.getValue().equals(vo.getAgentOnlineStatus())) { + vo.setMetricsData(this.getHostMetricsData(vo.getAgentKey(), vo.getConfig())); + } else { + vo.setMetricsData(MonitorHostMetricsDataVO.noData(vo.getAgentKey())); + } + return vo; + }); + } + + @Override + public List getMonitorHostMetrics(List agentKeyList) { + return agentKeyList.stream() + .map(s -> this.getHostMetricsData(s, null)) + .collect(Collectors.toList()); + } + + @Override + public List getMonitorHostChart(MonitorHostChartRequest request) { + List agentKeys = request.getAgentKeys(); + List fields = request.getFields(); + List seriesList = this.getChartSeries(request); + // 查询 agentKey 对应的名称 + Map cacheNameByAgentKey = hostAgentApi.getCacheNameByAgentKey(agentKeys); + // 封装数据 + for (TimeChartSeries series : seriesList) { + Map tags = series.getTags(); + Map sortedTags = new LinkedHashMap<>(); + String key = (String) tags.get(Const.KEY); + String field = monitorMetricsService.getMetricName((String) tags.get(Const.FIELD)); + tags.remove(Const.KEY); + tags.remove(Const.FIELD); + // 设置主机名称 + if (agentKeys.size() > 1) { + sortedTags.put(ExtraFieldConst.HOST_NAME, cacheNameByAgentKey.get(key)); + } + // 设置字段 + if (fields.size() > 1) { + sortedTags.put(ExtraFieldConst.FIELD, field); + } + sortedTags.putAll(tags); + // 为空需要添加 field (计算名称) + if (sortedTags.isEmpty()) { + sortedTags.put(ExtraFieldConst.FIELD, field); + } + series.setTags(sortedTags); + // 设置名称 + String name = sortedTags.values() + .stream() + .map(Objects::toString) + .collect(Collectors.joining("-")); + series.setName(name); + } + // 排序指标 + seriesList.sort(Comparator.comparing(TimeChartSeries::getName)); + return seriesList; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Integer updateMonitorHostById(MonitorHostUpdateRequest request) { + Long id = Valid.notNull(request.getId(), ErrorMessage.ID_MISSING); + Long policyId = request.getPolicyId(); + log.info("MonitorHostService-updateMonitorHostById id: {}, request: {}", id, JSON.toJSONString(request)); + // 查询数据 + MonitorHostDO monitorHost = monitorHostDAO.selectById(id); + Valid.notNull(monitorHost, ErrorMessage.DATA_ABSENT); + // 查询主机信息 + HostDTO host = hostApi.selectById(monitorHost.getHostId()); + Valid.notNull(host, ErrorMessage.HOST_ABSENT); + // 查询用户信息 + Optional.ofNullable(request.getOwnerUserId()) + .map(systemUserApi::getUsernameById) + .ifPresent(request::setOwnerUsername); + // 设置日志参数 + OperatorLogs.add(OperatorLogs.NAME, host.getName()); + // 查询策略是否存在 TODO + if (policyId != null) { + + } + // 转换 + MonitorHostDO updateRecord = MonitorHostConvert.MAPPER.to(request); + // 配置信息 + MonitorHostConfigDTO config = MonitorHostConfigDTO.builder() + .cpuName(request.getCpuName()) + .diskName(request.getDiskName()) + .networkName(request.getNetworkName()) + .build(); + updateRecord.setMonitorConfig(JSON.toJSONString(config)); + // 更新 + int effect = monitorHostDAO.updateById(updateRecord); + // 更新缓存 + monitorContext.setMonitorHostConfig(host.getAgentKey(), config); + log.info("MonitorHostService-updateMonitorHostById effect: {}", effect); + return effect; + } + + @Override + public Integer updateMonitorHostAlarmSwitch(MonitorHostSwitchUpdateRequest request) { + Long id = request.getId(); + MonitorAlarmSwitchEnum alarmSwitch = MonitorAlarmSwitchEnum.of(request.getAlarmSwitch()); + // 查询数据 + MonitorHostDO monitorHost = monitorHostDAO.selectById(id); + Valid.notNull(monitorHost, ErrorMessage.DATA_ABSENT); + // 查询主机信息 + HostDTO host = hostApi.selectById(monitorHost.getHostId()); + Valid.notNull(host, ErrorMessage.HOST_ABSENT); + // 设置日志参数 + OperatorLogs.add(OperatorLogs.NAME, host.getName()); + OperatorLogs.add(OperatorLogs.SWITCH, alarmSwitch.name()); + // 修改数据 + MonitorHostDO update = new MonitorHostDO(); + update.setId(id); + update.setAlarmSwitch(alarmSwitch.getValue()); + int effect = monitorHostDAO.updateById(update); + log.info("MonitorHostService-updateMonitorHostAlarmSwitch effect: {}", effect); + // todo 咋更新缓存 + return effect; + } + + /** + * 查询数据图表 + * + * @param request request + * @return values + */ + private List getChartSeries(MonitorHostChartRequest request) { + String measurement = request.getMeasurement(); + List agentKeys = request.getAgentKeys(); + List fields = request.getFields(); + // 获取配置信息 + List configList = agentKeys.stream() + .map(monitorContext::getMonitorHostConfig) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + // 查询主机信息 + FluxQueryBuilder query = InfluxdbUtils.query(); + // 设置时间 + String range = request.getRange(); + if (range != null) { + query.range(range); + } else { + Valid.notNull(request.getStart(), ErrorMessage.PARAM_MISSING); + Valid.notNull(request.getEnd(), ErrorMessage.PARAM_MISSING); + } + // 设置名称 + Set names = null; + if (MeasurementFieldEnum.CPU.getMeasurement().equals(measurement)) { + names = configList.stream() + .map(MonitorHostConfigDTO::getCpuName) + .collect(Collectors.toSet()); + } else if (MeasurementFieldEnum.DISK.getMeasurement().equals(measurement)) { + names = configList.stream() + .map(MonitorHostConfigDTO::getDiskName) + .collect(Collectors.toSet()); + } else if (MeasurementFieldEnum.NETWORK.getMeasurement().equals(measurement)) { + names = configList.stream() + .map(MonitorHostConfigDTO::getNetworkName) + .collect(Collectors.toSet()); + } + if (!Lists.isEmpty(names)) { + query.name(names); + } + // 设置其他查询条件 + String flux = query.measurement(measurement) + .key(agentKeys) + .fields(fields) + .aggregateWindow(request.getWindow(), request.getAggregate(), true) + .pretty() + .build(); + // 查询数据 + return InfluxdbUtils.querySeries(flux); + } + + /** + * 获取主机指标数据 + * + * @param agentKey agentKey + * @param config config + * @return data + */ + public MonitorHostMetricsDataVO getHostMetricsData(String agentKey, MonitorHostConfigDTO config) { + MetricsDataDTO metrics = monitorContext.getAgentMetrics(agentKey); + // 无数据 + if (metrics == null) { + return MonitorHostMetricsDataVO.noData(agentKey); + } + // 从缓存中获取配置 + if (config == null) { + config = monitorContext.getMonitorHostConfig(agentKey); + } + // 获取名称 + LinkedHashMap metricDefaultNameMap = metrics.getMetrics() + .stream() + .collect(Collectors.toMap( + MetricsDTO::getType, + s -> Strings.def(Maps.get(s.getTags(), Const.NAME)), + Functions.left(), + LinkedHashMap::new)); + String cpuName = Optional.ofNullable(config) + .map(MonitorHostConfigDTO::getCpuName) + .orElse(metricDefaultNameMap.get(MeasurementFieldEnum.CPU.getMeasurement())); + String diskName = Optional.ofNullable(config) + .map(MonitorHostConfigDTO::getDiskName) + .orElse(metricDefaultNameMap.get(MeasurementFieldEnum.DISK.getMeasurement())); + String networkName = Optional.ofNullable(config) + .map(MonitorHostConfigDTO::getNetworkName) + .orElse(metricDefaultNameMap.get(MeasurementFieldEnum.NETWORK.getMeasurement())); + // 指标缓存 + Map metricTypeMap = metrics.getMetrics() + .stream() + .collect(Collectors.toMap( + s -> s.getType() + "_" + Strings.def(Maps.get(s.getTags(), Const.NAME)), + MetricsDTO::getValues, + Functions.right(), + LinkedHashMap::new)); + MonitorHostMetricsDataVO data = MonitorHostMetricsDataVO.builder() + .noData(false) + .agentKey(agentKey) + .cpuName(cpuName) + .diskName(diskName) + .networkName(networkName) + .timestamp(metrics.getTimestamp()) + .build(); + // 组装指标 + this.setNamedMetricValue(metricTypeMap, MeasurementFieldEnum.CPU, + cpuName, MetricsConst.CPU_TOTAL_SECONDS_TOTAL, 0D, + JSONObject::getDouble, + data::setCpuUsagePercent); + this.setNamedMetricValue(metricTypeMap, MeasurementFieldEnum.MEMORY, + null, MetricsConst.MEM_USED_BYTES_TOTAL, 0L, + JSONObject::getLong, + data::setMemoryUsageBytes); + this.setNamedMetricValue(metricTypeMap, MeasurementFieldEnum.MEMORY, + null, MetricsConst.MEM_USED_PERCENT, 0D, + JSONObject::getDouble, + data::setMemoryUsagePercent); + this.setNamedMetricValue(metricTypeMap, MeasurementFieldEnum.LOAD, + null, MetricsConst.LOAD1, 0D, + JSONObject::getDouble, + data::setLoad1); + this.setNamedMetricValue(metricTypeMap, MeasurementFieldEnum.LOAD, + null, MetricsConst.LOAD5, 0D, + JSONObject::getDouble, + data::setLoad5); + this.setNamedMetricValue(metricTypeMap, MeasurementFieldEnum.LOAD, + null, MetricsConst.LOAD15, 0D, + JSONObject::getDouble, + data::setLoad15); + this.setNamedMetricValue(metricTypeMap, MeasurementFieldEnum.DISK, + diskName, MetricsConst.DISK_FS_USED_PERCENT, 0D, + JSONObject::getDouble, + data::setDiskUsagePercent); + this.setNamedMetricValue(metricTypeMap, MeasurementFieldEnum.DISK, + diskName, MetricsConst.DISK_FS_USED_BYTES_TOTAL, 0L, + JSONObject::getLong, + data::setDiskUsageBytes); + this.setNamedMetricValue(metricTypeMap, MeasurementFieldEnum.NETWORK, + networkName, MetricsConst.NET_SENT_BYTES_PER_SECOND, 0D, + JSONObject::getDouble, + data::setNetworkSentPreBytes); + this.setNamedMetricValue(metricTypeMap, MeasurementFieldEnum.NETWORK, + networkName, MetricsConst.NET_RECV_BYTES_PER_SECOND, 0D, + JSONObject::getDouble, + data::setNetworkRecvPreBytes); + return data; + } + + /** + * 设置指标值 + * + * @param metricTypeMap metricTypeMap + * @param type type + * @param name name + * @param field field + * @param defaultValue defaultValue + * @param getter getter + * @param setter setter + * @param T + */ + private void setNamedMetricValue(Map metricTypeMap, + MeasurementFieldEnum type, + String name, + String field, + T defaultValue, + BiFunction getter, + Consumer setter) { + // 获取值 + T value = Optional.of(type.getMeasurement() + "_" + Strings.def(name)) + .map(metricTypeMap::get) + .map(s -> getter.apply(s, field)) + .orElse(defaultValue); + // 设置值 + setter.accept(value); + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/impl/MonitorMetricsServiceImpl.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/impl/MonitorMetricsServiceImpl.java new file mode 100644 index 00000000..afc9de26 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/service/impl/MonitorMetricsServiceImpl.java @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.service.impl; + +import cn.orionsec.kit.lang.define.wrapper.DataGrid; +import cn.orionsec.kit.lang.utils.collect.Lists; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.extern.slf4j.Slf4j; +import org.dromara.visor.common.constant.Const; +import org.dromara.visor.common.constant.ErrorMessage; +import org.dromara.visor.common.utils.Valid; +import org.dromara.visor.framework.biz.operator.log.core.utils.OperatorLogs; +import org.dromara.visor.framework.redis.core.utils.RedisMaps; +import org.dromara.visor.framework.redis.core.utils.barrier.CacheBarriers; +import org.dromara.visor.module.monitor.convert.MonitorMetricsConvert; +import org.dromara.visor.module.monitor.dao.MonitorMetricsDAO; +import org.dromara.visor.module.monitor.define.cache.MonitorMetricsCacheKeyDefine; +import org.dromara.visor.module.monitor.entity.domain.MonitorMetricsDO; +import org.dromara.visor.module.monitor.entity.dto.MonitorMetricsCacheDTO; +import org.dromara.visor.module.monitor.entity.request.metrics.MonitorMetricsCreateRequest; +import org.dromara.visor.module.monitor.entity.request.metrics.MonitorMetricsQueryRequest; +import org.dromara.visor.module.monitor.entity.request.metrics.MonitorMetricsUpdateRequest; +import org.dromara.visor.module.monitor.entity.vo.MonitorMetricsVO; +import org.dromara.visor.module.monitor.service.MonitorMetricsService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 监控指标 服务实现类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025-8-12 21:31 + */ +@Slf4j +@Service +public class MonitorMetricsServiceImpl implements MonitorMetricsService { + + private final Map metricsNameMap = new HashMap<>(); + + @Resource + private MonitorMetricsDAO monitorMetricsDAO; + + @PostConstruct + public void init() { + // 加载指标名称关联 + List metricsList = monitorMetricsDAO.selectList(null); + for (MonitorMetricsDO metrics : metricsList) { + metricsNameMap.put(metrics.getValue(), metrics.getName()); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createMonitorMetrics(MonitorMetricsCreateRequest request) { + log.info("MonitorMetricsService-createMonitorMetrics request: {}", JSON.toJSONString(request)); + // 转换 + MonitorMetricsDO record = MonitorMetricsConvert.MAPPER.to(request); + // 查询数据是否冲突 + this.checkMonitorMetricsPresent(record); + // 插入 + int effect = monitorMetricsDAO.insert(record); + Long id = record.getId(); + // 删除缓存 + RedisMaps.delete(MonitorMetricsCacheKeyDefine.MONITOR_METRICS); + // 设置日志参数 + OperatorLogs.add(OperatorLogs.ID, id); + // 修改本地缓存 + metricsNameMap.remove(record.getValue()); + metricsNameMap.put(request.getValue(), request.getName()); + log.info("MonitorMetricsService-createMonitorMetrics id: {}, effect: {}", id, effect); + return id; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Integer updateMonitorMetricsById(MonitorMetricsUpdateRequest request) { + Long id = Valid.notNull(request.getId(), ErrorMessage.ID_MISSING); + log.info("MonitorMetricsService-updateMonitorMetricsById id: {}, request: {}", id, JSON.toJSONString(request)); + // 查询 + MonitorMetricsDO record = monitorMetricsDAO.selectById(id); + Valid.notNull(record, ErrorMessage.DATA_ABSENT); + // 转换 + MonitorMetricsDO updateRecord = MonitorMetricsConvert.MAPPER.to(request); + // 查询数据是否冲突 + this.checkMonitorMetricsPresent(updateRecord); + // 更新 + int effect = monitorMetricsDAO.updateById(updateRecord); + log.info("MonitorMetricsService-updateMonitorMetricsById effect: {}", effect); + // 删除缓存 + RedisMaps.delete(MonitorMetricsCacheKeyDefine.MONITOR_METRICS); + // 修改本地缓存 + metricsNameMap.put(request.getValue(), request.getName()); + return effect; + } + + @Override + public List getMonitorMetricsList() { + // 查询缓存 + List list = RedisMaps.valuesJson(MonitorMetricsCacheKeyDefine.MONITOR_METRICS); + if (list.isEmpty()) { + // 查询数据库 + list = monitorMetricsDAO.of().list(MonitorMetricsConvert.MAPPER::toCache); + // 设置屏障 防止穿透 + CacheBarriers.checkBarrier(list, MonitorMetricsCacheDTO::new); + // 设置缓存 + RedisMaps.putAllJson(MonitorMetricsCacheKeyDefine.MONITOR_METRICS, s -> s.getId().toString(), list); + } + // 删除屏障 + CacheBarriers.removeBarrier(list); + // 转换 + return list.stream() + .map(MonitorMetricsConvert.MAPPER::to) + .sorted(Comparator.comparing(MonitorMetricsVO::getId).reversed()) + .collect(Collectors.toList()); + } + + @Override + public DataGrid getMonitorMetricsPage(MonitorMetricsQueryRequest request) { + // 条件 + LambdaQueryWrapper wrapper = this.buildQueryWrapper(request); + // 查询 + return monitorMetricsDAO.of() + .wrapper(wrapper) + .page(request) + .order(request, MonitorMetricsDO::getId) + .dataGrid(MonitorMetricsConvert.MAPPER::to); + } + + @Override + public String getMetricName(String value) { + return metricsNameMap.getOrDefault(value, value); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Integer deleteMonitorMetricsById(Long id) { + log.info("MonitorMetricsService-deleteMonitorMetricsById id: {}", id); + // 检查数据是否存在 + MonitorMetricsDO record = monitorMetricsDAO.selectById(id); + Valid.notNull(record, ErrorMessage.DATA_ABSENT); + // 删除 + int effect = monitorMetricsDAO.deleteById(id); + // 删除缓存 + RedisMaps.delete(MonitorMetricsCacheKeyDefine.MONITOR_METRICS, id); + // 设置日志参数 + OperatorLogs.add(OperatorLogs.COUNT, effect); + log.info("MonitorMetricsService-deleteMonitorMetricsById id: {}, effect: {}", id, effect); + return effect; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public Integer deleteMonitorMetricsByIdList(List idList) { + if (Lists.isEmpty(idList)) { + OperatorLogs.add(OperatorLogs.COUNT, Const.N_0); + return Const.N_0; + } + log.info("MonitorMetricsService-deleteMonitorMetricsByIdList idList: {}", idList); + int effect = monitorMetricsDAO.deleteBatchIds(idList); + // 删除缓存 + RedisMaps.delete(MonitorMetricsCacheKeyDefine.MONITOR_METRICS, idList); + // 设置日志参数 + OperatorLogs.add(OperatorLogs.COUNT, effect); + log.info("MonitorMetricsService-deleteMonitorMetricsByIdList effect: {}", effect); + return effect; + } + + @Override + public LambdaQueryWrapper buildQueryWrapper(MonitorMetricsQueryRequest request) { + return monitorMetricsDAO.wrapper() + .eq(MonitorMetricsDO::getName, request.getName()) + .eq(MonitorMetricsDO::getMeasurement, request.getMeasurement()) + .eq(MonitorMetricsDO::getValue, request.getValue()) + .eq(MonitorMetricsDO::getDescription, request.getDescription()); + } + + /** + * 检查对象是否存在 + * + * @param domain domain + */ + private void checkMonitorMetricsPresent(MonitorMetricsDO domain) { + // 构造条件 + LambdaQueryWrapper wrapper = monitorMetricsDAO.wrapper() + // 更新时忽略当前记录 + .ne(MonitorMetricsDO::getId, domain.getId()) + // 用其他字段做重复校验 + .eq(MonitorMetricsDO::getName, domain.getName()) + .eq(MonitorMetricsDO::getMeasurement, domain.getMeasurement()) + .eq(MonitorMetricsDO::getValue, domain.getValue()); + // 检查是否存在 + boolean present = monitorMetricsDAO.of(wrapper).present(); + Valid.isFalse(present, ErrorMessage.DATA_PRESENT); + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/utils/MetricsUtils.java b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/utils/MetricsUtils.java new file mode 100644 index 00000000..419b3286 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/java/org/dromara/visor/module/monitor/utils/MetricsUtils.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 - present Dromara, All rights reserved. + * + * https://visor.dromara.org + * https://visor.dromara.org.cn + * https://visor.orionsec.cn + * + * Members: + * Jiahang Li - ljh1553488six@139.com - author + * + * 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.dromara.visor.module.monitor.utils; + +import cn.orionsec.kit.lang.utils.Strings; +import com.alibaba.fastjson.JSONObject; +import com.influxdb.client.write.Point; +import org.dromara.visor.module.monitor.enums.MeasurementFieldEnum; + +/** + * 指标值工具类 + * + * @author Jiahang Li + * @version 1.0.0 + * @since 2025/8/11 22:46 + */ +public class MetricsUtils { + + private MetricsUtils() { + } + + /** + * 设置值 + * + * @param type type + * @param values values + * @return point + */ + public static Point createPoint(String type, JSONObject values) { + // 创建数据点 + Point point = Point.measurement(type); + // 设置数据值 + for (String field : values.keySet()) { + // 数据类型 + Class dataType = MeasurementFieldEnum.getMetricsValueType(type, field); + if (dataType == null) { + continue; + } + // 过滤数据 + String str = values.getString(field); + if (Strings.isBlank(str)) { + continue; + } + // 转换数据类型 + if (dataType == byte.class || dataType == short.class || dataType == int.class || dataType == long.class) { + point.addField(field, values.getLongValue(field)); + } else if (dataType == float.class || dataType == double.class) { + point.addField(field, values.getDoubleValue(field)); + } else if (dataType == boolean.class) { + point.addField(field, values.getBoolean(field)); + } else if (dataType == String.class) { + point.addField(field, values.getString(field)); + } + } + return point; + } + +} diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/resources/mapper/MonitorHostMapper.xml b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/resources/mapper/MonitorHostMapper.xml new file mode 100644 index 00000000..eb7c0d19 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/resources/mapper/MonitorHostMapper.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + id, host_id, policy_id, agent_key, alarm_switch, owner_user_id, owner_username, monitor_meta, monitor_config, create_time, update_time, creator, updater, deleted + + + diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/resources/mapper/MonitorMetricsMapper.xml b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/resources/mapper/MonitorMetricsMapper.xml new file mode 100644 index 00000000..84e4f020 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/main/resources/mapper/MonitorMetricsMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + id, name, measurement, value, unit, suffix, description, id, create_time, update_time, creator, updater, deleted + + + diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/test/java/org/dromara/visor/module/monitor/api/impl/.gitkeep b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/test/java/org/dromara/visor/module/monitor/api/impl/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/test/java/org/dromara/visor/module/monitor/service/impl/.gitkeep b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/test/java/org/dromara/visor/module/monitor/service/impl/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/test/resources/application-unit-test.yaml b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/test/resources/application-unit-test.yaml new file mode 100644 index 00000000..f349f31e --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/test/resources/application-unit-test.yaml @@ -0,0 +1,30 @@ +spring: + main: + lazy-initialization: true + banner-mode: OFF + datasource: + druid: + name: orion_visor + url: jdbc:h2:mem:memdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; + driver-class-name: org.h2.Driver + username: sa + password: + max-active: 1 + async-init: true + initial-size: 1 + test-while-idle: false + sql: + init: + schema-locations: + - classpath:/sql/create-table-h2-*.sql + redis: + host: 127.0.0.1 + port: 16379 + database: 0 + redisson: + threads: 2 + netty-threads: 2 + minimum-idle-size: 2 + +mybatis-plus: + lazy-initialization: true diff --git a/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/test/resources/sql/.gitkeep b/orion-visor-modules/orion-visor-module-monitor/orion-visor-module-monitor-service/src/test/resources/sql/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/orion-visor-modules/orion-visor-module-monitor/pom.xml b/orion-visor-modules/orion-visor-module-monitor/pom.xml new file mode 100644 index 00000000..d0effa82 --- /dev/null +++ b/orion-visor-modules/orion-visor-module-monitor/pom.xml @@ -0,0 +1,23 @@ + + + + org.dromara.visor + orion-visor-modules + ${revision} + + + 4.0.0 + orion-visor-module-monitor + pom + + 项目监控模块 + https://github.com/dromara/orion-visor + + + orion-visor-module-monitor-provider + orion-visor-module-monitor-service + + + \ No newline at end of file diff --git a/orion-visor-modules/pom.xml b/orion-visor-modules/pom.xml index a9e26967..191903fe 100644 --- a/orion-visor-modules/pom.xml +++ b/orion-visor-modules/pom.xml @@ -21,6 +21,7 @@ orion-visor-module-asset orion-visor-module-exec orion-visor-module-terminal + orion-visor-module-monitor \ No newline at end of file diff --git a/orion-visor-ui/src/api/asset/host-agent.ts b/orion-visor-ui/src/api/asset/host-agent.ts new file mode 100644 index 00000000..d07c658d --- /dev/null +++ b/orion-visor-ui/src/api/asset/host-agent.ts @@ -0,0 +1,102 @@ +import axios from 'axios'; +import qs from 'query-string'; + +/** + * 主机探针状态 + */ +export interface HostAgentStatusResponse { + id: number; + agentVersion: string; + latestVersion: string; + agentInstallStatus: number; + agentOnlineStatus: number; +} + +/** + * 探针日志 + */ +export interface HostAgentLogResponse { + id: number; + hostId: number; + agentKey: string; + type: string; + status: string; + message: string; + createTime: number; + updateTime: number; + creator: string; + updater: string; + agentStatus: HostAgentStatusResponse; +} + +/** + * 安装探针请求 + */ +export interface HostInstallAgentRequest { + idList?: Array; +} + +/** + * 主机安装探针更新状态请求 + */ +export interface HostAgentInstallStatusUpdateRequest { + id?: number; + status?: string; + message?: string; +} + +/** + * 安装主机探针 + */ +export function installHostAgent(request: HostInstallAgentRequest) { + return axios.post('/asset/host-agent/install', request); +} + +/** + * 修改探针安装状态 + */ +export function updateAgentInstallStatus(request: HostAgentInstallStatusUpdateRequest) { + return axios.put('/asset/host-agent/update-install-status', request); +} + +/** + * 查询主机探针状态 + */ +export function getHostAgentStatus(idList: Array) { + return axios.get>('/asset/host-agent/status', { + params: { idList }, + promptBizErrorMessage: false, + promptRequestErrorMessage: false, + paramsSerializer: params => { + return qs.stringify(params, { arrayFormat: 'comma' }); + } + }); +} + +/** + * 查询探针安装状态 + */ +export function getAgentInstallLogStatus(idList: Array) { + return axios.get>('/asset/host-agent/install-status', { + params: { idList }, + promptBizErrorMessage: false, + promptRequestErrorMessage: false, + paramsSerializer: params => { + return qs.stringify(params, { arrayFormat: 'comma' }); + } + }); +} + +/** + * 上传探针发布包 + */ +export function uploadAgentRelease(file: File) { + const formData = new FormData(); + formData.append('file', file); + return axios.post('/asset/host-agent/upload-agent-release', formData, { + timeout: 120000, + headers: { + 'Content-Type': 'multipart/form-data' + }, + }); +} diff --git a/orion-visor-ui/src/api/asset/host-config.ts b/orion-visor-ui/src/api/asset/host-config.ts index 281d34a0..1de7a426 100644 --- a/orion-visor-ui/src/api/asset/host-config.ts +++ b/orion-visor-ui/src/api/asset/host-config.ts @@ -56,7 +56,6 @@ export interface HostVncConfig extends HostBaseConfig { identityId?: number; noUsername?: boolean; noPassword?: boolean; - portForwardId?: number; timezone?: string; clipboardEncoding?: string; } diff --git a/orion-visor-ui/src/api/asset/host-extra.ts b/orion-visor-ui/src/api/asset/host-extra.ts index ca235c83..c77a90d0 100644 --- a/orion-visor-ui/src/api/asset/host-extra.ts +++ b/orion-visor-ui/src/api/asset/host-extra.ts @@ -61,7 +61,7 @@ export interface HostSpecExtraModel { outBandwidth: number; publicIpAddresses: Array; privateIpAddresses: Array; - chargePerson: string; + ownerPerson: string; createdTime: number; expiredTime: number; items: Array<{ diff --git a/orion-visor-ui/src/api/asset/host.ts b/orion-visor-ui/src/api/asset/host.ts index a01dd48e..4da9acfb 100644 --- a/orion-visor-ui/src/api/asset/host.ts +++ b/orion-visor-ui/src/api/asset/host.ts @@ -69,6 +69,11 @@ export interface HostQueryBaseResponse { code: string; address: string; status: string; + agentKey: string; + agentVersion: string; + agentInstallStatus: number; + agentOnlineStatus: number; + agentOnlineChangeTime: number; description: string; createTime: number; updateTime: number; @@ -143,8 +148,8 @@ export function updateHostSpec(request: Partial) { /** * 查询主机 */ -export function getHost(id: number) { - return axios.get('/asset/host/get', { params: { id } }); +export function getHost(id: number, base = false) { + return axios.get('/asset/host/get', { params: { id, base } }); } /** diff --git a/orion-visor-ui/src/api/interceptor.ts b/orion-visor-ui/src/api/interceptor.ts index 2bf14d34..a2b6b146 100644 --- a/orion-visor-ui/src/api/interceptor.ts +++ b/orion-visor-ui/src/api/interceptor.ts @@ -6,7 +6,7 @@ import { getToken } from '@/utils/auth'; import { httpBaseUrl } from '@/utils/env'; import { reLoginTipsKey } from '@/types/symbol'; -axios.defaults.timeout = 10000; +axios.defaults.timeout = 15000; axios.defaults.setAuthorization = true; axios.defaults.promptBizErrorMessage = true; axios.defaults.promptRequestErrorMessage = true; diff --git a/orion-visor-ui/src/api/monitor/metrics.ts b/orion-visor-ui/src/api/monitor/metrics.ts new file mode 100644 index 00000000..1d5437d3 --- /dev/null +++ b/orion-visor-ui/src/api/monitor/metrics.ts @@ -0,0 +1,95 @@ +import type { TableData } from '@arco-design/web-vue'; +import type { DataGrid, OrderDirection, Pagination } from '@/types/global'; +import axios from 'axios'; + +/** + * 监控指标创建请求 + */ +export interface MetricsCreateRequest { + name?: string; + measurement?: string; + value?: string; + unit?: string; + suffix?: string; + description?: string; +} + +/** + * 监控指标更新请求 + */ +export interface MetricsUpdateRequest extends MetricsCreateRequest { + id?: number; +} + +/** + * 监控指标查询请求 + */ +export interface MetricsQueryRequest extends Pagination, OrderDirection { + searchValue?: string; + id?: number; + name?: string; + measurement?: string; + value?: string; + unit?: string; + suffix?: string; + description?: string; +} + +/** + * 监控指标查询响应 + */ +export interface MetricsQueryResponse extends TableData { + id: number; + name: string; + measurement: string; + value: string; + unit: string; + suffix: string; + description: string; + createTime: number; + updateTime: number; + creator: string; + updater: string; +} + +/** + * 创建监控指标 + */ +export function createMetrics(request: MetricsCreateRequest) { + return axios.post('/monitor/monitor-metrics/create', request); +} + +/** + * 更新监控指标 + */ +export function updateMetrics(request: MetricsUpdateRequest) { + return axios.put('/monitor/monitor-metrics/update', request); +} + +/** + * 查询监控指标 + */ +export function getMetrics(id: number) { + return axios.get('/monitor/monitor-metrics/get', { params: { id } }); +} + +/** + * 查询全部监控指标 + */ +export function getMetricsList() { + return axios.get>('/monitor/monitor-metrics/list'); +} + +/** + * 分页查询监控指标 + */ +export function getMetricsPage(request: MetricsQueryRequest) { + return axios.post>('/monitor/monitor-metrics/query', request); +} + +/** + * 删除监控指标 + */ +export function deleteMetrics(id: number) { + return axios.delete('/monitor/monitor-metrics/delete', { params: { id } }); +} diff --git a/orion-visor-ui/src/api/monitor/monitor-host.ts b/orion-visor-ui/src/api/monitor/monitor-host.ts new file mode 100644 index 00000000..34d62e3f --- /dev/null +++ b/orion-visor-ui/src/api/monitor/monitor-host.ts @@ -0,0 +1,168 @@ +import type { TableData } from '@arco-design/web-vue'; +import type { DataGrid, Pagination, TimeChartSeries } from '@/types/global'; +import type { HostAgentLogResponse } from '@/api/asset/host-agent'; +import axios from 'axios'; + +/** + * 监控主机更新请求 + */ +export interface MonitorHostUpdateRequest { + id?: number; + policyId?: number; + alarmSwitch?: number; + ownerUserId?: number; + cpuName?: string; + diskName?: string; + networkName?: string; +} + +/** + * 监控主机更新请求 + */ +export interface MonitorHostSwitchUpdateRequest { + id?: number; + alarmSwitch?: number; +} + +/** + * 监控主机查询请求 + */ +export interface MonitorHostQueryRequest extends Pagination { + agentKeyList?: Array; + searchValue?: string; + alarmSwitch?: number; + policyId?: number; + ownerUserId?: number; + name?: string; + code?: string; + address?: string; + agentKey?: string; + agentInstallStatus?: number; + agentOnlineStatus?: number; + description?: string; + tags?: Array; +} + +/** + * 监控主机图表查询请求 + */ +export interface MonitorHostChartRequest { + agentKeys?: Array; + measurement?: string; + fields?: Array; + window?: string; + aggregate?: string; + range?: string; + start?: string; + end?: string; +} + +/** + * 监控主机查询响应 + */ +export interface MonitorHostQueryResponse extends TableData { + id: number; + hostId: number; + policyId: number; + policyName: string; + osType: string; + name: string; + code: string; + address: string; + status: string; + agentKey: string; + agentVersion: string; + latestVersion: string; + agentInstallStatus: number; + agentOnlineStatus: number; + agentOnlineChangeTime: number; + alarmSwitch: number; + ownerUserId: number; + ownerUsername: string; + tags: Array<{ id: number, name: string }>; + meta: MonitorHostMeta; + config: MonitorHostConfig; + metricsData: MonitorHostMetricsData; + installLog: HostAgentLogResponse; +} + +/** + * 监控元数据 + */ +export interface MonitorHostMeta { + cpus: Array; + disks: Array; + nets: Array; + memoryBytes: number; +} + +/** + * 监控配置 + */ +export interface MonitorHostConfig { + cpuName: string; + diskName: string; + networkName: string; +} + +/** + * 监控数据 + */ +export interface MonitorHostMetricsData { + agentKey: string; + noData: boolean; + timestamp: number; + cpuName: string; + diskName: string; + networkName: string; + cpuUsagePercent: number; + memoryUsagePercent: number; + memoryUsageBytes: number; + load1: number; + load5: number; + load15: number; + diskUsagePercent: number; + diskUsageBytes: number; + networkSentPreBytes: number; + networkRecvPreBytes: number; +} + +/** + * 查询监控主机指标 + */ +export function getMonitorHostMetrics(agentKeyList: Array) { + return axios.post>('/monitor/monitor-host/metrics', { + agentKeyList + }, { + promptBizErrorMessage: false, + promptRequestErrorMessage: false, + }); +} + +/** + * 查询监控主机图表 + */ +export function getMonitorHostChart(request: MonitorHostChartRequest) { + return axios.post>('/monitor/monitor-host/chart', request); +} + +/** + * 分页查询监控主机 + */ +export function getMonitorHostPage(request: MonitorHostQueryRequest) { + return axios.post>('/monitor/monitor-host/query', request); +} + +/** + * 更新监控主机 + */ +export function updateMonitorHost(request: MonitorHostUpdateRequest) { + return axios.put('/monitor/monitor-host/update', request); +} + +/** + * 更新监控主机告警开关 + */ +export function updateMonitorHostAlarmSwitch(request: MonitorHostSwitchUpdateRequest) { + return axios.put('/monitor/monitor-host/update-switch', request); +} diff --git a/orion-visor-ui/src/api/terminal/terminal-sftp.ts b/orion-visor-ui/src/api/terminal/terminal-sftp.ts index 43f837fd..252de82e 100644 --- a/orion-visor-ui/src/api/terminal/terminal-sftp.ts +++ b/orion-visor-ui/src/api/terminal/terminal-sftp.ts @@ -20,7 +20,7 @@ export function setSftpFileContent(token: string, content: string) { formData.append('token', token); formData.append('file', new File([content], Date.now() + '', { type: 'text/plain' })); return axios.post('/terminal/terminal-sftp/set-content', formData, { - timeout: 60000, + timeout: 120000, headers: { 'Content-Type': 'multipart/form-data' } diff --git a/orion-visor-ui/src/assets/style/arco-extends.less b/orion-visor-ui/src/assets/style/arco-extends.less index 386470a9..2bdecfc7 100644 --- a/orion-visor-ui/src/assets/style/arco-extends.less +++ b/orion-visor-ui/src/assets/style/arco-extends.less @@ -31,19 +31,19 @@ background-color: rgb(var(--blue-6)); &.normal { - color: rgb(var(--arcoblue-6)); + background-color: rgb(var(--arcoblue-6)); } &.pass { - color: rgb(var(--green-6)); + background-color: rgb(var(--green-6)); } &.warn { - color: rgb(var(--orange-6)); + background-color: rgb(var(--orange-6)); } &.error { - color: rgb(var(--red-6)); + background-color: rgb(var(--red-6)); } } } diff --git a/orion-visor-ui/src/assets/style/chart.less b/orion-visor-ui/src/assets/style/chart.less new file mode 100644 index 00000000..844607a5 --- /dev/null +++ b/orion-visor-ui/src/assets/style/chart.less @@ -0,0 +1,49 @@ +// tooltip +.chart-tooltip-wrapper { + // 时间 + .chart-tooltip-time { + font-size: 13px; + } + + // 表头 + .chart-tooltip-header { + margin-top: 5px; + font-size: 12px; + line-height: 1.3; + + &-grid { + display: grid; + gap: 0 8px; + align-items: center; + } + + &-item { + font-weight: bold; + padding: 2px 0; + white-space: nowrap; + border-bottom: 1px solid #ddd; + } + } + + // 圆点 + .chart-tooltip-dot { + display: inline-block; + width: 8px; + height: 8px; + border-radius: 50%; + margin-right: 5px; + } + + // 数据行 + .chart-tooltip-col { + font-weight: 500; + color: #000; + padding: 3px 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: flex; + align-items: center; + } + +} diff --git a/orion-visor-ui/src/assets/style/global.less b/orion-visor-ui/src/assets/style/global.less index 105f2ba8..3d82980c 100644 --- a/orion-visor-ui/src/assets/style/global.less +++ b/orion-visor-ui/src/assets/style/global.less @@ -282,10 +282,18 @@ body { margin-left: 4px; } +.mr2 { + margin-right: 2px; +} + .mr4 { margin-right: 4px; } +.mt2 { + margin-top: 2px; +} + .mt4 { margin-top: 4px; } diff --git a/orion-visor-ui/src/assets/style/layout.less b/orion-visor-ui/src/assets/style/layout.less index e7bbf85a..1930ceeb 100644 --- a/orion-visor-ui/src/assets/style/layout.less +++ b/orion-visor-ui/src/assets/style/layout.less @@ -172,7 +172,7 @@ } & > .arco-card-body { - padding: 0 16px 16px 16px; + padding: 0 16px 12px 16px; flex-grow: 1; } } @@ -230,6 +230,10 @@ } // -- doption +.arco-dropdown-option-disabled .arco-dropdown-option-content .more-doption { + color: var(--color-text-4); +} + .more-doption { min-width: 42px; padding: 0 4px; diff --git a/orion-visor-ui/src/components/app/setting/index.vue b/orion-visor-ui/src/components/app/setting/index.vue index dd3ac34e..b2c937a0 100644 --- a/orion-visor-ui/src/components/app/setting/index.vue +++ b/orion-visor-ui/src/components/app/setting/index.vue @@ -152,6 +152,15 @@ defaultVal: appStore.hostIdentityView, options: cardOptions, }, + { + name: '主机监控', + key: 'monitorHostView', + type: 'radio-group', + margin: '0 0 4px 0', + permission: ['monitor:monitor-host:query'], + defaultVal: appStore.monitorHostView, + options: cardOptions, + }, ]); // 是否展示创建 PWA 应用 diff --git a/orion-visor-ui/src/components/app/tab-bar/index.vue b/orion-visor-ui/src/components/app/tab-bar/index.vue index 2911802f..03e86b5a 100644 --- a/orion-visor-ui/src/components/app/tab-bar/index.vue +++ b/orion-visor-ui/src/components/app/tab-bar/index.vue @@ -6,6 +6,7 @@

@@ -18,7 +19,6 @@ + + + + diff --git a/orion-visor-ui/src/views/monitor/metrics/components/metrics-table.vue b/orion-visor-ui/src/views/monitor/metrics/components/metrics-table.vue new file mode 100644 index 00000000..61eca0d0 --- /dev/null +++ b/orion-visor-ui/src/views/monitor/metrics/components/metrics-table.vue @@ -0,0 +1,221 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/monitor/metrics/index.vue b/orion-visor-ui/src/views/monitor/metrics/index.vue new file mode 100644 index 00000000..8876f0ee --- /dev/null +++ b/orion-visor-ui/src/views/monitor/metrics/index.vue @@ -0,0 +1,46 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/monitor/metrics/types/const.ts b/orion-visor-ui/src/views/monitor/metrics/types/const.ts new file mode 100644 index 00000000..d14d05b0 --- /dev/null +++ b/orion-visor-ui/src/views/monitor/metrics/types/const.ts @@ -0,0 +1,10 @@ +export const TableName = 'monitor_metrics'; + +// 监控指标类型 字典项 +export const MeasurementKey = 'metricsMeasurement'; + +// 监控指标单位 字典项 +export const MetricsUnitKey = 'metricsUnit'; + +// 加载的字典值 +export const dictKeys = [MeasurementKey, MetricsUnitKey]; diff --git a/orion-visor-ui/src/views/monitor/metrics/types/form.rules.ts b/orion-visor-ui/src/views/monitor/metrics/types/form.rules.ts new file mode 100644 index 00000000..9bfc9f58 --- /dev/null +++ b/orion-visor-ui/src/views/monitor/metrics/types/form.rules.ts @@ -0,0 +1,52 @@ +import type { FieldRule } from '@arco-design/web-vue'; + +export const name = [{ + required: true, + message: '请输入指标名称' +}, { + maxLength: 64, + message: '指标名称长度不能大于64位' +}] as FieldRule[]; + +export const measurement = [{ + required: true, + message: '请输入数据集' +}, { + maxLength: 64, + message: '数据集长度不能大于64位' +}] as FieldRule[]; + +export const value = [{ + required: true, + message: '请输入指标项' +}, { + maxLength: 128, + message: '指标项长度不能大于128位' +}] as FieldRule[]; + +export const unit = [{ + required: true, + message: '请选择单位' +}] as FieldRule[]; + +export const suffix = [{ + required: true, + message: '请输入后缀文本' +}, { + maxLength: 32, + message: '后缀文本长度不能大于32位' +}] as FieldRule[]; + +export const description = [{ + maxLength: 128, + message: '指标描述长度不能大于128位' +}] as FieldRule[]; + +export default { + name, + measurement, + value, + unit, + suffix, + description, +} as Record; diff --git a/orion-visor-ui/src/views/monitor/metrics/types/table.columns.ts b/orion-visor-ui/src/views/monitor/metrics/types/table.columns.ts new file mode 100644 index 00000000..bfbdfce6 --- /dev/null +++ b/orion-visor-ui/src/views/monitor/metrics/types/table.columns.ts @@ -0,0 +1,98 @@ +import type { TableColumnData } from '@arco-design/web-vue'; +import { dateFormat } from '@/utils'; + +const columns = [ + { + title: 'id', + dataIndex: 'id', + slotName: 'id', + width: 68, + align: 'left', + fixed: 'left', + default: true, + }, { + title: '指标名称', + dataIndex: 'name', + slotName: 'name', + align: 'left', + width: 238, + ellipsis: true, + tooltip: true, + default: true, + }, { + title: '数据集', + dataIndex: 'measurement', + slotName: 'measurement', + align: 'left', + width: 148, + ellipsis: true, + tooltip: true, + default: true, + }, { + title: '指标项', + dataIndex: 'value', + slotName: 'value', + align: 'left', + minWidth: 288, + ellipsis: true, + tooltip: true, + default: true, + }, { + title: '指标单位', + dataIndex: 'unit', + slotName: 'unit', + align: 'left', + width: 168, + default: true, + }, { + title: '指标描述', + dataIndex: 'description', + slotName: 'description', + align: 'left', + ellipsis: true, + tooltip: true, + default: true, + }, { + title: '创建时间', + dataIndex: 'createTime', + slotName: 'createTime', + align: 'center', + width: 180, + render: ({ record }) => { + return dateFormat(new Date(record.createTime)); + }, + }, { + title: '修改时间', + dataIndex: 'updateTime', + slotName: 'updateTime', + align: 'center', + width: 180, + render: ({ record }) => { + return dateFormat(new Date(record.updateTime)); + }, + default: true, + }, { + title: '创建人', + dataIndex: 'creator', + slotName: 'creator', + width: 148, + ellipsis: true, + tooltip: true, + }, { + title: '修改人', + dataIndex: 'updater', + slotName: 'updater', + width: 148, + ellipsis: true, + tooltip: true, + }, { + title: '操作', + slotName: 'handle', + width: 130, + align: 'center', + fixed: 'right', + default: true, + }, +] as TableColumnData[]; + +export default columns; diff --git a/orion-visor-ui/src/views/monitor/monitor-detail/compoments/detail-header.vue b/orion-visor-ui/src/views/monitor/monitor-detail/compoments/detail-header.vue new file mode 100644 index 00000000..59e84fa5 --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-detail/compoments/detail-header.vue @@ -0,0 +1,207 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/monitor/monitor-detail/compoments/metrics-chart-tab.vue b/orion-visor-ui/src/views/monitor/monitor-detail/compoments/metrics-chart-tab.vue new file mode 100644 index 00000000..bcc8608f --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-detail/compoments/metrics-chart-tab.vue @@ -0,0 +1,179 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/monitor/monitor-detail/compoments/metrics-chart.vue b/orion-visor-ui/src/views/monitor/monitor-detail/compoments/metrics-chart.vue new file mode 100644 index 00000000..ef9f8fb4 --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-detail/compoments/metrics-chart.vue @@ -0,0 +1,241 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/monitor/monitor-detail/index.vue b/orion-visor-ui/src/views/monitor/monitor-detail/index.vue new file mode 100644 index 00000000..fc2b8402 --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-detail/index.vue @@ -0,0 +1,112 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/monitor/monitor-detail/types/const.ts b/orion-visor-ui/src/views/monitor/monitor-detail/types/const.ts new file mode 100644 index 00000000..b83e96af --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-detail/types/const.ts @@ -0,0 +1,45 @@ +import type { WindowUnit, MetricUnitType, MetricUnitFormatOptions } from '@/utils/metrics'; + +// 图表组件配置 +export interface MetricsChartProps { + agentKeys: Array; + range: string; + windowValue: number; + windowUnit: WindowUnit; + option: MetricsChartOption; +} + +// 图表显示配置 +export interface MetricsChartOption { + name: string; + type?: 'line' | 'bar'; + measurement: string; + fields: Array; + span?: number; + legend?: boolean; + background?: boolean; + colors: Array<[string, string]>; + aggregate: string; + unit: MetricUnitType; + unitOption: MetricUnitFormatOptions; +} + +// tab +export const TabKeys = { + CHART: 'chart' +}; + +// 探针在线状态 字典项 +export const OnlineStatusKey = 'agentOnlineStatus'; + +// 监控告警开关 字典项 +export const AlarmSwitchKey = 'monitorAlarmSwitch'; + +// 指标图表区间 字典项 +export const ChartRangeKey = 'metricsChartRange'; + +// 指标聚合函数 字典项 +export const MetricsAggregateKey = 'metricsAggregate'; + +// 加载的字典值 +export const dictKeys = [AlarmSwitchKey, OnlineStatusKey, ChartRangeKey, MetricsAggregateKey]; diff --git a/orion-visor-ui/src/views/monitor/monitor-host/components/monitor-cell.vue b/orion-visor-ui/src/views/monitor/monitor-host/components/monitor-cell.vue new file mode 100644 index 00000000..b2939e74 --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-host/components/monitor-cell.vue @@ -0,0 +1,68 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/monitor/monitor-host/components/monitor-host-card-list.vue b/orion-visor-ui/src/views/monitor/monitor-host/components/monitor-host-card-list.vue new file mode 100644 index 00000000..0b6fdd94 --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-host/components/monitor-host-card-list.vue @@ -0,0 +1,418 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/monitor/monitor-host/components/monitor-host-form-drawer.vue b/orion-visor-ui/src/views/monitor/monitor-host/components/monitor-host-form-drawer.vue new file mode 100644 index 00000000..7a3f8b1b --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-host/components/monitor-host-form-drawer.vue @@ -0,0 +1,150 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/monitor/monitor-host/components/monitor-host-table.vue b/orion-visor-ui/src/views/monitor/monitor-host/components/monitor-host-table.vue new file mode 100644 index 00000000..fe224806 --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-host/components/monitor-host-table.vue @@ -0,0 +1,484 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/monitor/monitor-host/components/release-upload-modal.vue b/orion-visor-ui/src/views/monitor/monitor-host/components/release-upload-modal.vue new file mode 100644 index 00000000..83fcf6a2 --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-host/components/release-upload-modal.vue @@ -0,0 +1,112 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/monitor/monitor-host/index.vue b/orion-visor-ui/src/views/monitor/monitor-host/index.vue new file mode 100644 index 00000000..1dc9a151 --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-host/index.vue @@ -0,0 +1,65 @@ + + + + + + + diff --git a/orion-visor-ui/src/views/monitor/monitor-host/types/card.fields.ts b/orion-visor-ui/src/views/monitor/monitor-host/types/card.fields.ts new file mode 100644 index 00000000..c6b3c21a --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-host/types/card.fields.ts @@ -0,0 +1,81 @@ +import type { CardField, CardFieldConfig } from '@/types/card'; + +const fieldConfig = { + rowGap: '10px', + labelSpan: 6, + minHeight: '22px', + fields: [ + { + label: '主机ID', + dataIndex: 'hostId', + slotName: 'hostId', + default: true, + }, { + label: '主机地址', + dataIndex: 'address', + slotName: 'address', + default: true, + }, { + label: '主机编码', + dataIndex: 'code', + slotName: 'code', + default: false, + }, { + label: '负责人', + dataIndex: 'ownerUsername', + slotName: 'ownerUsername', + ellipsis: true, + default: true, + }, { + label: '设备状态', + dataIndex: 'agentOnlineStatus', + slotName: 'agentOnlineStatus', + default: true, + }, { + label: 'CPU', + dataIndex: 'cpuUsage', + slotName: 'cpuUsage', + default: true, + }, { + label: '内存', + dataIndex: 'memoryUsage', + slotName: 'memoryUsage', + default: true, + }, { + label: '磁盘', + dataIndex: 'diskUsage', + slotName: 'diskUsage', + default: true, + }, { + label: '网络', + dataIndex: 'network', + slotName: 'network', + default: true, + }, { + label: '负载', + dataIndex: 'load', + slotName: 'load', + default: true, + }, { + label: '标签', + dataIndex: 'tags', + slotName: 'tags', + default: false, + }, { + label: 'agentKey', + dataIndex: 'agentKey', + slotName: 'agentKey', + ellipsis: true, + default: false, + }, { + label: '探针版本', + dataIndex: 'agentVersion', + slotName: 'agentVersion', + ellipsis: true, + tooltip: true, + default: true, + } + ] as CardField[] +} as CardFieldConfig; + +export default fieldConfig; diff --git a/orion-visor-ui/src/views/monitor/monitor-host/types/const.ts b/orion-visor-ui/src/views/monitor/monitor-host/types/const.ts new file mode 100644 index 00000000..9b0d221b --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-host/types/const.ts @@ -0,0 +1,32 @@ +export const TableName = 'monitor_host'; + +// 监控告警开关 +export const AlarmSwitch = { + OFF: 0, + ON: 1, +}; + +// 探针日志状态 +export const AgentLogStatus = { + WAIT: 'WAIT', + RUNNING: 'RUNNING', + SUCCESS: 'SUCCESS', + FAILED: 'FAILED', +}; + +export const NODATA_TIPS = '暂无数据'; + +// 探针安装状态 字典项 +export const InstallStatusKey = 'agentInstallStatus'; + +// 探针在线状态 字典项 +export const OnlineStatusKey = 'agentOnlineStatus'; + +// 监控告警开关 字典项 +export const AlarmSwitchKey = 'monitorAlarmSwitch'; + +// 探针日志状态 字典项 +export const AgentLogStatusKey = 'agentLogStatus'; + +// 加载的字典值 +export const dictKeys = [InstallStatusKey, AlarmSwitchKey, OnlineStatusKey, AgentLogStatusKey]; diff --git a/orion-visor-ui/src/views/monitor/monitor-host/types/form.rules.ts b/orion-visor-ui/src/views/monitor/monitor-host/types/form.rules.ts new file mode 100644 index 00000000..00b6821b --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-host/types/form.rules.ts @@ -0,0 +1,16 @@ +import type { FieldRule } from '@arco-design/web-vue'; + +export const policyId = [{ + required: false, + message: '请输入策略id' +}] as FieldRule[]; + +export const alarmSwitch = [{ + required: true, + message: '请输入告警开关' +}] as FieldRule[]; + +export default { + policyId, + alarmSwitch, +} as Record; diff --git a/orion-visor-ui/src/views/monitor/monitor-host/types/table.columns.ts b/orion-visor-ui/src/views/monitor/monitor-host/types/table.columns.ts new file mode 100644 index 00000000..3328df4f --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-host/types/table.columns.ts @@ -0,0 +1,112 @@ +import type { TableColumnData } from '@arco-design/web-vue'; + +const columns = [ + { + title: '主机ID', + dataIndex: 'hostId', + slotName: 'hostId', + width: 80, + align: 'left', + fixed: 'left', + default: true, + }, { + title: '主机信息', + dataIndex: 'hostInfo', + slotName: 'hostInfo', + width: 248, + align: 'left', + fixed: 'left', + default: true, + }, { + title: '设备状态', + dataIndex: 'agentOnlineStatus', + slotName: 'agentOnlineStatus', + align: 'center', + width: 120, + default: true, + }, { + title: 'CPU', + dataIndex: 'cpuUsage', + slotName: 'cpuUsage', + align: 'left', + width: 198, + default: true, + }, { + title: '内存', + dataIndex: 'memoryUsage', + slotName: 'memoryUsage', + align: 'left', + width: 198, + default: true, + }, { + title: '磁盘', + dataIndex: 'diskUsage', + slotName: 'diskUsage', + align: 'left', + width: 198, + default: true, + }, { + title: '网络', + dataIndex: 'network', + slotName: 'network', + align: 'left', + width: 148, + default: true, + }, { + title: '负载', + dataIndex: 'load', + slotName: 'load', + align: 'left', + width: 148, + default: true, + }, { + title: '标签', + dataIndex: 'tags', + slotName: 'tags', + align: 'left', + minWidth: 148, + default: false, + }, { + title: 'agentKey', + dataIndex: 'agentKey', + slotName: 'agentKey', + align: 'left', + width: 288, + default: false, + }, { + // TODO + // title: '告警策略', + // dataIndex: 'alarmPolicy', + // slotName: 'alarmPolicy', + // align: 'left', + // width: 120, + // default: true, + // }, { + title: '负责人', + dataIndex: 'ownerUsername', + slotName: 'ownerUsername', + align: 'left', + width: 108, + ellipsis: true, + tooltip: true, + default: true, + }, { + title: '探针版本', + dataIndex: 'agentVersion', + slotName: 'agentVersion', + align: 'left', + width: 118, + ellipsis: true, + tooltip: true, + default: true, + }, { + title: '操作', + slotName: 'handle', + width: 128, + align: 'center', + fixed: 'right', + default: true, + }, +] as TableColumnData[]; + +export default columns; diff --git a/orion-visor-ui/src/views/monitor/monitor-host/types/use-monitor-host-list.ts b/orion-visor-ui/src/views/monitor/monitor-host/types/use-monitor-host-list.ts new file mode 100644 index 00000000..6e072b3e --- /dev/null +++ b/orion-visor-ui/src/views/monitor/monitor-host/types/use-monitor-host-list.ts @@ -0,0 +1,273 @@ +import type { MonitorHostQueryResponse, } from '@/api/monitor/monitor-host'; +import { getMonitorHostMetrics, updateMonitorHostAlarmSwitch } from '@/api/monitor/monitor-host'; +import type { HostAgentLogResponse } from '@/api/asset/host-agent'; +import { getAgentInstallLogStatus, getHostAgentStatus, installHostAgent, updateAgentInstallStatus } from '@/api/asset/host-agent'; +import type { Ref } from 'vue'; +import { onActivated, onDeactivated, onMounted, onUnmounted, ref } from 'vue'; +import { useRouter } from 'vue-router'; +import { useDictStore } from '@/store'; +import { Message, Modal } from '@arco-design/web-vue'; +import { AgentInstallStatus, HostOsType } from '@/views/asset/host-list/types/const'; +import { AgentLogStatus, AlarmSwitchKey } from '@/views/monitor/monitor-host/types/const'; + +// 监控主机列表配置 +export interface UseMonitorHostListOptions { + // 主机信息 + hosts: Ref>; + // 设置加载中 + setLoading: (loading: boolean) => void; + // 重新加载 + reload: () => void; +} + +// 使用监控主机列表 +export default function useMonitorHostList(options: UseMonitorHostListOptions) { + const autoRefresh = ref(true); + const autoRefreshId = ref(); + const fetchInstallStatusId = ref(); + const lastRefreshTime = ref(0); + + const router = useRouter(); + const { toggleDict } = useDictStore(); + const { hosts, setLoading, reload } = options; + + // 打开详情 + const openDetail = (hostId: number, name: string) => { + router.push({ name: 'monitorDetail', query: { hostId, name } }); + }; + + // 安装探针 + const installAgent = async (hostIdList: Array) => { + try { + setLoading(true); + // 获取全部数据 + const installHosts = hosts.value.filter(s => hostIdList.includes(s.hostId)); + let hasWindows = false; + // 安装前检查 + for (let host of installHosts) { + // 检查状态 + if (host?.installLog?.status === AgentLogStatus.WAIT || host?.installLog?.status === AgentLogStatus.RUNNING) { + Message.error('主机' + host.name + '正在安装中, 请勿重复操作'); + return; + } + // 检查系统类型 + if (host.osType === HostOsType.WINDOWS.value) { + hasWindows = true; + } + } + // 二次确认 + Modal.confirm({ + title: '安装提示', + titleAlign: 'start', + bodyStyle: { 'white-space': 'pre-wrap' }, + content: `请确保探针已关闭\n请确认文件夹是否有权限${hasWindows ? '\nWindows 系统仅支持探针上传, 请手动进行安装' : ''}`, + okText: '确定', + onOk: async () => { + try { + // 调用安装 + await installHostAgent({ idList: hostIdList }); + Message.success('开始安装'); + // 重新加载 + reload(); + } catch (e) { + } finally { + setLoading(false); + } + } + }); + } catch (e) { + } finally { + setLoading(false); + } + }; + + // 手动安装成功 + const setInstallSuccess = (log: HostAgentLogResponse) => { + Modal.confirm({ + title: '修正状态', + titleAlign: 'start', + content: `确定要手动将安装记录修正为完成吗?`, + okText: '确定', + onOk: async () => { + try { + setLoading(true); + // 调用修改接口 + await updateAgentInstallStatus({ + id: log.id, + status: AgentLogStatus.SUCCESS, + message: '手动修正', + }); + log.status = AgentLogStatus.SUCCESS; + Message.success('状态已修正'); + } catch (e) { + } finally { + setLoading(false); + } + } + }); + }; + + // 更新报警开关 + const toggleAlarmSwitch = async (record: MonitorHostQueryResponse) => { + const dict = toggleDict(AlarmSwitchKey, record.alarmSwitch); + Modal.confirm({ + title: `${dict.label}确认`, + titleAlign: 'start', + content: `确定要${dict.label}报警功能吗?`, + okText: '确定', + onOk: async () => { + try { + setLoading(true); + const newSwitch = dict.value as number; + // 调用修改接口 + await updateMonitorHostAlarmSwitch({ + id: record.id, + alarmSwitch: newSwitch, + }); + record.alarmSwitch = newSwitch; + Message.success(`已${dict.label}`); + } catch (e) { + } finally { + setLoading(false); + } + } + }); + }; + + // 获取探针安装状态 + const pullInstallLogStatus = async () => { + // 获取安装中的记录 + const runningIdList = hosts.value.filter(s => s.installLog?.status === AgentLogStatus.WAIT || s.installLog?.status === AgentLogStatus.RUNNING) + .map(s => s.installLog?.id) + .filter(Boolean); + if (!runningIdList.length) { + return; + } + // 查询状态 + const { data } = await getAgentInstallLogStatus(runningIdList); + data.forEach(item => { + hosts.value.filter(s => s.installLog?.id === item.id).forEach(s => { + s.installLog.status = item.status; + s.installLog.message = item.message; + // 若安装成功则修改探针信息 + if (item.status === AgentLogStatus.SUCCESS && item.agentStatus) { + s.agentVersion = item.agentStatus.agentVersion; + s.latestVersion = item.agentStatus.latestVersion; + s.agentInstallStatus = item.agentStatus.agentInstallStatus; + s.agentOnlineStatus = item.agentStatus.agentOnlineStatus; + } + }); + }); + }; + + // 获取探针状态 + const getAgentStatus = async () => { + // 获取全部 hostId + const hostIds = hosts.value.map(s => s.hostId); + if (hostIds.length) { + try { + // 查询状态 + const { data } = await getHostAgentStatus(hostIds); + data.forEach(item => { + hosts.value.filter(s => s.hostId === item.id).forEach(s => { + s.agentVersion = item.agentVersion; + s.latestVersion = item.latestVersion; + s.agentInstallStatus = item.agentInstallStatus; + s.agentOnlineStatus = item.agentOnlineStatus; + }); + }); + } catch (e) { + } + } + }; + + // 获取指标信息 + const getHostMetrics = async () => { + // 获取全部已安装 agentKey + const agentKeys = hosts.value + .filter(s => s.agentInstallStatus === AgentInstallStatus.INSTALLED) + .map(s => s.agentKey) + .filter(Boolean); + if (agentKeys.length) { + try { + // 查询指标 + const { data } = await getMonitorHostMetrics(agentKeys); + data.forEach(item => { + hosts.value.filter(s => s.agentKey === item.agentKey).forEach(s => { + s.metricsData = item; + }); + }); + } catch (e) { + } + } + }; + + // 刷新指标 + const refreshMetrics = async () => { + // 加载状态信息 + await getAgentStatus(); + // 加载指标数据 + await getHostMetrics(); + // 设置刷新时间 + lastRefreshTime.value = Date.now(); + }; + + // 切换自动刷新 + const toggleAutoRefresh = async () => { + autoRefresh.value = !autoRefresh.value; + if (autoRefresh.value) { + // 开启自动刷新 + await openAutoRefresh(); + } else { + // 关闭自动刷新 + closeAutoRefresh(); + } + }; + + // 开启自动刷新 + const openAutoRefresh = async () => { + window.clearInterval(autoRefreshId.value); + if (!autoRefresh.value) { + return; + } + if (lastRefreshTime.value === 0) { + // 防止首次就刷新 + lastRefreshTime.value = 1; + } else if (Date.now() - lastRefreshTime.value > 60000) { + // 超过刷新的时间 + await refreshMetrics(); + } + // 设置自动刷新 + autoRefreshId.value = window.setInterval(refreshMetrics, 60000); + }; + + // 关闭自动刷新 + const closeAutoRefresh = () => { + window.clearInterval(autoRefreshId.value); + autoRefreshId.value = undefined; + }; + + onMounted(openAutoRefresh); + onActivated(openAutoRefresh); + onDeactivated(closeAutoRefresh); + onUnmounted(closeAutoRefresh); + + onMounted(() => { + window.clearInterval(fetchInstallStatusId.value); + fetchInstallStatusId.value = window.setInterval(pullInstallLogStatus, 5000); + }); + + onUnmounted(() => { + window.clearInterval(fetchInstallStatusId.value); + }); + + return { + autoRefresh, + openDetail, + installAgent, + setInstallSuccess, + toggleAlarmSwitch, + toggleAutoRefresh, + }; + +}; diff --git a/orion-visor-ui/src/views/terminal/components/view/rdp/rdp-action-bar.vue b/orion-visor-ui/src/views/terminal/components/view/rdp/rdp-action-bar.vue index 7d96f1fc..ba3a311e 100644 --- a/orion-visor-ui/src/views/terminal/components/view/rdp/rdp-action-bar.vue +++ b/orion-visor-ui/src/views/terminal/components/view/rdp/rdp-action-bar.vue @@ -206,7 +206,11 @@ // 选择文件回调 const onSelectFile = (files: Array) => { - fileList.value = [files[files.length - 1]]; + if (files.length) { + fileList.value = [files[files.length - 1]]; + } else { + fileList.value = []; + } }; // 上传文件