From 1485d5d46c2295c2a6c41e14aaddafc7a01b0365 Mon Sep 17 00:00:00 2001 From: qiminbao Date: Mon, 27 Oct 2025 10:27:48 +0800 Subject: [PATCH] =?UTF-8?q?v1.1=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/core/config/GlobalConfig.java | 1 + .../agent/client/core/eo/ScriptPolicyEO.java | 2 + .../client/netty/enpoint/AgentEndpoint.java | 20 +++ .../scheduler/service/AppInitializer.java | 33 ++-- .../scheduler/service/BusinessTasks.java | 2 +- .../scheduler/task/SpecificTimeRequest.java | 1 + .../task/SpecificTimeTaskService.java | 14 +- .../agent/client/service/AgentService.java | 4 + .../client/service/impl/AgentServiceImpl.java | 145 +++++++++++++++++- .../tongran/agent/client/utils/AgentUtil.java | 28 ++++ .../agent/client/utils/NetworkUtil.java | 27 ++++ 11 files changed, 252 insertions(+), 25 deletions(-) create mode 100644 src/main/java/com/tongran/agent/client/utils/NetworkUtil.java 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 3c179ff..4c11ad2 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 @@ -43,6 +43,7 @@ public class GlobalConfig { public static long MONITOR_TIME = 0L; public static long SCRIPT_TIME = 0L; public static long VERSION_TIME = 0L; + public static long ROUTE_TIME = 0L; /** * 采集标识 */ diff --git a/src/main/java/com/tongran/agent/client/core/eo/ScriptPolicyEO.java b/src/main/java/com/tongran/agent/client/core/eo/ScriptPolicyEO.java index e720707..926386a 100644 --- a/src/main/java/com/tongran/agent/client/core/eo/ScriptPolicyEO.java +++ b/src/main/java/com/tongran/agent/client/core/eo/ScriptPolicyEO.java @@ -15,6 +15,8 @@ public class ScriptPolicyEO implements Serializable { private static final long serialVersionUID = -1267013167162440612L; + private String scriptId; + private String policyName; //文件类型为1、外网HTTP(S)时必传 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 cf3ddf5..087c926 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 @@ -56,6 +56,25 @@ public class AgentEndpoint { } //注册成功,更新外置文件注册标识 if(resCode == 1){ + String addRoute = ""; + if(object.containsKey("addRoute")) { + addRoute = object.getString("addRoute"); + AssertLog.info("注册成功,路由addRoute={}",addRoute); + if(StringUtils.isNotBlank(addRoute)){ + JSONObject addRouteJson = JSONObject.parseObject(addRoute); + String name = ""; + String gateway = ""; + if(addRouteJson.containsKey("name")){ + name = addRouteJson.getString("name"); + } + if(addRouteJson.containsKey("gateway")){ + gateway = addRouteJson.getString("gateway"); + } + if(StringUtils.isNotBlank(name) && StringUtils.isNotBlank(gateway)){ + agentService.addRoute(name,gateway); + } + } + } //检查外置目录是否存在 if(AdvancedAsyncDownloader.createSingleDirectoryIfNotExists(properties.getConfPath())){ String[] lines = { @@ -67,6 +86,7 @@ public class AgentEndpoint { //取消注册定时任务 agentService.cancelTask("register"); agentService.start(); + } return null; } 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 94367bb..483707f 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 @@ -16,7 +16,6 @@ import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; -import java.util.concurrent.TimeUnit; @Component public class AppInitializer implements CommandLineRunner { @@ -57,23 +56,25 @@ public class AppInitializer implements CommandLineRunner { if(success){ AssertLog.info("连接成功,发送初始连接消息"); //连接成功,发送初始连接消息 - long timestamp = System.currentTimeMillis(); - timestamp = Math.round(timestamp / 1000.0); - JSONObject object = new JSONObject(); - object.put("clientId", GlobalConfig.CLIENT_ID); - object.put("sn", GlobalConfig.DEVICE_SN); - object.put("timestamp", timestamp); - Message msg = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.建立连接.getValue()).data(object.toString()).build(); - // 将对象转为 JSON 字符串 - client.sendMessages(GlobalConfig.CLIENT_ID, msg); - // 等待3秒 - try { - TimeUnit.SECONDS.sleep(3); - } catch (InterruptedException e) { - e.printStackTrace(); - } +// long timestamp = System.currentTimeMillis(); +// timestamp = Math.round(timestamp / 1000.0); +// JSONObject object = new JSONObject(); +// object.put("clientId", GlobalConfig.CLIENT_ID); +// object.put("sn", GlobalConfig.DEVICE_SN); +// object.put("timestamp", timestamp); +// Message msg = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.建立连接.getValue()).data(object.toString()).build(); +// // 将对象转为 JSON 字符串 +// client.sendMessages(GlobalConfig.CLIENT_ID, msg); +// // 等待3秒 +// try { +// TimeUnit.SECONDS.sleep(3); +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } //判断是否发送注册信息 if(GlobalConfig.isRegister){ + //添加路由 + agentService.addRoute(null,null); //已注册,发送心跳 // 创建心跳定时任务 AssertLog.info("启动心跳定时任务 - 延迟: {}ms, 间隔: {}ms", 15000, 30000); 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 2e916dd..754f030 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 @@ -765,8 +765,8 @@ public class BusinessTasks { success = agentService.connection(); } if(success){ + AssertLog.info("连接成功,发送初始连接消息"); try { - // 判定客户端与服务端是否连接 if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) { List infos = AgentUtil.collectNetworkInfo(); JSONObject object = new JSONObject(); diff --git a/src/main/java/com/tongran/agent/client/scheduler/task/SpecificTimeRequest.java b/src/main/java/com/tongran/agent/client/scheduler/task/SpecificTimeRequest.java index db78e36..4fc599c 100644 --- a/src/main/java/com/tongran/agent/client/scheduler/task/SpecificTimeRequest.java +++ b/src/main/java/com/tongran/agent/client/scheduler/task/SpecificTimeRequest.java @@ -16,6 +16,7 @@ public class SpecificTimeRequest { private String taskName; private String taskData; + private String scriptId; private String clientId; private String dataType; diff --git a/src/main/java/com/tongran/agent/client/scheduler/task/SpecificTimeTaskService.java b/src/main/java/com/tongran/agent/client/scheduler/task/SpecificTimeTaskService.java index ad02e9b..cdb6b35 100644 --- a/src/main/java/com/tongran/agent/client/scheduler/task/SpecificTimeTaskService.java +++ b/src/main/java/com/tongran/agent/client/scheduler/task/SpecificTimeTaskService.java @@ -102,14 +102,17 @@ public class SpecificTimeTaskService { 100, TimeUnit.SECONDS); future.thenAccept(result -> { JSONObject jsonObject = new JSONObject(); + jsonObject.put("scriptId", request.getScriptId()); jsonObject.put("command", request.getTaskData()); jsonObject.put("resOut", result.getOutput()); System.out.println("JSON: " + jsonObject.toJSONString()); // 注意:toJSONString() - + long timestamps = System.currentTimeMillis(); + timestamps = Math.round(timestamps / 1000.0); JSONObject json = new JSONObject(); json.put("resCode",1); json.put("resMsg", ""); json.put("result", jsonObject.toJSONString()); + json.put("timestamp",timestamps); Message message = Message.builder().clientId(request.getClientId()).dataType(request.getDataType()).data(jsonObject.toJSONString()).build(); if (Objects.nonNull(sessionManager.getSessionById(request.getClientId()))) { System.out.println("发送执行结果: " + json.toJSONString()); // 注意:toJSONString() @@ -117,10 +120,17 @@ public class SpecificTimeTaskService { } }).exceptionally(ex -> { System.err.println("执行失败: " + ex.getMessage()); + JSONObject rse = new JSONObject(); + rse.put("scriptId", request.getScriptId()); + rse.put("command", request.getTaskData()); + rse.put("resOut", "脚本执行失败"); + long timestamps = System.currentTimeMillis(); + timestamps = Math.round(timestamps / 1000.0); JSONObject json = new JSONObject(); json.put("resCode",0); json.put("resMsg", "执行失败:Policy execute filed"); - json.put("result", ""); + json.put("result", rse.toString()); + json.put("timestamp",timestamps); Message message = Message.builder().clientId(request.getClientId()).dataType(request.getDataType()).data(json.toJSONString()).build(); if (Objects.nonNull(sessionManager.getSessionById(request.getClientId()))) { sessionManager.writeAndFlush(sessionManager.getSessionById(request.getClientId()).getChannel(), message); 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 c9adb9b..73fc303 100644 --- a/src/main/java/com/tongran/agent/client/service/AgentService.java +++ b/src/main/java/com/tongran/agent/client/service/AgentService.java @@ -22,4 +22,8 @@ public interface AgentService { void sendMessage(String type, String data); boolean connection(); + + void addRoute(String name, String gateway); + + void dellRoute(String name, String gateway); } 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 1895940..770b1e0 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 @@ -30,8 +30,7 @@ import javax.annotation.Resource; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.file.*; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -159,6 +158,7 @@ public class AgentServiceImpl implements AgentService { .taskId("") .taskName(policy.getPolicyName()) .taskData(policy.getCommandParams()) + .scriptId(policy.getScriptId()) .specificDateTime(AgentUtil.toLocalDateTime(policy.getPolicyTime(),true)) .clientId(clientId) .dataType(dataType) @@ -196,7 +196,7 @@ public class AgentServiceImpl implements AgentService { String SCRIPT_PATH = properties.getScriptPath()+"/rollback-tragent.sh"; AgentDataUtil.chmod(SCRIPT_PATH,"775"); AgentUtil.scheduleScriptIn3Minutes(SCRIPT_PATH); - System.out.println("重启进程已启动,当前服务退出"); + AssertLog.info("版本策略重启进程已启动,当前服务退出"); ProcessBuilder pb = new ProcessBuilder("/bin/sh", "-c", policy.getCommandParams()); pb.start(); @@ -219,6 +219,7 @@ public class AgentServiceImpl implements AgentService { System.out.println("[失败resOut] " + result.getOutput()); } JSONObject rse = new JSONObject(); + rse.put("scriptId", policy.getScriptId()); rse.put("command",policy.getCommandParams()); rse.put("resOut", result.getOutput()); long timestamps = System.currentTimeMillis(); @@ -238,12 +239,13 @@ public class AgentServiceImpl implements AgentService { }).exceptionally(ex -> { System.err.println("执行失败: " + ex.getMessage()); JSONObject rse = new JSONObject(); + rse.put("scriptId", policy.getScriptId()); rse.put("command",policy.getCommandParams()); rse.put("resOut", "脚本执行失败"); long timestamps = System.currentTimeMillis(); timestamps = Math.round(timestamps / 1000.0); JSONObject json = new JSONObject(); - json.put("resCode",1); + json.put("resCode",0); json.put("resMsg", ""); json.put("timestamp",timestamps); json.put("result", rse.toString()); @@ -712,7 +714,7 @@ public class AgentServiceImpl implements AgentService { AdvancedAsyncDownloader.downloadWithProgress(versionUpdateEO.getFileUrl(), properties.getTempPath(), fileName, progress -> { System.out.printf("下载进度: %.1f%%\n", progress); }).thenAccept(filePath -> { - System.out.println("下载完成: " + filePath); + AssertLog.info("版本策略下载完成: {}", filePath); try { //验证文件MD5 String md5 = AgentUtil.getFileMD5(properties.getTempPath()+"/"+fileName); @@ -723,8 +725,10 @@ public class AgentServiceImpl implements AgentService { //关闭采集任务 cancelCollect(); //所有文件下载完成,执行脚本命令 + AssertLog.info("版本策略MD5验证成功"); command(policy, GlobalConfig.CLIENT_ID,MsgEnum.Agent版本更新应答.getValue()); }else{ + AssertLog.info("版本策略MD5验证失败"); //发送更新失败 long timestamp = System.currentTimeMillis(); timestamp = Math.round(timestamp / 1000.0); @@ -766,6 +770,49 @@ public class AgentServiceImpl implements AgentService { GlobalConfig.VERSION_TIME = upTime; } } + //静态路由策略 + if(jsonObject.containsKey("routes")){ + String routes = jsonObject.getString("routes"); + JSONObject routeJson = JSONObject.parseObject(routes); + long upTime = 0; + if(routeJson.containsKey("upTime")){ + upTime = routeJson.getLong("upTime"); + } + //判断监控策略最新更新时间戳,不一致则进行更新策略 + if(upTime != 0 && GlobalConfig.ROUTE_TIME != upTime){ + if(routeJson.containsKey("delRoute")) { + String delRoute = routeJson.getString("delRoute"); + JSONObject delRouteJson = JSONObject.parseObject(delRoute); + String name = ""; + String gateway = ""; + if(delRouteJson.containsKey("name")){ + name = delRouteJson.getString("name"); + } + if(delRouteJson.containsKey("gateway")){ + gateway = delRouteJson.getString("gateway"); + } + if(StringUtils.isNotBlank(name) && StringUtils.isNotBlank(gateway)){ + dellRoute(name, gateway); + } + } + if(routeJson.containsKey("addRoute")) { + String addRoute = routeJson.getString("addRoute"); + JSONObject addRouteJson = JSONObject.parseObject(addRoute); + String name = ""; + String gateway = ""; + if(addRouteJson.containsKey("name")){ + name = addRouteJson.getString("name"); + } + if(addRouteJson.containsKey("gateway")){ + gateway = addRouteJson.getString("gateway"); + } + if(StringUtils.isNotBlank(name) && StringUtils.isNotBlank(gateway)){ + addRoute(name,gateway); + } + } + } + + } } @@ -863,7 +910,93 @@ public class AgentServiceImpl implements AgentService { GlobalConfig.CLIENT_ID = clientId; } } - return client.createConnection(GlobalConfig.CLIENT_ID, config.getHost(), config.getPort(), 5); + //先进行断开连接 + client.closeConnection(GlobalConfig.CLIENT_ID); + boolean success = client.createConnection(GlobalConfig.CLIENT_ID, config.getHost(), config.getPort(), 5); + if(success){ + //连接成功,发送初始连接消息 + long timestamp = System.currentTimeMillis(); + timestamp = Math.round(timestamp / 1000.0); + JSONObject object = new JSONObject(); + object.put("clientId", GlobalConfig.CLIENT_ID); + object.put("sn", GlobalConfig.DEVICE_SN); + object.put("timestamp", timestamp); + Message msg = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.建立连接.getValue()).data(object.toString()).build(); + // 将对象转为 JSON 字符串 + client.sendMessages(GlobalConfig.CLIENT_ID, msg); + // 等待3秒 + try { + TimeUnit.SECONDS.sleep(3); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + return success; + } + + @Override + public void addRoute(String name, String gateway) { + String ip = ""; + String prefix = "32"; + String command = ""; + if(StringUtils.isNotBlank(name) && StringUtils.isNotBlank(gateway)){ + ip = config.getHost(); + command = "ip route add "+ip+"/"+prefix+" via "+gateway+" dev "+name; + }else{ + String filePath = properties.getConfPath()+"/route.conf"; + try { + String result = AgentUtil.readNonEmptyLinesAsString(filePath); + if(StringUtils.isNotBlank(result)){ + String[] arr = result.split(" "); + if(arr.length == 8){ + ip = arr[3].substring(0,arr[3].indexOf("/")); + prefix = arr[3].substring(arr[3].indexOf("/")+1,arr[3].length()); + name = arr[7]; + gateway = arr[5]; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + AssertLog.info("addRoute脚本开始执行,command={}",command); + boolean flag = NetworkUtil.addRoute(ip,prefix,gateway,name); + if(flag){ + AssertLog.info("addRoute脚本执行成功,command={}",command); + //检查外置目录是否存在 + if(AdvancedAsyncDownloader.createSingleDirectoryIfNotExists(properties.getConfPath())){ + String[] lines = { + command + }; + AgentUtil.bufferedWriter(properties.getConfPath()+"/route.conf",lines); + } + }else{ + AssertLog.info("addRoute脚本执行失败,command={}",command); + } + } + + @Override + public void dellRoute(String name, String gateway) { + String command = "ip route del "+config.getHost()+"/32 via "+gateway+" dev "+name; + try { + AssertLog.info("delRoute脚本开始执行,command={}",command); + boolean flag = NetworkUtil.deleteRoute(config.getHost(),String.valueOf(config.getPort()),gateway,name); + if(flag){ + AssertLog.info("dellRoute脚本执行成功,command={}",command); + Path path = Paths.get(properties.getConfPath()+"/route.conf"); + try { + Files.delete(path); + } catch (NoSuchFileException e) { + } catch (DirectoryNotEmptyException e) { + } catch (IOException e) { + System.err.println("删除文件失败:" + e.getMessage()); + } + }else{ + AssertLog.info("dellRoute脚本执行失败,command={}",command); + } + }catch (Exception e){ + System.err.println(e.getMessage()); + } } diff --git a/src/main/java/com/tongran/agent/client/utils/AgentUtil.java b/src/main/java/com/tongran/agent/client/utils/AgentUtil.java index cb63ffd..e708b2b 100644 --- a/src/main/java/com/tongran/agent/client/utils/AgentUtil.java +++ b/src/main/java/com/tongran/agent/client/utils/AgentUtil.java @@ -16,6 +16,7 @@ import java.time.LocalDateTime; import java.time.ZoneId; import java.time.temporal.ChronoUnit; import java.util.*; +import java.util.stream.Collectors; public class AgentUtil { @@ -552,4 +553,31 @@ public class AgentUtil { } } + public static String getNetworkParam(String filePath, String key){ + Properties props = new Properties(); + String result = ""; + try (InputStream input = Files.newInputStream(Paths.get(filePath))) { + // 加载配置文件 + props.load(input); + result = props.getProperty(key, ""); + System.out.println("配置文件加载成功"); + } catch (IOException e) { + System.err.println("无法加载配置文件,使用默认值"); + } catch (NumberFormatException e) { + System.err.println("配置文件格式错误: " + e.getMessage()); + } + return result; + } + + /** + * 读取文件,跳过空行,将所有非空行拼接成一个字符串 + * @param filePath 文件路径 + * @return 拼接后的字符串(空行已去除) + */ + public static String readNonEmptyLinesAsString(String filePath) throws Exception { + return Files.lines(Paths.get(filePath)) + .filter(line -> !line.trim().isEmpty()) // 去除 null 和 空/空白行 + .collect(Collectors.joining("\n")); // 用换行符连接 + } + } diff --git a/src/main/java/com/tongran/agent/client/utils/NetworkUtil.java b/src/main/java/com/tongran/agent/client/utils/NetworkUtil.java new file mode 100644 index 0000000..0ca4130 --- /dev/null +++ b/src/main/java/com/tongran/agent/client/utils/NetworkUtil.java @@ -0,0 +1,27 @@ +package com.tongran.agent.client.utils; + +public class NetworkUtil { + public static boolean addRoute(String ip, String prefix, String gateway, String dev) { + try { + ProcessBuilder pb = new ProcessBuilder("ip", "route", "add", + ip + "/" + prefix, "via", gateway, "dev", dev); + pb.redirectErrorStream(true); + Process p = pb.start(); + return p.waitFor() == 0; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public static boolean deleteRoute(String ip, String prefix, String gateway, String dev) { + try { + ProcessBuilder pb = new ProcessBuilder("ip", "route", "del", + ip + "/" + prefix, "via", gateway, "dev", dev); + return pb.start().waitFor() == 0; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } +} \ No newline at end of file