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 4837580..47fa5cc 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 @@ -15,7 +15,13 @@ import java.util.concurrent.ConcurrentHashMap; */ public class GlobalConfig { - + /** + * pppoe配置方式(1静态ip配置,2非saas平台配置) + */ + public static String PPPOEMODE = ""; + /** + * 业务网卡名称 + */ public static String NETNAME = ""; /** * 服务启动时间 diff --git a/src/main/java/com/tongran/agent/client/core/vo/NetworkInterfaceInfo.java b/src/main/java/com/tongran/agent/client/core/vo/NetworkInterfaceInfo.java index abf4f7e..5781b79 100644 --- a/src/main/java/com/tongran/agent/client/core/vo/NetworkInterfaceInfo.java +++ b/src/main/java/com/tongran/agent/client/core/vo/NetworkInterfaceInfo.java @@ -24,6 +24,7 @@ public class NetworkInterfaceInfo { String province; // 省 String city; // 市 String ipv6; // 市 + String status; // 与外网连通状态 // 如果是子接口,存储父接口名称 private String parentInterface; 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 b43fbe3..b529343 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 @@ -108,6 +108,9 @@ public class AppInitializer implements CommandLineRunner { agentService.handleRebootRecovery(); AssertLog.info("启动macvlan状态上报定时任务 - 延迟: {}ms, 间隔: {}ms", 15000, 120000); dynamicTaskService.scheduleTask("upMacvlanStatus", businessTasks::upMacvlanStatus, 15000, 120000); + // 检测PppoE配置模式配置 + AssertLog.info("检测PppoE配置模式配置"); + agentService.checkPppoEMode(); }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 217a21e..c89fa18 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 @@ -867,6 +867,9 @@ public class BusinessTasks { agentService.handleRebootRecovery(); AssertLog.info("启动macvlan状态上报定时任务 - 延迟: {}ms, 间隔: {}ms", 15000, 120000); dynamicTaskService.scheduleTask("upMacvlanStatus", businessTasks::upMacvlanStatus, 15000, 120000); + // 检测PppoE配置模式配置 + AssertLog.info("检测PppoE配置模式配置"); + agentService.checkPppoEMode(); }else{ //未注册,发送注册 try { 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 e9ddd8c..c166bff 100644 --- a/src/main/java/com/tongran/agent/client/service/AgentService.java +++ b/src/main/java/com/tongran/agent/client/service/AgentService.java @@ -37,6 +37,7 @@ public interface AgentService { void addFirewall(String netName); void checkFirewall(); + void checkPppoEMode(); void checkAndAddFirewallPeriodically(); @@ -47,4 +48,5 @@ public interface AgentService { 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 fa3e64c..5fa1746 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 @@ -10,6 +10,7 @@ import com.tongran.agent.client.core.enums.MsgEnum; 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.core.vo.NetworkInterfaceInfo; import com.tongran.agent.client.netty.MultiTargetNettyClient; import com.tongran.agent.client.netty.config.AgentNettyConfig; import com.tongran.agent.client.netty.model.Message; @@ -324,6 +325,9 @@ public class AgentServiceImpl implements AgentService { handleRebootRecovery(); AssertLog.info("启动macvlan状态上报定时任务 - 延迟: {}ms, 间隔: {}ms", 15000, 120000); dynamicTaskService.scheduleTask("upMacvlanStatus", businessTasks::upMacvlanStatus, 15000, 120000); + // 检测PppoE配置模式配置 + AssertLog.info("检测PppoE配置模式配置"); + checkPppoEMode(); } @Override @@ -925,6 +929,39 @@ public class AgentServiceImpl implements AgentService { AssertLog.error("PPPoE启用状态为空"); return; } + String pppoeConfigMode = pppoeEO.getPppoeConfigMode(); + if (pppoeConfigMode == null) { + AssertLog.error("PPPoE配置方式为空"); + return; + } + if("2".equals(pppoeConfigMode)){ + // 保存配置方式到pppoemode.conf + if (!pppoeConfigMode.equals(GlobalConfig.PPPOEMODE)) { + try { + // 1. 将pppoe配置方式写入配置文件 + String[] lines = { + "# pppoe配置方式配置文件", + "# 生成时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), + "# pppoe配置方式(1静态ip配置,2非saas平台配置)", + "pppoeConfigMode=" + pppoeConfigMode, + "", + "# 配置元信息", + "lastUpdateTime=" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), + }; + + // 检查目录并写入配置文件 + if (AdvancedAsyncDownloader.createSingleDirectoryIfNotExists(properties.getConfPath())) { + AgentUtil.bufferedWriter(properties.getConfPath() + "/pppoemode.conf", lines); + } + + // 更新全局变量 + GlobalConfig.PPPOEMODE = pppoeConfigMode; + + } catch (Exception e) { + AssertLog.info("配置PPPOE配置方式时发生错误: {}", e.getMessage()); + } + } + } String csvFilePath = properties.getPoePath() + "/macvlan_vlan.csv"; @@ -934,17 +971,17 @@ public class AgentServiceImpl implements AgentService { generateCsvFile(pppoeEO, csvFilePath); updateAndExecuteScript(pppoeEO.getPppoeInterface(), csvFilePath); } catch (Exception e) { - AssertLog.error("生成CSV文件或执行脚本失败: {}", e.getMessage()); + AssertLog.info("生成CSV文件或执行脚本失败: {}", e.getMessage()); } } else if (enable == 0L) { // 禁用PPPoE时删除CSV文件 try { deleteCsvFile(csvFilePath); } catch (Exception e) { - AssertLog.error("删除CSV文件失败: {}", e.getMessage()); + AssertLog.info("删除CSV文件失败: {}", e.getMessage()); } } else { - AssertLog.error("无效的PPPoE启用状态: {}", enable); + AssertLog.info("无效的PPPoE启用状态: {}", enable); } } @@ -1012,9 +1049,43 @@ public class AgentServiceImpl implements AgentService { } try { - String scriptContent = FileUtils.readFileToString(scriptFile, "UTF-8"); + // 读取原始CSV中的所有网卡信息 + List allInterfaceInfo = getMacvlanInfoFromCsv(csvFilePath); - // 按行处理,替换参数 + if (allInterfaceInfo.isEmpty()) { + AssertLog.error("CSV文件中没有有效的网卡配置"); + return; + } + + // 检查每个网卡是否存在,收集不存在的网卡信息 + List missingInterfaceInfo = new ArrayList<>(); + for (String interfaceInfo : allInterfaceInfo) { + String macvlanName = extractMacvlanName(interfaceInfo); + if (macvlanName != null) { + if (!checkInterfaceExists(macvlanName, interfaceInfo)) { + missingInterfaceInfo.add(interfaceInfo); + AssertLog.info("网卡 {} 需要重新配置,将添加到处理列表", macvlanName); + } else { + AssertLog.info("网卡 {} 已存在且配置正确,跳过处理", macvlanName); + } + } + } + + // 如果所有网卡都存在,不执行脚本 + if (missingInterfaceInfo.isEmpty()) { + AssertLog.info("所有网卡已存在,跳过脚本执行"); + return; + } + + // 创建只包含不存在网卡的新CSV文件 + String tempCsvPath = createTempCsvForMissingInterfaces(missingInterfaceInfo); + if (tempCsvPath == null) { + AssertLog.error("创建临时CSV文件失败"); + return; + } + + // 读取并修改脚本 + String scriptContent = FileUtils.readFileToString(scriptFile, "UTF-8"); String[] lines = scriptContent.split("\n"); for (int i = 0; i < lines.length; i++) { String line = lines[i]; @@ -1026,7 +1097,7 @@ public class AgentServiceImpl implements AgentService { // 替换CSV开头的行 if (line.trim().startsWith("CSV=")) { - lines[i] = String.format("CSV=\"%s\"", csvFilePath); + lines[i] = String.format("CSV=\"%s\"", tempCsvPath); } } @@ -1039,11 +1110,9 @@ public class AgentServiceImpl implements AgentService { 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(); @@ -1066,10 +1135,72 @@ public class AgentServiceImpl implements AgentService { AssertLog.error("脚本执行失败,退出码: {},输出: {}", exitCode, output.toString()); } + // 清理临时文件 +// File tempFile = new File(tempCsvPath); +// if (tempFile.exists()) { +// FileUtils.deleteQuietly(tempFile); +// } + } catch (Exception e) { AssertLog.error("脚本执行失败: {}", e.getMessage()); } } + + /** + * 从CSV文件中读取所有网卡信息 + */ + private List getMacvlanInfoFromCsv(String csvFilePath) { + List interfaceInfoList = 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; // 跳过空行和注释 + } + interfaceInfoList.add(line); + } + } catch (Exception e) { + AssertLog.error("读取CSV文件失败: {}", e.getMessage()); + } + return interfaceInfoList; + } + + /** + * 从CSV行中提取macvlan网卡名称 + */ + private String extractMacvlanName(String csvLine) { + try { + String[] parts = csvLine.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(), csvLine); + } + return null; + } + + /** + * 创建包含不存在网卡的临时CSV文件 + */ + private String createTempCsvForMissingInterfaces(List missingInterfaceInfo) { + try { + String tempFilePath = properties.getPoePath() + "/macvlan_vlan_use.csv"; + + File tempFile = new File(tempFilePath); + FileUtils.writeLines(tempFile, "UTF-8", missingInterfaceInfo); + + AssertLog.info("创建临时CSV文件: {},包含 {} 个不存在的网卡", tempFilePath, missingInterfaceInfo.size()); + return tempFilePath; + + } catch (Exception e) { + AssertLog.error("创建临时CSV文件失败: {}", e.getMessage()); + return null; + } + } /** 启动frpc服务 */ private void restartFrpc(String frpPath) { long timestamp = System.currentTimeMillis() / 1000; @@ -2003,6 +2134,27 @@ public class AgentServiceImpl implements AgentService { AssertLog.debug("业务网卡配置文件不存在: {}", businessNetFile.getPath()); } } + @Override + public void checkPppoEMode() { + File pppoemode = new File(properties.getConfPath() + "/pppoemode.conf"); + if (pppoemode.exists()) { + Properties props = new Properties(); + try (InputStream input = Files.newInputStream(pppoemode.toPath())) { + props.load(input); + + String pppoeConfigMode = props.getProperty("pppoeConfigMode"); + if (StringUtils.isNotBlank(pppoeConfigMode)) { + GlobalConfig.PPPOEMODE = pppoeConfigMode; + AssertLog.info("应用启动时加载pppoe配置模式配置成功"); + } + + } catch (Exception e) { + AssertLog.error("应用启动时加载pppoe配置模式配置异常:{}", e.getMessage()); + } + } else { + AssertLog.debug("pppoe配置模式配置文件不存在: {}", pppoemode.getPath()); + } + } public void caseTypeBySystem(String type, int interval, boolean collect){ @@ -2306,34 +2458,42 @@ public class AgentServiceImpl implements AgentService { } @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); + if(!"2".equals(GlobalConfig.PPPOEMODE)){ + String csvFilePath = properties.getPoePath() + "/macvlan_vlan.csv"; + File csvFile = new File(csvFilePath); + // 检查文件是否存在 + if (!csvFile.exists()) { + AssertLog.info("CSV文件不存在: {}", csvFilePath); + return list; // 文件不存在,返回空列表 + } + 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 = NetworkInterfaceUtil.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()); } - } catch (Exception e) { - AssertLog.error("读取CSV文件失败: {}", e.getMessage()); } return list; } @@ -2361,29 +2521,6 @@ public class AgentServiceImpl implements AgentService { } 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; - } - } /** * 检查网卡是否存在 @@ -2397,4 +2534,97 @@ public class AgentServiceImpl implements AgentService { return false; } } + /** + * 检查网卡是否存在且IP配置是否正确 + */ + private boolean checkInterfaceExists(String interfaceName, String csvLine) { + try { + // 1. 检查网卡是否存在 + ProcessBuilder pb = new ProcessBuilder("ip", "link", "show", interfaceName); + Process process = pb.start(); + int exitCode = process.waitFor(); + + if (exitCode != 0) { + return false; // 网卡不存在 + } + + // 2. 如果网卡存在,检查IP配置 + String[] params = csvLine.split(","); + if (params.length >= 3) { // 确保有第三个参数(IP) + String expectedIp = params[2].trim(); + if (expectedIp.isEmpty() || expectedIp.equals("-") || expectedIp.equals("dhcp")) { + AssertLog.info("网卡 {} 已存在,IP配置为 {},无需检查", interfaceName, expectedIp); + return true; // IP为-、空或dhcp,不检查具体IP + } + + // 获取网卡当前的IP地址 + String currentIp = getInterfaceIp(interfaceName); + if (currentIp == null) { + AssertLog.warn("网卡 {} 存在,但无法获取当前IP", interfaceName); + return false; // 无法获取IP,认为需要重新配置 + } + + // 比较IP是否一致 + if (currentIp.equals(expectedIp)) { + AssertLog.info("网卡 {} 已存在且IP配置正确: {}", interfaceName, currentIp); + return true; + } else { + AssertLog.info("网卡 {} 存在但IP不匹配,当前IP: {},期望IP: {}", + interfaceName, currentIp, expectedIp); + return false; + } + } + + return true; // 没有指定IP参数,认为配置正确 + + } catch (Exception e) { + AssertLog.error("检查网卡 {} 存在失败: {}", interfaceName, e.getMessage()); + return false; + } + } + + /** + * 获取网卡的IP地址 + */ + private String getInterfaceIp(String interfaceName) { + try { + ProcessBuilder pb = new ProcessBuilder("ip", "-4", "addr", "show", interfaceName); + 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"); + } + } + + int exitCode = process.waitFor(); + if (exitCode != 0) { + return null; + } + + // 解析IP地址,格式如: inet 192.168.1.100/24 brd 192.168.1.255 scope global eth0 + String result = output.toString(); + String[] lines = result.split("\n"); + for (String line : lines) { + line = line.trim(); + if (line.startsWith("inet ")) { + String[] parts = line.split("\\s+"); + if (parts.length >= 2) { + String ipWithCidr = parts[1]; + // 去掉CIDR后缀 + return ipWithCidr.split("/")[0]; + } + } + } + + return null; // 没有找到IP地址 + + } catch (Exception e) { + AssertLog.error("获取网卡 {} 的IP失败: {}", interfaceName, e.getMessage()); + return null; + } + } } diff --git a/src/main/java/com/tongran/agent/client/utils/NetworkInterfaceUtil.java b/src/main/java/com/tongran/agent/client/utils/NetworkInterfaceUtil.java index be6a2d7..da254ec 100644 --- a/src/main/java/com/tongran/agent/client/utils/NetworkInterfaceUtil.java +++ b/src/main/java/com/tongran/agent/client/utils/NetworkInterfaceUtil.java @@ -6,6 +6,7 @@ import org.apache.commons.lang3.StringUtils; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -14,6 +15,30 @@ import java.util.regex.Pattern; */ public class NetworkInterfaceUtil { + public static 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; + } + } + /** * 收集所有 Ethernet 类型网卡信息 */ @@ -185,6 +210,9 @@ public class NetworkInterfaceUtil { if (parent.getSubInterfaces() == null) { parent.setSubInterfaces(new ArrayList<>()); } + if(child.getIpv4() != null){ + child.setStatus(getmacVlanStatus(child.getName())?"1":"0"); + } parent.getSubInterfaces().add(child); AssertLog.info("子接口 {} 关联到父接口 {}", child.getName(), parentName); } else {