Files
tr-agent-client/src/main/java/com/tongran/agent/client/utils/CrontabManager.java
T
2025-11-04 20:05:51 +08:00

326 lines
12 KiB
Java

package com.tongran.agent.client.utils;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.TimeUnit;
public class CrontabManager {
// // 要添加的定时任务
// private static final String CRON_JOB = "*/10 * * * * /usr/local/tongran/sbin/test2.sh >/dev/null 2>&1";
// // 用于判断是否已存在的关键标识(可以是脚本路径)
// private static final String JOB_IDENTIFIER = "/usr/local/tongran/sbin/test2.sh";
/**
* 检查并添加定时任务
*/
public static boolean ensureCronJobExists(String CRON_JOB, String JOB_IDENTIFIER) {
try {
// 1. 读取当前用户的 crontab
ProcessBuilder pb = new ProcessBuilder("crontab", "-l");
pb.redirectErrorStream(true);
Process process = pb.start();
// 设置超时(防止卡死)
if (!process.waitFor(5, TimeUnit.SECONDS)) {
process.destroy();
throw new IOException("crontab -l timeout");
}
StringBuilder crontabContent = new StringBuilder();
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
crontabContent.append(line).append("\n");
}
}
int exitCode = process.exitValue();
if (exitCode != 0 && exitCode != 1) {
// exit code 1 表示没有 crontab 文件(正常)
throw new IOException("crontab -l failed with exit code: " + exitCode);
}
String content = crontabContent.toString();
// 2. 检查是否已存在该任务
if (content.contains(JOB_IDENTIFIER)) {
System.out.println("Crontab 任务已存在,无需添加。");
return true;
}
// 3. 如果不存在,追加任务
String newCrontab;
if (content.trim().isEmpty()) {
// 原来没有 crontab
newCrontab = CRON_JOB + "\n";
} else {
// 原来有 crontab,在末尾添加新任务
newCrontab = content;
if (!content.endsWith("\n")) {
newCrontab += "\n";
}
newCrontab += CRON_JOB + "\n";
}
// 4. 写入新的 crontab
ProcessBuilder pbWrite = new ProcessBuilder("crontab", "-");
pbWrite.redirectErrorStream(true);
Process writeProcess = pbWrite.start();
try (OutputStreamWriter writer = new OutputStreamWriter(writeProcess.getOutputStream())) {
writer.write(newCrontab);
writer.flush();
}
if (!writeProcess.waitFor(5, TimeUnit.SECONDS)) {
writeProcess.destroy();
throw new IOException("crontab - write timeout");
}
int writeExitCode = writeProcess.exitValue();
if (writeExitCode != 0) {
throw new IOException("crontab - write failed with exit code: " + writeExitCode);
}
System.out.println("Crontab 任务添加成功:\n" + CRON_JOB);
return true;
} catch (IOException | InterruptedException e) {
System.err.println("操作 crontab 失败:" + e.getMessage());
e.printStackTrace();
return false;
}
}
// === 使用示例 ===
public static void main(String[] args) {
// 要添加的定时任务
String CRON_JOB = "*/10 * * * * /usr/local/tongran/sbin/test2.sh >/dev/null 2>&1";
// 用于判断是否已存在的关键标识(可以是脚本路径)
String JOB_IDENTIFIER = "/usr/local/tongran/sbin/test2.sh";
// boolean success = ensureCronJobExists(CRON_JOB,JOB_IDENTIFIER);
// if (success) {
// System.out.println("✅ Crontab 状态正常。");
// } else {
// System.err.println("❌ 操作失败,请检查权限或路径。");
// }
}
/**
* 验证当前定时任务中是否包含目标脚本
*/
public static boolean isCronEntryExists(String TARGET_SCRIPT) {
try {
AssertLog.info("验证: 检查当前定时任务是否包含 {}",TARGET_SCRIPT);
Process process = Runtime.getRuntime().exec("crontab -l");
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream())
);
String line;
while ((line = reader.readLine()) != null) {
if (line.contains(TARGET_SCRIPT)) {
AssertLog.info("✅ 发现目标脚本在当前定时任务中: {}",line.trim());
reader.close();
return true;
}
}
reader.close();
int exitCode = process.waitFor();
if (exitCode != 0 && exitCode != 1) { // exitCode 1 表示没有 crontab
throw new IOException("获取当前 crontab 失败,退出码: " + exitCode);
}
AssertLog.info("当前定时任务中未找到目标脚本");
return false;
}catch (IOException | InterruptedException e) {
System.err.println("操作 crontab 失败:" + e.getMessage());
e.printStackTrace();
return false;
}
}
/**
* 0. 清空 tr_live.cron 文件内容
*/
public static void clearCronFile(String cronDir, String CRON_FILE_PATH) {
try {
AssertLog.info("步骤0: 清空 {} 文件内容",CRON_FILE_PATH);
// 确保目录存在
new File(cronDir).mkdirs();
// 创建空文件(如果不存在)或清空现有内容
Files.write(Paths.get(CRON_FILE_PATH), new byte[0]);
AssertLog.info("✅ {} 文件已清空",CRON_FILE_PATH);
}catch (IOException e) {
System.err.println("操作 crontab 失败:" + e.getMessage());
e.printStackTrace();
}
}
/**
* 1. 备份当前定时任务到文件
*/
public static void backupCurrentCrontab(String CRON_FILE_PATH) {
try {
AssertLog.info("步骤1: 备份当前定时任务到 {}",CRON_FILE_PATH);
Process process = Runtime.getRuntime().exec("crontab -l");
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream())
);
// 读取当前 crontab 内容
StringBuilder currentCrontab = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
currentCrontab.append(line).append("\n");
}
reader.close();
int exitCode = process.waitFor();
if (exitCode != 0 && exitCode != 1) { // exitCode 1 表示没有 crontab
throw new IOException("获取当前 crontab 失败,退出码: " + exitCode);
}
// 写入当前定时任务内容
Files.write(Paths.get(CRON_FILE_PATH), currentCrontab.toString().getBytes());
AssertLog.info("✅ 当前定时任务已保存到: {}",CRON_FILE_PATH);
}catch (IOException | InterruptedException e) {
System.err.println("操作 crontab 失败:" + e.getMessage());
e.printStackTrace();
}
}
/**
* 2. 在文件末尾添加新的定时任务
*/
public static void appendNewCronEntry(String CRON_FILE_PATH, String NEW_CRON_ENTRY) {
try {
AssertLog.info("步骤2: 在文件末尾添加新定时任务");
// 检查是否已存在该定时任务
String fileContent = new String(Files.readAllBytes(Paths.get(CRON_FILE_PATH)));
if (fileContent.contains(NEW_CRON_ENTRY)) {
AssertLog.info("⚠️ 定时任务已存在,跳过添加");
return;
}
// 添加新定时任务到文件末尾
Files.write(
Paths.get(CRON_FILE_PATH),
(NEW_CRON_ENTRY + "\n").getBytes(),
StandardOpenOption.APPEND
);
AssertLog.info("✅ 新定时任务已添加到文件末尾");
}catch (IOException e) {
System.err.println("操作 crontab 失败:" + e.getMessage());
e.printStackTrace();
}
}
/**
* 3. 清除当前所有定时任务
*/
public static void clearCurrentCrontab() {
try {
AssertLog.info("步骤3: 清除当前所有定时任务");
// 创建一个空的临时文件
File tempFile = File.createTempFile("empty_cron", ".tmp");
tempFile.deleteOnExit();
// 用空文件替换当前 crontab
Process process = Runtime.getRuntime().exec("crontab " + tempFile.getAbsolutePath());
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new IOException("清除当前 crontab 失败,退出码: " + exitCode);
}
AssertLog.info("✅ 当前所有定时任务已清除");
}catch (IOException | InterruptedException e) {
System.err.println("操作 crontab 失败:" + e.getMessage());
e.printStackTrace();
}
}
/**
* 4. 重新加载定时任务文件
*/
public static void installNewCrontab(String CRON_FILE_PATH) {
try {
AssertLog.info("步骤4: 加载新的定时任务文件");
// 检查文件是否存在
if (!Files.exists(Paths.get(CRON_FILE_PATH))) {
throw new IOException("定时任务文件不存在: " + CRON_FILE_PATH);
}
// 执行 crontab 命令加载新文件
Process process = Runtime.getRuntime().exec("crontab " + CRON_FILE_PATH);
// 读取输出
BufferedReader stdout = new BufferedReader(
new InputStreamReader(process.getInputStream())
);
BufferedReader stderr = new BufferedReader(
new InputStreamReader(process.getErrorStream())
);
String outputLine;
while ((outputLine = stdout.readLine()) != null) {
System.out.println("STDOUT: " + outputLine);
}
String errorLine;
while ((errorLine = stderr.readLine()) != null) {
System.err.println("STDERR: " + errorLine);
}
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new IOException("加载新 crontab 失败,退出码: " + exitCode);
}
AssertLog.info("✅ 新定时任务已成功加载");
}catch (IOException | InterruptedException e) {
System.err.println("操作 crontab 失败:" + e.getMessage());
e.printStackTrace();
}
}
/**
* 验证最终结果
*/
public static void verifyFinalResult(String TARGET_SCRIPT) {
try {
AssertLog.info("\n--- 验证最终定时任务结果 ---");
Process process = Runtime.getRuntime().exec("crontab -l");
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream())
);
boolean found = false;
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
if (line.contains(TARGET_SCRIPT)) {
AssertLog.info("✅ 确认 " + TARGET_SCRIPT + " 已成功添加到定时任务中");
found = true;
}
}
reader.close();
if (!found) {
AssertLog.info("❌ 未在当前定时任务中找到目标脚本");
}
} catch (Exception e) {
AssertLog.info("验证 crontab 时出错: " + e.getMessage());
}
}
}