From 0f649a2cfcc5a6ab05e8fdd61996e51eb2f99e4f Mon Sep 17 00:00:00 2001 From: gaoyutao Date: Tue, 30 Dec 2025 18:21:12 +0800 Subject: [PATCH] =?UTF-8?q?pppoe=E5=8A=9F=E8=83=BD=E5=A2=9E=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/config/ApplicationProperties.java | 1 + .../agent/client/core/enums/MsgEnum.java | 2 + .../client/core/eo/PppoeConfigSubEO.java | 21 ++ .../tongran/agent/client/core/eo/PppoeEO.java | 19 ++ .../tongran/agent/client/core/vo/CpuVO.java | 3 + .../agent/client/core/vo/MacVlanVO.java | 13 + .../scheduler/service/AppInitializer.java | 4 + .../scheduler/service/BusinessTasks.java | 39 +++ .../agent/client/service/AgentService.java | 5 + .../client/service/impl/AgentServiceImpl.java | 304 +++++++++++++++++- .../client/service/impl/CPUServiceImpl.java | 1 + 11 files changed, 408 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/tongran/agent/client/core/eo/PppoeConfigSubEO.java create mode 100644 src/main/java/com/tongran/agent/client/core/eo/PppoeEO.java create mode 100644 src/main/java/com/tongran/agent/client/core/vo/MacVlanVO.java diff --git a/src/main/java/com/tongran/agent/client/core/config/ApplicationProperties.java b/src/main/java/com/tongran/agent/client/core/config/ApplicationProperties.java index 7851edd..6c52bbd 100644 --- a/src/main/java/com/tongran/agent/client/core/config/ApplicationProperties.java +++ b/src/main/java/com/tongran/agent/client/core/config/ApplicationProperties.java @@ -16,4 +16,5 @@ public class ApplicationProperties { private String tmpPath; private String tempPath; private String frpPath; + private String poePath; } \ No newline at end of file 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 70536bc..50d8db1 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 @@ -69,6 +69,8 @@ public enum MsgEnum { 修改frp配置文件应答("UPDATE_FRP_RSP"), + macvlan状态上报("MACVLAN_STATUS_RSP"), + 多网IP探测上报("NETWORK_DETECT"); private String value; diff --git a/src/main/java/com/tongran/agent/client/core/eo/PppoeConfigSubEO.java b/src/main/java/com/tongran/agent/client/core/eo/PppoeConfigSubEO.java new file mode 100644 index 0000000..69616c9 --- /dev/null +++ b/src/main/java/com/tongran/agent/client/core/eo/PppoeConfigSubEO.java @@ -0,0 +1,21 @@ +package com.tongran.agent.client.core.eo; + +import lombok.Data; + +@Data +public class PppoeConfigSubEO { + /** 序号 */ + private Long serialNumber; + + /** VLANID */ + private Long vlanId; + + /** IPv4地址 */ + private String ipv4Address; + + /** IPv4掩码位数 */ + private Long ipv4MaskBits; + + /** IPv4网关 */ + private String ipv4Gateway; +} diff --git a/src/main/java/com/tongran/agent/client/core/eo/PppoeEO.java b/src/main/java/com/tongran/agent/client/core/eo/PppoeEO.java new file mode 100644 index 0000000..c5d37c9 --- /dev/null +++ b/src/main/java/com/tongran/agent/client/core/eo/PppoeEO.java @@ -0,0 +1,19 @@ +package com.tongran.agent.client.core.eo; + +import lombok.Data; + +import java.util.List; + +@Data +public class PppoeEO { + /** 是否启用PPPoE(0-否,1-是) */ + private Long pppoeEnabled; + + /** PPPoE配置方式 */ + private String pppoeConfigMode; + + /** PPPoE网卡名称 */ + private String pppoeInterface; + /** pppoe子表集合 */ + private List subList; +} diff --git a/src/main/java/com/tongran/agent/client/core/vo/CpuVO.java b/src/main/java/com/tongran/agent/client/core/vo/CpuVO.java index fe11f60..009a6a2 100644 --- a/src/main/java/com/tongran/agent/client/core/vo/CpuVO.java +++ b/src/main/java/com/tongran/agent/client/core/vo/CpuVO.java @@ -34,6 +34,9 @@ public class CpuVO implements Serializable { @Schema(description = "CPU数量") private int num; + @Schema(description = "CPU核数") + private int cores; + @Schema(description = "CPU正常运行时间:秒") private long normal; diff --git a/src/main/java/com/tongran/agent/client/core/vo/MacVlanVO.java b/src/main/java/com/tongran/agent/client/core/vo/MacVlanVO.java new file mode 100644 index 0000000..132704b --- /dev/null +++ b/src/main/java/com/tongran/agent/client/core/vo/MacVlanVO.java @@ -0,0 +1,13 @@ +package com.tongran.agent.client.core.vo; + +import lombok.Data; + +@Data +public class MacVlanVO { + /** 虚拟网卡id */ + private String vlanId; + /** 编号 */ + private String mid; + /** 状态 */ + private String status; +} diff --git a/src/main/java/com/tongran/agent/client/scheduler/service/AppInitializer.java b/src/main/java/com/tongran/agent/client/scheduler/service/AppInitializer.java index adb77fd..b43fbe3 100644 --- a/src/main/java/com/tongran/agent/client/scheduler/service/AppInitializer.java +++ b/src/main/java/com/tongran/agent/client/scheduler/service/AppInitializer.java @@ -104,6 +104,10 @@ public class AppInitializer implements CommandLineRunner { dynamicTaskService.scheduleTask("checkFrpc", businessTasks::checkFrpcTask, 15000, 600000); AssertLog.info("启动frpc状态上报定时任务 - 延迟: {}ms, 间隔: {}ms", 15000, 300000); dynamicTaskService.scheduleTask("upFrpcMsg", businessTasks::upFrpcMsgTask, 15000, 300000); + AssertLog.info("检测PppoE配置"); + agentService.handleRebootRecovery(); + AssertLog.info("启动macvlan状态上报定时任务 - 延迟: {}ms, 间隔: {}ms", 15000, 120000); + dynamicTaskService.scheduleTask("upMacvlanStatus", businessTasks::upMacvlanStatus, 15000, 120000); }else{ //未注册,发送注册 try { 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 528e6a7..217a21e 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 @@ -63,6 +63,7 @@ public class BusinessTasks { private final AtomicInteger checkFirewallTask = new AtomicInteger(0); private final AtomicInteger checkFrpcTask = new AtomicInteger(0); private final AtomicInteger upFrpcMsgTask = new AtomicInteger(0); + private final AtomicInteger upMacvlanStatusTask = new AtomicInteger(0); @@ -862,6 +863,10 @@ public class BusinessTasks { dynamicTaskService.scheduleTask("checkFrpc", businessTasks::checkFrpcTask, 15000, 600000); AssertLog.info("启动frpc状态上报定时任务 - 延迟: {}ms, 间隔: {}ms", 15000, 300000); dynamicTaskService.scheduleTask("upFrpcMsg", businessTasks::upFrpcMsgTask, 15000, 300000); + AssertLog.info("检测PppoE配置"); + agentService.handleRebootRecovery(); + AssertLog.info("启动macvlan状态上报定时任务 - 延迟: {}ms, 间隔: {}ms", 15000, 120000); + dynamicTaskService.scheduleTask("upMacvlanStatus", businessTasks::upMacvlanStatus, 15000, 120000); }else{ //未注册,发送注册 try { @@ -970,6 +975,40 @@ public class BusinessTasks { } } + /** + * 任务33:macvlan状态上报 + */ + @Async("taskExecutor") + public void upMacvlanStatus() { + int count = upMacvlanStatusTask.incrementAndGet(); + AssertLog.info("macvlan状态上报定时任务执行 - 时间: {},task #{}", LocalDateTime.now(), count); + // 判定客户端与服务端是否连接 + if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) { + if(StringUtils.isBlank(GlobalConfig.DEVICE_SN)){ + GlobalConfig.DEVICE_SN = AgentUtil.getDeviceSN(); + } + long timestamps = System.currentTimeMillis(); + timestamps = Math.round(timestamps / 1000.0); + List macVlanVOList = null; + try { + macVlanVOList = agentService.upMacvlanStatus(); + } catch (Exception e) { + e.printStackTrace(); + } + if(macVlanVOList != null && !macVlanVOList.isEmpty()){ + JSONObject objects = new JSONObject(); + objects.put("clientId", GlobalConfig.CLIENT_ID); + objects.put("macVlans", macVlanVOList); + objects.put("timestamp", timestamps); + Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.macvlan状态上报.getValue()).data(objects.toString()).build(); + sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message); + AssertLog.info("发送macvlan状态上报信息包={}",JSON.toJSONString(message)); + }else { + AssertLog.info("未检测到虚拟网卡,不进行macvlan状态上报"); + } + } + AssertLog.info("发送macvlan状态上报定时任务执行 - task #{} completed", count); + } 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 9c62085..e9ddd8c 100644 --- a/src/main/java/com/tongran/agent/client/service/AgentService.java +++ b/src/main/java/com/tongran/agent/client/service/AgentService.java @@ -1,6 +1,9 @@ package com.tongran.agent.client.service; import com.tongran.agent.client.core.eo.ScriptPolicyEO; +import com.tongran.agent.client.core.vo.MacVlanVO; + +import java.util.List; public interface AgentService { void cancelCollect(); @@ -42,4 +45,6 @@ public interface AgentService { void checkFrpc(); void upFrpcMsg(); + void handleRebootRecovery(); + List upMacvlanStatus(); } 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 797e7d2..c8bebde 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 @@ -7,11 +7,9 @@ import com.alibaba.fastjson2.TypeReference; import com.tongran.agent.client.core.config.ApplicationProperties; 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.CollectEO; -import com.tongran.agent.client.core.eo.FrpMsgEO; -import com.tongran.agent.client.core.eo.ScriptPolicyEO; +import com.tongran.agent.client.core.eo.*; import com.tongran.agent.client.core.session.SessionManager; +import com.tongran.agent.client.core.vo.MacVlanVO; import com.tongran.agent.client.netty.MultiTargetNettyClient; import com.tongran.agent.client.netty.config.AgentNettyConfig; import com.tongran.agent.client.netty.model.Message; @@ -23,6 +21,7 @@ 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.*; +import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; @@ -319,6 +318,10 @@ public class AgentServiceImpl implements AgentService { dynamicTaskService.scheduleTask("checkFrpc", businessTasks::checkFrpcTask, 15000, 600000); AssertLog.info("启动frpc状态上报定时任务 - 延迟: {}ms, 间隔: {}ms", 15000, 300000); dynamicTaskService.scheduleTask("upFrpcMsg", businessTasks::upFrpcMsgTask, 15000, 300000); + AssertLog.info("检测PppoE配置"); + handleRebootRecovery(); + AssertLog.info("启动macvlan状态上报定时任务 - 延迟: {}ms, 间隔: {}ms", 15000, 120000); + dynamicTaskService.scheduleTask("upMacvlanStatus", businessTasks::upMacvlanStatus, 15000, 120000); } @Override @@ -898,8 +901,173 @@ public class AgentServiceImpl implements AgentService { restartFrpc(properties.getFrpPath()); } } + if(jsonObject.containsKey("pppoeConfig")){ + String pppoeConfig = jsonObject.getString("pppoeConfig"); + PppoeEO pppoeEO = JSON.parseObject(pppoeConfig, PppoeEO.class); + handlePppoeConfig(pppoeEO); + } } + /** + * 处理PPPoE配置 + * @param pppoeEO PPPoE配置对象 + */ + private void handlePppoeConfig(PppoeEO pppoeEO) { + if (pppoeEO == null) { + AssertLog.error("PPPoE配置对象为空"); + return; + } + + Long enable = pppoeEO.getPppoeEnabled(); + if (enable == null) { + AssertLog.error("PPPoE启用状态为空"); + return; + } + + String csvFilePath = properties.getPoePath() + "/macvlan_vlan.csv"; + + if (enable == 1L) { + // 启用PPPoE时生成CSV文件 + try { + generateCsvFile(pppoeEO, csvFilePath); + updateAndExecuteScript(pppoeEO.getPppoeInterface(), csvFilePath); + } catch (Exception e) { + AssertLog.error("生成CSV文件或执行脚本失败: {}", e.getMessage()); + } + } else if (enable == 0L) { + // 禁用PPPoE时删除CSV文件 + try { + deleteCsvFile(csvFilePath); + } catch (Exception e) { + AssertLog.error("删除CSV文件失败: {}", e.getMessage()); + } + } else { + AssertLog.error("无效的PPPoE启用状态: {}", enable); + } + } + + /** + * 生成CSV文件 + * @param pppoeEO PPPoE配置对象 + * @param csvFilePath CSV文件路径 + */ + private void generateCsvFile(PppoeEO pppoeEO, String csvFilePath) { + if (pppoeEO.getSubList() == null || pppoeEO.getSubList().isEmpty()) { + AssertLog.error("PPPoE子配置列表为空"); + return; + } + + List csvLines = new ArrayList<>(); + for (PppoeConfigSubEO subConfig : pppoeEO.getSubList()) { + String line = String.format("%d,%d,%s,%d,%s", + subConfig.getVlanId(), + subConfig.getSerialNumber(), + subConfig.getIpv4Address(), + subConfig.getIpv4MaskBits(), + subConfig.getIpv4Gateway()); + csvLines.add(line); + } + + try { + // 写入CSV文件 + FileUtils.writeLines(new File(csvFilePath), "UTF-8", csvLines); + AssertLog.info("CSV文件生成成功: {}", csvFilePath); + } catch (IOException e) { + AssertLog.error("写入CSV文件失败: {}", e.getMessage()); + } + } + + /** + * 删除CSV文件 + * @param csvFilePath CSV文件路径 + */ + private void deleteCsvFile(String csvFilePath) { + File csvFile = new File(csvFilePath); + if (csvFile.exists()) { + try { + FileUtils.forceDelete(csvFile); + AssertLog.info("CSV文件删除成功: {}", csvFilePath); + } catch (IOException e) { + AssertLog.error("删除CSV文件失败: {}", e.getMessage()); + } + } else { + AssertLog.info("CSV文件不存在: {}", csvFilePath); + } + } + + /** + * 更新脚本参数并执行 + * @param interfaceName 网卡名称 + * @param csvFilePath CSV文件路径 + */ + private void updateAndExecuteScript(String interfaceName, String csvFilePath) { + String scriptPath = properties.getPoePath() + "/multi_wan_conntrack.sh"; + File scriptFile = new File(scriptPath); + + if (!scriptFile.exists()) { + AssertLog.error("脚本文件不存在: {}", scriptPath); + return; + } + + try { + String scriptContent = FileUtils.readFileToString(scriptFile, "UTF-8"); + + // 按行处理,替换参数 + String[] lines = scriptContent.split("\n"); + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + + // 替换PARENT_IF开头的行 + if (line.trim().startsWith("PARENT_IF=")) { + lines[i] = String.format("PARENT_IF=\"%s\"", interfaceName); + } + + // 替换CSV开头的行 + if (line.trim().startsWith("CSV=")) { + lines[i] = String.format("CSV=\"%s\"", csvFilePath); + } + } + + // 重新组合内容 + scriptContent = String.join("\n", lines); + FileUtils.writeStringToFile(scriptFile, scriptContent, "UTF-8"); + + // 给脚本添加执行权限 + if (!scriptFile.canExecute()) { + scriptFile.setExecutable(true); + } + + // 修改这里:使用bash执行脚本,而不是source命令 + ProcessBuilder pb = new ProcessBuilder("/bin/bash", scriptPath); + pb.redirectErrorStream(true); + + // 设置工作目录 + pb.directory(new File(properties.getPoePath())); + + Process process = pb.start(); + + // 读取脚本输出 + StringBuilder output = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + String line; + while ((line = reader.readLine()) != null) { + output.append(line).append("\n"); + AssertLog.info("脚本输出: {}", line); + } + } + + int exitCode = process.waitFor(); + + if (exitCode == 0) { + AssertLog.info("脚本执行成功: {}", scriptPath); + } else { + AssertLog.error("脚本执行失败,退出码: {},输出: {}", exitCode, output.toString()); + } + + } catch (Exception e) { + AssertLog.error("脚本执行失败: {}", e.getMessage()); + } + } /** 启动frpc服务 */ private void restartFrpc(String frpPath) { long timestamp = System.currentTimeMillis() / 1000; @@ -2099,4 +2267,132 @@ public class AgentServiceImpl implements AgentService { return false; } } + /** + * 重启恢复处理 + */ + @Override + public void handleRebootRecovery() { + String csvFilePath = properties.getPoePath() + "/macvlan_vlan.csv"; + File csvFile = new File(csvFilePath); + + // 检查CSV文件是否存在 + if (!csvFile.exists()) { + AssertLog.info("CSV文件不存在,不执行脚本"); + return; + } + + AssertLog.info("CSV文件存在: {}", csvFilePath); + + // 从CSV读取macvlan网卡名称 + String macvlanInterface = getFirstMacvlanFromCsv(csvFilePath); + if (macvlanInterface == null) { + AssertLog.error("无法从CSV文件中解析出macvlan网卡名称"); + return; + } + + // 检查网卡是否存在 + boolean interfaceExists = checkInterfaceExists(macvlanInterface); + + if (!interfaceExists) { + // CSV存在 && 网卡不存在 → 执行脚本 + AssertLog.info("macvlan网卡不存在: {},执行脚本", macvlanInterface); + updateAndExecuteScript("eth0", csvFilePath); + } else { + // 其他情况都不执行 + AssertLog.info("macvlan网卡已存在: {},不执行脚本", macvlanInterface); + } + } + @Override + public List upMacvlanStatus() { + String csvFilePath = properties.getPoePath() + "/macvlan_vlan.csv"; + List list = new ArrayList<>(); + try { + List lines = FileUtils.readLines(new File(csvFilePath), "UTF-8"); + for (String line : lines) { + line = line.trim(); + if (line.isEmpty() || line.startsWith("#")) { + continue; // 跳过空行和注释 + } + String[] parts = line.split(","); + if (parts.length >= 2) { // 至少需要vlan和mid + String vlan = parts[0].trim(); + String mid = parts[1].trim(); + String interfaceName = String.format("xdbvl.%s.%s", vlan, mid); + boolean interExites = checkInterfaceExists(interfaceName); + if(interExites){ + // 检测与外网的连通性 + boolean status = getmacVlanStatus(interfaceName); + MacVlanVO macVlanVO = new MacVlanVO(); + macVlanVO.setVlanId(vlan); + macVlanVO.setMid(mid); + macVlanVO.setStatus(status?"1":"0"); + list.add(macVlanVO); + } + } + } + } catch (Exception e) { + AssertLog.error("读取CSV文件失败: {}", e.getMessage()); + } + return list; + } + + /** + * 从CSV读取第一个macvlan网卡名称 + */ + private String getFirstMacvlanFromCsv(String csvFilePath) { + try { + List lines = FileUtils.readLines(new File(csvFilePath), "UTF-8"); + for (String line : lines) { + line = line.trim(); + if (line.isEmpty() || line.startsWith("#")) { + continue; // 跳过空行和注释 + } + String[] parts = line.split(","); + if (parts.length >= 2) { // 至少需要vlan和mid + String vlan = parts[0].trim(); + String mid = parts[1].trim(); + return String.format("xdbvl.%s.%s", vlan, mid); + } + } + } catch (Exception e) { + AssertLog.error("读取CSV文件失败: {}", e.getMessage()); + } + return null; + } + private boolean getmacVlanStatus(String interfaceName) { + try { + ProcessBuilder pb = new ProcessBuilder( + "ping", "-I", interfaceName, "-c", "2", "-W", "2", "-4", "www.baidu.com" + ); + pb.redirectErrorStream(true); + + Process process = pb.start(); + boolean finished = process.waitFor(5, TimeUnit.SECONDS); + + if (!finished) { + process.destroy(); + AssertLog.warn("接口 {} ping超时", interfaceName); + return false; + } + + return process.exitValue() == 0; + + } catch (Exception e) { + AssertLog.error("接口 {} ping失败: {}", interfaceName, e.getMessage()); + return false; + } + } + + /** + * 检查网卡是否存在 + */ + private boolean checkInterfaceExists(String interfaceName) { + try { + ProcessBuilder pb = new ProcessBuilder("ip", "link", "show", interfaceName); + Process process = pb.start(); + return process.waitFor() == 0; + } catch (Exception e) { + return false; + } + } } diff --git a/src/main/java/com/tongran/agent/client/service/impl/CPUServiceImpl.java b/src/main/java/com/tongran/agent/client/service/impl/CPUServiceImpl.java index d173799..eb5e86b 100644 --- a/src/main/java/com/tongran/agent/client/service/impl/CPUServiceImpl.java +++ b/src/main/java/com/tongran/agent/client/service/impl/CPUServiceImpl.java @@ -27,6 +27,7 @@ public class CPUServiceImpl implements CPUService { System.out.println("========================================================="); // 1. CPU基本信息 cpuVO.setNum(processor.getPhysicalProcessorCount()); // CUP数量 + cpuVO.setCores(processor.getLogicalProcessorCount()); // CUP核数 System.out.println("=== CPU基本信息 ==="); System.out.println("CPU型号: " + processor.getProcessorIdentifier().getName()); System.out.println("物理核心数: " + processor.getPhysicalProcessorCount());