pppoe功能增加

This commit is contained in:
gaoyutao
2025-12-30 18:21:12 +08:00
parent 2ad6ea2ad5
commit 0f649a2cfc
11 changed files with 408 additions and 4 deletions
@@ -16,4 +16,5 @@ public class ApplicationProperties {
private String tmpPath;
private String tempPath;
private String frpPath;
private String poePath;
}
@@ -69,6 +69,8 @@ public enum MsgEnum {
修改frp配置文件应答("UPDATE_FRP_RSP"),
macvlan状态上报("MACVLAN_STATUS_RSP"),
多网IP探测上报("NETWORK_DETECT");
private String value;
@@ -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;
}
@@ -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<PppoeConfigSubEO> subList;
}
@@ -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;
@@ -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;
}
@@ -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 {
@@ -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 {
}
}
/**
* 任务33macvlan状态上报
*/
@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<MacVlanVO> 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);
}
@@ -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<MacVlanVO> upMacvlanStatus();
}
@@ -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<String> 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<MacVlanVO> upMacvlanStatus() {
String csvFilePath = properties.getPoePath() + "/macvlan_vlan.csv";
List<MacVlanVO> list = new ArrayList<>();
try {
List<String> 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<String> 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;
}
}
}
@@ -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());