diff --git a/src/main/java/com/tongran/agent/client/core/config/GlobalConfig.java b/src/main/java/com/tongran/agent/client/core/config/GlobalConfig.java index a1e75d2..ffd4ac2 100644 --- a/src/main/java/com/tongran/agent/client/core/config/GlobalConfig.java +++ b/src/main/java/com/tongran/agent/client/core/config/GlobalConfig.java @@ -1,6 +1,10 @@ package com.tongran.agent.client.core.config; +import com.tongran.agent.client.core.eo.AlarmEO; +import com.tongran.agent.client.core.eo.NativeNetworkInterfaceEO; + import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -22,7 +26,7 @@ public class GlobalConfig { public static String CLIENT_ID; /** - * 交换机 + * 交换机信息 */ public static String SWITCH_COMMUNITY; //团名 public static String SWITCH_IP; //交换机IP @@ -40,7 +44,7 @@ public class GlobalConfig { public static boolean isCollect = false; public static Map taskIds = new ConcurrentHashMap<>(); /** - * 系统监控 + * 采集系统监控 */ public static boolean cpuCollect = false; //cpu采集 public static long cpuInterval = 300; //cpu采集间隔 @@ -53,7 +57,7 @@ public class GlobalConfig { public static boolean dockerCollect = false; //docker采集 public static long dockerInterval = 300; //docker采集间隔 /** - * 系统其他监控 + * 采集系统其他监控 */ public static boolean systemSwapSizeFreeCollect = false; //交换卷/文件的可用空间(字节)采集 public static long systemSwapSizeFreeInterval = 300; //交换卷/文件的可用空间(字节)采集间隔 @@ -90,7 +94,7 @@ public class GlobalConfig { public static boolean procNumCollect = false; //进程数采集 public static long procNumInterval = 300; //进程数采集间隔 /** - * 交换机监控 + * 采集交换机监控 */ public static boolean switchNetCollect = false; //交换机网络采集 public static long switchNetInterval = 300; //交换机网络采集间隔 @@ -103,7 +107,7 @@ public class GlobalConfig { public static boolean switchFanCollect = false; //风扇采集 public static long switchFanInterval = 300; //风扇采集间隔 /** - * 交换机其他监控 + * 采集交换机其他监控 */ public static boolean switchSysDescrCollect = false; //系统描述采集 public static long switchSysDescrInterval = 300; //系统描述采集间隔 @@ -135,6 +139,28 @@ public class GlobalConfig { public static long switchHwCurrentPowerInterval = 300; //系统实时功率(mW)采集间隔 + /** + * 告警 + */ + public static boolean IS_ALARM = false; + public static long ALARM_INTERVAL = 120; + public static List ALARM_LIST; //告警设置信息 + /** + * 告警监控 + */ + public static boolean systemCpuUti = false; //CPU使用率 + public static boolean memoryUtilization = false; //内存利用率 + public static boolean systemSwapSizePercent = false; //可用交换空间百分比 + public static boolean systemUsersNum = false; //登录用户数 + public static boolean vfsFsUtil = false; //挂载点的空间利用率 + public static boolean netIfStatus = false; //网络运行状态UP变down + public static boolean netUtil = false; //网络带宽使用率 + public static boolean containerMemUtil = false; //容器内存使用率 + public static boolean extraPorts = false; //多余端口 + /** + * 所有网络接口 + */ + public static List NET_LIST; } diff --git a/src/main/java/com/tongran/agent/client/core/enums/MsgEnum.java b/src/main/java/com/tongran/agent/client/core/enums/MsgEnum.java index 55cb040..786dedb 100644 --- a/src/main/java/com/tongran/agent/client/core/enums/MsgEnum.java +++ b/src/main/java/com/tongran/agent/client/core/enums/MsgEnum.java @@ -38,6 +38,8 @@ public enum MsgEnum { 系统其他上报("OTHER_SYSTEM"), + 告警上报("ALARM"), + 开启系统采集("SYSTEM_COLLECT_START"), 开启系统采集应答("SYSTEM_COLLECT_START_RSP"), diff --git a/src/main/java/com/tongran/agent/client/core/eo/AlarmEO.java b/src/main/java/com/tongran/agent/client/core/eo/AlarmEO.java new file mode 100644 index 0000000..c36edeb --- /dev/null +++ b/src/main/java/com/tongran/agent/client/core/eo/AlarmEO.java @@ -0,0 +1,25 @@ +package com.tongran.agent.client.core.eo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class AlarmEO { + + //告警内容类型 + private String type; + + //是否开启标识:默认false + private boolean collect; + + //告警阈值 + private String threshold; + + //比较类型:0、大于;1、大于且等于;2、小于;3、小于且等于; + private int compareType; +} diff --git a/src/main/java/com/tongran/agent/client/core/eo/NativeNetworkInterfaceEO.java b/src/main/java/com/tongran/agent/client/core/eo/NativeNetworkInterfaceEO.java new file mode 100644 index 0000000..5fb38c7 --- /dev/null +++ b/src/main/java/com/tongran/agent/client/core/eo/NativeNetworkInterfaceEO.java @@ -0,0 +1,16 @@ +package com.tongran.agent.client.core.eo; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class NativeNetworkInterfaceEO { + private String name; + private String displayName; + private boolean up; +} diff --git a/src/main/java/com/tongran/agent/client/core/vo/AlarmVO.java b/src/main/java/com/tongran/agent/client/core/vo/AlarmVO.java new file mode 100644 index 0000000..3d8aa1d --- /dev/null +++ b/src/main/java/com/tongran/agent/client/core/vo/AlarmVO.java @@ -0,0 +1,22 @@ +package com.tongran.agent.client.core.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor +@Schema(description = "告警信息") +public class AlarmVO { + @Schema(description = "告警内容类型") + private String type; + + private String result; + + @Schema(description = "时间戳") + private long timestamp; +} diff --git a/src/main/java/com/tongran/agent/client/netty/enpoint/AgentEndpoint.java b/src/main/java/com/tongran/agent/client/netty/enpoint/AgentEndpoint.java index 616a6ad..eda47a4 100644 --- a/src/main/java/com/tongran/agent/client/netty/enpoint/AgentEndpoint.java +++ b/src/main/java/com/tongran/agent/client/netty/enpoint/AgentEndpoint.java @@ -7,6 +7,7 @@ import com.alibaba.fastjson2.TypeReference; import com.tongran.agent.client.core.config.GlobalConfig; import com.tongran.agent.client.core.enums.MsgEnum; import com.tongran.agent.client.core.eo.AgentVersionUpdateEO; +import com.tongran.agent.client.core.eo.AlarmEO; import com.tongran.agent.client.core.eo.ScriptPolicyEO; import com.tongran.agent.client.netty.annotation.AgentDispatcher; import com.tongran.agent.client.netty.basics.AgentHandler; @@ -19,6 +20,7 @@ import com.tongran.agent.client.scheduler.service.Java8FileDownloader; import com.tongran.agent.client.scheduler.task.SpecificTimeRequest; import com.tongran.agent.client.scheduler.task.SpecificTimeTaskService; import com.tongran.agent.client.service.AgentService; +import com.tongran.agent.client.utils.AgentDataUtil; import com.tongran.agent.client.utils.AgentUtil; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; @@ -201,63 +203,24 @@ public class AgentEndpoint { public class AlarmSetHandler implements AgentHandler { @Override public UpMsgResponse upHandle(String data, String clientId) { -// //更改全局变量 -// JSONObject jsonObject = JSONObject.parseObject(data); -// if(jsonObject.containsKey("switchBoard")){ -// String switchBoard = jsonObject.getString("switchBoard"); -// jsonObject = JSONObject.parseObject(switchBoard); -// if(jsonObject.containsKey("community")){ -// GlobalConfig.SWITCH_COMMUNITY = jsonObject.getString("community"); -// } -// if(jsonObject.containsKey("ip")){ -// GlobalConfig.SWITCH_IP = jsonObject.getString("ip"); -// } -// if(jsonObject.containsKey("port")){ -// GlobalConfig.SWITCH_PORT = jsonObject.getInteger("port"); -// } -// if(jsonObject.containsKey("netOID")){ -// String netOID = jsonObject.getString("netOID"); -// LinkedHashMap map = JSON.parseObject(netOID, new TypeReference>() {}); -// GlobalConfig.SWITCH_NET_OID = map; -// } -// if(jsonObject.containsKey("moduleOID")){ -// String moduleOID = jsonObject.getString("moduleOID"); -// LinkedHashMap map = JSON.parseObject(moduleOID, new TypeReference>() {}); -// GlobalConfig.SWITCH_MODULE_OID = map; -// } -// if(jsonObject.containsKey("mpuOID")){ -// String mpuOID = jsonObject.getString("mpuOID"); -// LinkedHashMap map = JSON.parseObject(mpuOID, new TypeReference>() {}); -// GlobalConfig.SWITCH_MPU_OID = map; -// } -// if(jsonObject.containsKey("pwrOID")){ -// String pwrOID = jsonObject.getString("pwrOID"); -// LinkedHashMap map = JSON.parseObject(pwrOID, new TypeReference>() {}); -// GlobalConfig.SWITCH_PWR_OID = map; -// } -// if(jsonObject.containsKey("fanOID")){ -// String fanOID = jsonObject.getString("fanOID"); -// LinkedHashMap map = JSON.parseObject(fanOID, new TypeReference>() {}); -// GlobalConfig.SWITCH_FAN_OID = map; -// } -// if(jsonObject.containsKey("otherOID")){ -// String otherOID = jsonObject.getString("otherOID"); -// LinkedHashMap map = JSON.parseObject(otherOID, new TypeReference>() {}); -// GlobalConfig.SWITCH_OTHER_OID = map; -// } -// } -// GlobalConfig.isCollect = true; -// GlobalConfig.CLIENT_ID = clientId; -// //调用采集任务 -// try { -// appInitializer.run(); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// JSONObject json = new JSONObject(); -// json.put("resCode",1); + //更改全局变量 + JSONObject jsonObject = JSONObject.parseObject(data); + if(jsonObject.containsKey("alarms")){ + String alarms = jsonObject.getString("alarms"); + GlobalConfig.ALARM_LIST = JSON.parseObject(alarms, new TypeReference>() {}); + if(CollectionUtil.isNotEmpty(GlobalConfig.ALARM_LIST)){ + GlobalConfig.IS_ALARM = AgentDataUtil.hasAnyActiveAlarm(GlobalConfig.ALARM_LIST); + } + } + agentService.alarmMonitor(); + long timestamp = System.currentTimeMillis(); + timestamp = Math.round(timestamp / 1000.0); + JSONObject json = new JSONObject(); + json.put("resCode",1); + json.put("resMag",""); + json.put("timestamp",timestamp); return UpMsgResponse.builder().clientId(clientId).dataType(MsgEnum.告警设置应答.getValue()) - .content("").build(); + .content(json.toString()).build(); } } diff --git a/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java b/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java index c094670..b05781f 100644 --- a/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java +++ b/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java @@ -1,5 +1,6 @@ package com.tongran.agent.client.scheduler.service; +import cn.hutool.core.collection.CollectionUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; @@ -12,6 +13,7 @@ import com.tongran.agent.client.netty.model.Message; import com.tongran.agent.client.service.*; import com.tongran.agent.client.utils.AgentUtil; import com.tongran.agent.client.utils.AssertLog; +import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @@ -34,6 +36,7 @@ public class BusinessTasks { private final AtomicInteger task7Counter = new AtomicInteger(0); private final AtomicInteger task8Counter = new AtomicInteger(0); private final AtomicInteger task9Counter = new AtomicInteger(0); + private final AtomicInteger task10Counter = new AtomicInteger(0); protected final SessionManager sessionManager; @@ -69,6 +72,9 @@ public class BusinessTasks { @Resource private SystemService systemService; + @Resource + private AlarmService alarmService; + @Resource private ApplicationProperties properties; @@ -130,8 +136,11 @@ public class BusinessTasks { // 判定客户端与服务端是否连接 if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) { // 发送磁盘信息包 + String data = ""; List list = diskService.diskList(timestamp); - String data = JSONArray.toJSONString(list); + if(CollectionUtil.isNotEmpty(list)){ + data = JSONArray.toJSONString(list); + } Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.磁盘上报.getValue()).data(data).build(); sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message); } @@ -150,8 +159,11 @@ public class BusinessTasks { // 判定客户端与服务端是否连接 if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) { // 发送容器包 + String data = ""; List list = dockerService.dockerList(timestamp); - String data = JSONArray.toJSONString(list); + if(CollectionUtil.isNotEmpty(list)){ + data = JSONArray.toJSONString(list); + } Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.容器上报.getValue()).data(data).build(); sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message); } @@ -190,8 +202,11 @@ public class BusinessTasks { // 判定客户端与服务端是否连接 if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) { // 发送网卡信息包 + String data = ""; List list = netService.netList(timestamp); - String data = JSONArray.toJSONString(list); + if(CollectionUtil.isNotEmpty(list)){ + data = JSONArray.toJSONString(list); + } Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.网络上报.getValue()).data(data).build(); sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message); } @@ -210,8 +225,11 @@ public class BusinessTasks { // 判定客户端与服务端是否连接 if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) { // 发送挂载点信息包 + String data = ""; List list = diskService.pointList(timestamp); - String data = JSONArray.toJSONString(list); + if(CollectionUtil.isNotEmpty(list)){ + data = JSONArray.toJSONString(list); + } Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.挂载上报.getValue()).data(data).build(); sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message); } @@ -233,8 +251,11 @@ public class BusinessTasks { // List list = switchBoardService.switchBoardList(timestamp); // String data = JSONArray.toJSONString(list); // Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.交换机上报.getValue()).data(data).build(); + JSONObject jsonObject = new JSONObject(); String data = switchBoardService.getSwitchDataByType(type); - JSONObject jsonObject = JSONObject.parseObject(data); + if(StringUtils.isNotBlank(data)){ + jsonObject = JSONObject.parseObject(data); + } jsonObject.put("timestamp", timestamp); Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.交换机上报.getValue()).data(jsonObject.toString()).build(); sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message); @@ -248,6 +269,7 @@ public class BusinessTasks { @Async("taskExecutor") public void systemTask(String type) { long timestamp = System.currentTimeMillis(); + timestamp = Math.round(timestamp / 1000.0); int count = task9Counter.incrementAndGet(); AssertLog.info("系统信息采集定时任务执行 - 时间: {},task #{}", LocalDateTime.now(), count); // 判定客户端与服务端是否连接 @@ -257,8 +279,11 @@ public class BusinessTasks { // systemVO.setTimestamp(timestamp); // String data = JSON.toJSONString(systemVO); // Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.系统其他上报.getValue()).data(data).build(); + JSONObject jsonObject = new JSONObject(); String data = systemService.otherSystem(type); - JSONObject jsonObject = JSONObject.parseObject(data); + if(StringUtils.isNotBlank(data)){ + jsonObject = JSONObject.parseObject(data); + } jsonObject.put("timestamp", timestamp); Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.系统其他上报.getValue()).data(jsonObject.toString()).build(); sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message); @@ -266,4 +291,26 @@ public class BusinessTasks { AssertLog.info("系统信息采集定时任务执行 - task #{} completed", count); } + /** + * 任务10:告警监控任务 + */ + @Async("taskExecutor") + public void alarmTask() { + long timestamp = System.currentTimeMillis(); + timestamp = Math.round(timestamp / 1000.0); + int count = task10Counter.incrementAndGet(); + AssertLog.info("告警监控定时任务执行 - 时间: {},task #{}", LocalDateTime.now(), count); + // 判定客户端与服务端是否连接 + if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) { + String data = ""; + List list = alarmService.alarmMonitor(timestamp); + if(CollectionUtil.isNotEmpty(list)){ + data = JSONArray.toJSONString(list); + } + Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.告警上报.getValue()).data(data).build(); + sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message); + } + AssertLog.info("告警监控定时任务执行 - task #{} completed", count); + } + } \ No newline at end of file diff --git a/src/main/java/com/tongran/agent/client/service/AgentService.java b/src/main/java/com/tongran/agent/client/service/AgentService.java index fb3cbe3..5d06b9e 100644 --- a/src/main/java/com/tongran/agent/client/service/AgentService.java +++ b/src/main/java/com/tongran/agent/client/service/AgentService.java @@ -8,4 +8,6 @@ public interface AgentService { void switchCollectStart(String data); void switchCollectStop(); + + void alarmMonitor(); } diff --git a/src/main/java/com/tongran/agent/client/service/AlarmService.java b/src/main/java/com/tongran/agent/client/service/AlarmService.java new file mode 100644 index 0000000..b94485e --- /dev/null +++ b/src/main/java/com/tongran/agent/client/service/AlarmService.java @@ -0,0 +1,9 @@ +package com.tongran.agent.client.service; + +import com.tongran.agent.client.core.vo.AlarmVO; + +import java.util.List; + +public interface AlarmService { + List alarmMonitor(long timestamp); +} diff --git a/src/main/java/com/tongran/agent/client/service/impl/AgentServiceImpl.java b/src/main/java/com/tongran/agent/client/service/impl/AgentServiceImpl.java index 1aff3b4..7af6f76 100644 --- a/src/main/java/com/tongran/agent/client/service/impl/AgentServiceImpl.java +++ b/src/main/java/com/tongran/agent/client/service/impl/AgentServiceImpl.java @@ -377,5 +377,19 @@ public class AgentServiceImpl implements AgentService { GlobalConfig.switchHwCurrentPowerInterval = 300; //系统实时功率(mW)采集间隔 } + @Override + public void alarmMonitor() { + if(GlobalConfig.IS_ALARM){ + //开启告警监控 + long milli = AgentUtil.getMillisToNextMinute() + 60000; + dynamicTaskService.scheduleTask("alarmTask", + businessTasks::alarmTask, milli, GlobalConfig.ALARM_INTERVAL*1000L); + }else{ + //关闭告警监控 + dynamicTaskService.cancelTask("alarmTask"); + } + + } + } diff --git a/src/main/java/com/tongran/agent/client/service/impl/AlarmServiceImpl.java b/src/main/java/com/tongran/agent/client/service/impl/AlarmServiceImpl.java new file mode 100644 index 0000000..586eb12 --- /dev/null +++ b/src/main/java/com/tongran/agent/client/service/impl/AlarmServiceImpl.java @@ -0,0 +1,456 @@ +package com.tongran.agent.client.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.github.dockerjava.core.DockerClientImpl; +import com.github.dockerjava.httpclient5.ApacheDockerHttpClient; +import com.github.dockerjava.transport.DockerHttpClient; +import com.tongran.agent.client.core.config.GlobalConfig; +import com.tongran.agent.client.core.eo.AlarmEO; +import com.tongran.agent.client.core.eo.NativeNetworkInterfaceEO; +import com.tongran.agent.client.core.vo.AlarmVO; +import com.tongran.agent.client.service.AlarmService; +import com.tongran.agent.client.utils.AgentDataUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import oshi.SystemInfo; +import oshi.hardware.CentralProcessor; +import oshi.hardware.HardwareAbstractionLayer; +import oshi.hardware.NetworkIF; +import oshi.software.os.OSFileStore; +import oshi.software.os.OperatingSystem; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Service +public class AlarmServiceImpl implements AlarmService { + @Override + public List alarmMonitor(long timestamp) { + List alarmVOList = new ArrayList<>(); + List list = GlobalConfig.ALARM_LIST.stream().filter(a -> a.isCollect() == true).collect(Collectors.toList()); + if(CollectionUtil.isNotEmpty(list)){ + for (AlarmEO alarmEO : list) { + String type = alarmEO.getType(); + String threshold = alarmEO.getThreshold(); + int compareType = alarmEO.getCompareType(); + AlarmVO alarmVO = AlarmVO.builder().type(type).timestamp(timestamp).build(); + switch(type) { + case "systemCpuUti": //CPU使用率 + alarmVO.setResult(handleSystemCpuUti(threshold, compareType)); + alarmVOList.add(alarmVO); + break; + case "memoryUtilization": //内存利用率 + alarmVO.setResult(handleMemoryUtilization(threshold, compareType)); + alarmVOList.add(alarmVO); + break; + case "systemSwapSizePercent": //可用交换空间百分比 + alarmVO.setResult(handleSystemSwapSizePercent(threshold, compareType)); + alarmVOList.add(alarmVO); + break; + case "systemUsersNum": //登录用户数 + alarmVO.setResult(handleSystemUsersNum(threshold, compareType)); + alarmVOList.add(alarmVO); + break; + case "vfsFsUtil": //挂载点的空间利用率 + alarmVO.setResult(handleVfsFsUtil(threshold, compareType)); + alarmVOList.add(alarmVO); + break; + case "netUtil": //网络带宽使用率 + alarmVO.setResult(handleNetUtil(threshold, compareType)); + alarmVOList.add(alarmVO); + break; + case "containerMemUtil": //容器内存使用率 + alarmVO.setResult(handleContainerMemUtil(threshold, compareType)); + alarmVOList.add(alarmVO); + break; + case "netIfStatus": //网络运行状态UP变down + alarmVO.setResult(handleNetIfStatus()); + alarmVOList.add(alarmVO); + break; + case "extraPorts": //多余端口 + alarmVO.setResult(handleExtraPorts(threshold)); + alarmVOList.add(alarmVO); + break; + default: //其他 + break; + } + } + } + return alarmVOList; + } + + private String handleSystemCpuUti(String threshold, int compareType){ + try { + SystemInfo si = new SystemInfo(); + HardwareAbstractionLayer hal = si.getHardware(); + CentralProcessor processor = hal.getProcessor(); + long[] prevTicks = processor.getSystemCpuLoadTicks(); + try { + TimeUnit.SECONDS.sleep(1); // 等待1秒 + } catch (InterruptedException e) { + e.printStackTrace(); + } + // 计算使用率 + double cpuUsage = processor.getSystemCpuLoadBetweenTicks(prevTicks) * 100; + boolean isFalse = false; + if(StringUtils.isNotBlank(threshold)){ + isFalse = compare(cpuUsage, threshold, compareType); + } + if(isFalse){ + return "当前CPU使用率:"+cpuUsage +"%"; + } + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + private String handleMemoryUtilization(String threshold, int compareType){ + try { + Map memInfo = AgentDataUtil.parseMemInfo(); + long total = memInfo.get("MemTotal"); + long available = memInfo.getOrDefault("MemAvailable", + memInfo.get("MemFree") + + memInfo.getOrDefault("Buffers", 0L) + + memInfo.getOrDefault("Cached", 0L) + + memInfo.getOrDefault("SReclaimable", 0L)); + // 总内存使用率 + double totalUsage = (double)(total - available) / total * 100; + boolean isFalse = false; + if(StringUtils.isNotBlank(threshold)){ + isFalse = compare(totalUsage, threshold, compareType); + } + if(isFalse){ + return "当前内存利用率:"+totalUsage +"%"; + } + } catch (IOException e) { + e.printStackTrace(); + } + return ""; + } + + private String handleSystemSwapSizePercent(String threshold, int compareType){ + try { + Map memInfo = AgentDataUtil.parseMemInfo(); + long swapTotal = memInfo.getOrDefault("SwapTotal", 0L); + long swapFree = memInfo.getOrDefault("SwapFree", 0L); + double swapSizePercent = (double) swapFree / swapTotal * 100; //可用交换空间百分比 + boolean isFalse = false; + if(StringUtils.isNotBlank(threshold)){ + isFalse = compare(swapSizePercent, threshold, compareType); + } + if(isFalse){ + return "当前可用交换空间百分比:"+swapSizePercent +"%"; + } + } catch (IOException e) { + e.printStackTrace(); + } + return ""; + } + + private String handleSystemUsersNum(String threshold, int compareType){ + SystemInfo si = new SystemInfo(); + OperatingSystem os = si.getOperatingSystem(); + int userNum = os.getSessions().size(); + boolean isFalse = false; + if(StringUtils.isNotBlank(threshold)){ + isFalse = compare(userNum, threshold, compareType); + } + if(isFalse){ + return "当前登录用户数:"+userNum; + } + return ""; + } + + private String handleVfsFsUtil(String threshold, int compareType){ + String result = ""; + SystemInfo si = new SystemInfo(); + for (OSFileStore fs : si.getOperatingSystem().getFileSystem().getFileStores()) { + String mount = fs.getMount(); + long totalSpace = fs.getTotalSpace(); + long freeSpace = fs.getFreeSpace(); + double usagePercentage = totalSpace > 0 ? + (double) (totalSpace - freeSpace) / totalSpace * 100 : 0; + if(StringUtils.isNotBlank(threshold)){ + boolean isFalse = compare(usagePercentage, threshold, compareType); + if(isFalse){ + result +="挂载点:"+mount+",当前空间利用率:"+usagePercentage+"%;"; + } + } + } + return result; + } + + private String handleNetUtil(String threshold, int compareType){ + String result = ""; + try { + SystemInfo si = new SystemInfo(); + HardwareAbstractionLayer hal = si.getHardware(); + // 获取所有网络接口 + List networkIFs = hal.getNetworkIFs(); + // 第一次采样 + for (NetworkIF net : networkIFs) { + net.updateAttributes(); + } + // 等待1秒 + TimeUnit.SECONDS.sleep(1); + // 第二次采样并计算速率 + for (NetworkIF net : networkIFs) { + // 只显示以太网接口 + if (net.getName().startsWith("eth") || + net.getName().startsWith("en") || + net.getDisplayName().toLowerCase().contains("ethernet")) { + long prevBytesSent = net.getBytesSent(); + net.updateAttributes(); + long bytesSent = net.getBytesSent() - prevBytesSent; + // 获取最大带宽 + double maxBandwidth = getInterfaceMaxBandwidth(net); + // 计算使用率百分比 + double sentUsagePercentage = (bytesToMbps(bytesSent) / maxBandwidth) * 100; + boolean isFalse = false; + if(StringUtils.isNotBlank(threshold)){ + isFalse = compare(sentUsagePercentage, threshold, compareType); + } + if(isFalse){ + result += "网络接口:"+ net.getName() + ",当前发送流量带宽使用率:" + sentUsagePercentage +"%;"; + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + private String handleContainerMemUtil(String threshold, int compareType){ + // 配置Docker客户端 + DefaultDockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder() + .withDockerHost("unix:///var/run/docker.sock") + .withDockerTlsVerify(false) // 根据你的配置调整 + .build(); + DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder() + .dockerHost(config.getDockerHost()) + .sslConfig(config.getSSLConfig()) + .maxConnections(100) + .connectionTimeout(Duration.ofSeconds(30)) + .responseTimeout(Duration.ofSeconds(45)) + .build(); + DockerClient dockerClient = DockerClientImpl.getInstance(config, httpClient); + String result = ""; + try { + // 获取正在运行的容器列表 + List containers = dockerClient.listContainersCmd() + .withShowAll(false) // 只显示运行中的容器 + .exec(); + // 打印容器信息 + System.out.println("运行中的Docker容器:"); + System.out.println("容器ID\t\t镜像\t\t状态\t\t名称"); + for (Container container : containers) { + String id = container.getId().substring(0, 12); // 只显示短ID + String name = container.getNames()[0].replaceFirst("/", ""); + // 执行 docker stats 命令(--no-stream 表示只输出一次) + Process process = new ProcessBuilder( + "docker", "stats", "--no-stream", id, + "--format", "'table {{.ID}}\t{{.Name}}\t{{.CPUPerc}}\t{{.MemPerc}}\t{{.NetIO}}" + ).start(); + // 读取命令输出 + BufferedReader reader = new BufferedReader( + new InputStreamReader(process.getInputStream()) + ); + String line; + while ((line = reader.readLine()) != null) { + String[] parts = line.trim().split("\\s+"); + String memUtil = parts[4]; // 内存使用率 + memUtil = memUtil.replace("%",""); + if(StringUtils.isNotBlank(memUtil)){ + boolean isFalse = false; + if(StringUtils.isNotBlank(threshold)){ + isFalse = compare(Double.parseDouble(memUtil), threshold, compareType); + } + if(isFalse){ + result += "容器:"+name+",当前内存使用率"+memUtil+"%;"; + } + } + } + // 等待命令执行完成并获取退出码 + int exitCode = process.waitFor(); + if (exitCode != 0) { + System.err.println("命令执行失败,退出码: " + exitCode); + } + reader.close(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + dockerClient.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return result; + } + + private String handleNetIfStatus(){ + String result = ""; + try { + List list = getAllNetworkInterfaces(); + if(CollectionUtil.isNotEmpty(GlobalConfig.NET_LIST)){ + List natList = list.stream().filter(n -> n.isUp() == false).map(NativeNetworkInterfaceEO::getName).collect(Collectors.toList()); + List temp = GlobalConfig.NET_LIST.stream().filter(n -> n.isUp()) + .collect(Collectors.toList()); + for (NativeNetworkInterfaceEO n : temp) { + if(natList.contains(n.getName())){ + result += "网络接口:"+n.getName()+",运行状态由UP转为DOWN;"; + } + } + } + GlobalConfig.NET_LIST = list; + } catch (SocketException e) { + System.err.println("获取网络接口信息失败: " + e.getMessage()); + } + return result; + } + + private String handleExtraPorts(String threshold){ + String result = ""; + try { + List list = scanPortsUsingNmap(); + for (Integer port : list) { + boolean flag = verifyPort(port, threshold); + if(!flag){ + result += "端口:"+port+"已开放;"; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + private boolean compare(double value, String threshold, int compareType){ + boolean isFalse = false; + switch(compareType) { + case 1: //大于且等于 + if(value >= Double.parseDouble(threshold)){ + isFalse = true; + } + break; + case 2: //小于 + if(value < Double.parseDouble(threshold)){ + isFalse = true; + } + break; + case 3: //小于且等于 + if(value <= Double.parseDouble(threshold)){ + isFalse = true; + } + break; + default: //大于 + if(value > Double.parseDouble(threshold)){ + isFalse = true; + } + break; + } + return isFalse; + } + + private static double bytesToMbps(long bytes) { + return bytes * 8.0 / 1_000_000; // bytes to megabits + } + + /** + * 获取接口的理论最大带宽(Mbps) + */ + private double getInterfaceMaxBandwidth(NetworkIF netIf) { + String name = netIf.getName().toLowerCase(); + long speed = netIf.getSpeed(); // 获取接口速度(bps) + + if (speed > 0) { + return speed / 1_000_000.0; // 转换为Mbps + } + + // 如果无法获取速度,根据常见接口类型估算 + if (name.contains("eth") || name.contains("en") || name.contains("gigabit")) { + return 1000.0; // 千兆以太网 + } else if (name.contains("10g") || name.contains("10000")) { + return 10000.0; // 万兆以太网 + } else { + return 100.0; // 默认百兆以太网 + } + } + + + /** + * 获取所有网络接口信息 + */ + public List getAllNetworkInterfaces() throws SocketException { + List interfaces = new ArrayList<>(); + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + while (networkInterfaces.hasMoreElements()) { + NetworkInterface ni = networkInterfaces.nextElement(); + NativeNetworkInterfaceEO interfaceInfo = NativeNetworkInterfaceEO.builder() + .name(ni.getName()) + .displayName(ni.getDisplayName()) + .up(ni.isUp()) + .build(); + interfaces.add(interfaceInfo); + } + return interfaces; + } + + /** + * 获取所有开放端口 + */ + public List scanPortsUsingNmap() throws Exception { + List openPorts = new ArrayList<>(); + Process process = Runtime.getRuntime().exec("nmap -p 1-65535 localhost"); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + Pattern pattern = Pattern.compile("\\d+/tcp open"); // Adjust the regex based on nmap output format you expect + while ((line = reader.readLine()) != null) { + Matcher matcher = pattern.matcher(line); + if (matcher.find()) { // Assuming the output format is "port/protocol state" where state is "open" for open ports + String portStr = matcher.group(0).split("/")[0]; // Extract the port number part before "/tcp" or "/udp" etc. + openPorts.add(Integer.parseInt(portStr)); // Add the port number to the list of open ports + } + } + reader.close(); + return openPorts; + } + + public boolean verifyPort(int port, String threshold){ + String[] ports = threshold.split(";"); + for (int i = 0; i < ports.length; i++) { + String p = ports[i]; + int start = 0; + int end = 0; + String[] arr = p.split("-"); + start = Integer.parseInt(arr[0]); + if(arr.length == 2){ + end = Integer.parseInt(arr[1]); + } + if(start <= port && port <= end){ + return true; + } + } + return false; + } + + +} diff --git a/src/main/java/com/tongran/agent/client/utils/AgentDataUtil.java b/src/main/java/com/tongran/agent/client/utils/AgentDataUtil.java index e820eb9..d0be75d 100644 --- a/src/main/java/com/tongran/agent/client/utils/AgentDataUtil.java +++ b/src/main/java/com/tongran/agent/client/utils/AgentDataUtil.java @@ -1,9 +1,12 @@ package com.tongran.agent.client.utils; +import com.tongran.agent.client.core.eo.AlarmEO; + import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.HashMap; +import java.util.List; import java.util.Map; public class AgentDataUtil { @@ -23,4 +26,9 @@ public class AgentDataUtil { } return memInfo; } + + public static boolean hasAnyActiveAlarm(List alarmEOList) { + return alarmEOList.stream() + .anyMatch(AlarmEO::isCollect); + } }