目标上传worker添加、测试用例生成worker 、 AFLworker

This commit is contained in:
even 2025-05-27 21:26:20 +08:00
parent 4029e7d497
commit eb7b06607c
13 changed files with 469 additions and 113 deletions

View File

@ -14,7 +14,7 @@ public class MachineInfoResp {
* id
*/
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String id;
/**
* 主机ip

View File

@ -0,0 +1,8 @@
package cd.casic.ci.process.engine.constant;
public class AFLConstant {
/**
* 脚本内容
*/
public static final String COMMAND_SCRIPT ="buildScript";
}

View File

@ -0,0 +1,8 @@
package cd.casic.ci.process.engine.constant;
public class TestCaseGenerationConstant {
/**
* 脚本内容key
*/
public static final String COMMAND_SCRIPT ="buildScript";
}

View File

@ -32,6 +32,7 @@ public class MemoryLogManager implements LoggerManager {
private final Map<String,StringBuffer> taskIdMemoryLogMap = new ConcurrentHashMap<>();
public final Integer FLUSH_DB_SIZE=2*1024*1024;
// public final Integer FLUSH_DB_SIZE=1000;
private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
/**
* 缓存最近一次执行的日志key是taskIdval是数据库id已入库的情况下用于buffer满了增加日志内容

View File

@ -19,8 +19,8 @@ import java.util.List;
* @Date: 2025/5/26 17:28
* @Description:
*/
@Component
@RequiredArgsConstructor
//@Component
//@RequiredArgsConstructor
public class PipelineSchedulingBootstrapper {
@Resource
private PipelineSchedulingPropertiesServiceImpl taskService;

View File

@ -1,12 +1,20 @@
package cd.casic.ci.process.engine.worker;
import cd.casic.ci.common.pipeline.annotation.Plugin;
import cd.casic.ci.process.engine.constant.AFLConstant;
import cd.casic.ci.process.engine.constant.DIYImageExecuteCommandConstant;
import cd.casic.ci.process.engine.constant.EngineRuntimeConstant;
import cd.casic.ci.process.engine.runContext.BaseRunContext;
import cd.casic.ci.process.engine.runContext.PipelineRunContext;
import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.process.dataObject.base.PipBaseElement;
import cd.casic.ci.process.process.dataObject.log.PipTaskLog;
import cd.casic.ci.process.process.dataObject.machine.MachineInfo;
import cd.casic.ci.process.process.dataObject.pipeline.PipPipeline;
import cd.casic.ci.process.process.dataObject.target.TargetVersion;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.ci.process.process.service.target.TargetVersionService;
import cd.casic.ci.process.util.CryptogramUtil;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import com.jcraft.jsch.*;
@ -21,121 +29,50 @@ import java.util.Map;
@Plugin(taskType = "AFL")
@Slf4j
public class AFLWorker extends SshWorker{
@Resource
private TargetVersionService targetVersionService;
public class AFLWorker extends SshWorker {
@Override
public void execute(TaskRunContext context) {
String filePath = "";
int statusCode = -1;
Map<String, Object> localVariables = context.getLocalVariables();
PipBaseElement taskContextDef = context.getContextDef();
if (taskContextDef instanceof PipTask pipTask){
// 查询并下载目标文件
String pipelineId = pipTask.getPipelineId();
//根据流水线id查询流水线信息
PipPipeline pipeline = (PipPipeline) getContextManager().getContext(pipelineId).getContextDef();
//根据目标id查询目标信息
if (StringUtils.isEmpty(pipeline.getTargetVersionId())){
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"目标文件不存在");
}
TargetVersion targetVersion = targetVersionService.getById(pipeline.getTargetVersionId());
filePath = targetVersion.getFilePath();
File file = new File(filePath);
if (!file.exists() || !file.canRead()) {
log.error("目标文件不存在或不可读");
localVariables.put("statusCode", "-1");
append(context,"目标文件不存在或不可读");
if (context.getContextDef() instanceof PipTask taskDef) {
log.info(taskDef.getTaskName());
Map<String, Object> taskProperties = taskDef.getTaskProperties();
Object commandScriptObj = taskProperties.get(AFLConstant.COMMAND_SCRIPT);
// Object machineIdObj = taskProperties.get(DIYImageExecuteCommandConstant.MACHINE_ID);
String commandScript = commandScriptObj instanceof String ? ((String) commandScriptObj) : null;
PipPipeline pipeline = (PipPipeline) getContextManager().getContext(taskDef.getPipelineId()).getContextDef();
String machineId = pipeline.getMachineId();
if (StringUtils.isEmpty(commandScript)||StringUtils.isEmpty(machineId)) {
// 缺少参数
toBadEnding();
}
// 上传文件
// 执行shell脚本
}
}
public static void main(String[] args) {
String remoteHost = "your-remote-server-ip-or-hostname"; // 远程服务器IP或主机名
int remotePort = 22; // SFTP 默认端口通常是 22 (SSH 端口)
String username = "your-username"; // 远程服务器用户名
String password = "your-password"; // 远程服务器密码 SSH Key 路径
String localFilePath = "path/to/your/local/file.txt"; // 要上传的本地文件路径
String remoteDir = "/path/on/remote/server/"; // 远程服务器存放文件的目录
String remoteFileName = "uploaded_file.txt"; // 上传到远程服务器的文件名 (可以和本地不同)
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
FileInputStream fis = null;
try {
JSch jsch = new JSch();
// 如果使用 SSH Key 认证可以添加身份文件
// jsch.addIdentity("/path/to/your/private/key"); // 替换为你的私钥文件路径
session = jsch.getSession(username, remoteHost, remotePort);
// 如果使用密码认证
session.setPassword(password);
// 设置连接不进行主机密钥检查 (生产环境不推荐应该配置known_hosts)
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
System.out.println("SFTP Session 连接成功.");
channel = session.openChannel("sftp");
channel.connect();
System.out.println("SFTP Channel 打开成功.");
channelSftp = (ChannelSftp) channel;
// 切换到远程目录 (如果目录不存在可能需要先创建)
try {
channelSftp.cd(remoteDir);
} catch (SftpException e) {
System.err.println("远程目录不存在,尝试创建: " + remoteDir);
try {
channelSftp.mkdir(remoteDir);
channelSftp.cd(remoteDir);
} catch (SftpException e2) {
System.err.println("创建远程目录失败: " + remoteDir);
throw e2; // 抛出异常终止上传
}
}
//将节点的配置信息反编译成对象
log.info("构建脚本" + commandScript);
//如果machineId为0则说明该节点没有配置机器则使用开始节点的机器
// 上传文件
File localFile = new File(localFilePath);
fis = new FileInputStream(localFile);
channelSftp.put(fis, remoteFileName);
System.out.println("文件上传成功到: " + remoteDir + remoteFileName);
} catch (JSchException | SftpException | IOException e) {
System.err.println("SFTP 文件上传过程中发生异常: " + e.getMessage());
e.printStackTrace();
} finally {
// 关闭资源
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
//获取机器
MachineInfo machineInfoDO = this.getMachineInfoService().getById(machineId);
statusCode = shell(machineInfoDO, CryptogramUtil.doDecrypt(machineInfoDO.getPassword()), context,
"echo \"自定义镜像执行命令\"",
commandScript
);
} catch (Exception e) {
String errorMessage = "该节点配置信息为空,请先配置该节点信息" + "\r\n";
log.error("执行ssh失败:", e);
append(context, errorMessage);
toBadEnding();
}
if (channelSftp != null) {
channelSftp.disconnect();
System.out.println("SFTP Channel 已断开.");
}
if (channel != null) {
channel.disconnect();
}
if (session != null) {
session.disconnect();
System.out.println("SFTP Session 已断开.");
if (statusCode == 0) {
log.info("节点执行完成");
} else {
log.error("节点执行失败");
}
localVariables.put(DIYImageExecuteCommandConstant.STATUS_CODE, statusCode);
}
}
}

View File

@ -3,8 +3,23 @@ package cd.casic.ci.process.engine.worker;
import cd.casic.ci.common.pipeline.annotation.Plugin;
import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.process.dataObject.base.PipBaseElement;
import cd.casic.ci.process.process.dataObject.machine.MachineInfo;
import cd.casic.ci.process.process.dataObject.pipeline.PipPipeline;
import cd.casic.ci.process.process.dataObject.target.TargetVersion;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.ci.process.process.service.machine.MachineInfoService;
import cd.casic.ci.process.process.service.target.TargetVersionService;
import cd.casic.ci.process.util.CryptogramUtil;
import cd.casic.ci.process.util.SftpUploadUtil;
import cd.casic.framework.commons.exception.ServiceException;
import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants;
import com.alibaba.fastjson.JSON;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.util.Map;
/**
* 目标处理worker
@ -13,11 +28,44 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j
@Plugin(taskType = "code")
public class TargetHandleWorker extends BaseWorker{
@Resource
private TargetVersionService targetVersionService;
@Resource
private MachineInfoService machineInfoService;
@Override
public void execute(TaskRunContext context) {
PipBaseElement contextDef = context.getContextDef();
String id = contextDef.getId();
log.info("==============触发worker执行========");
log.info("==========运行context{}===========", JSON.toJSONString(context));
String filePath = "";
Map<String, Object> localVariables = context.getLocalVariables();
PipBaseElement taskContextDef = context.getContextDef();
if (taskContextDef instanceof PipTask pipTask){
// 查询并下载目标文件
String pipelineId = pipTask.getPipelineId();
//根据流水线id查询流水线信息
PipPipeline pipeline = (PipPipeline) getContextManager().getContext(pipelineId).getContextDef();
//根据目标id查询目标信息
if (StringUtils.isEmpty(pipeline.getTargetVersionId())){
throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"目标文件不存在");
}
TargetVersion targetVersion = targetVersionService.getById(pipeline.getTargetVersionId());
filePath = targetVersion.getFilePath();
File file = new File(filePath);
if (!file.exists() || !file.canRead()) {
log.error("目标文件不存在或不可读");
localVariables.put("statusCode", "-1");
append(context,"目标文件不存在或不可读");
toBadEnding();
}
// 上传文件
String machineId = pipeline.getMachineId();
MachineInfo byId = machineInfoService.getById(machineId);
append(context,"开始文件上传");
try {
SftpUploadUtil.uploadFileViaSftp(byId.getMachineHost(),byId.getSshPort(),byId.getUsername(), CryptogramUtil.doDecrypt(byId.getPassword()),null,file.getAbsolutePath(),"/home/casic/706/ai_test_527",file.getName());
} catch (SftpUploadUtil.SftpUploadException e) {
log.error("文件上传失败",e);
toBadEnding();
}
append(context,"文件上传至"+byId.getMachineHost()+" /home/casic/706/ai_test_527");
}
}
}

View File

@ -1,12 +1,64 @@
package cd.casic.ci.process.engine.worker;
import cd.casic.ci.common.pipeline.annotation.Plugin;
import cd.casic.ci.process.engine.constant.AFLConstant;
import cd.casic.ci.process.engine.constant.DIYImageExecuteCommandConstant;
import cd.casic.ci.process.engine.constant.TestCaseGenerationConstant;
import cd.casic.ci.process.engine.runContext.TaskRunContext;
import cd.casic.ci.process.process.dataObject.machine.MachineInfo;
import cd.casic.ci.process.process.dataObject.pipeline.PipPipeline;
import cd.casic.ci.process.process.dataObject.task.PipTask;
import cd.casic.ci.process.util.CryptogramUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
@Plugin(taskType = "TEST_CASE_GENERATION")
@Slf4j
public class TestCaseGenerationWorker extends SshWorker{
@Override
public void execute(TaskRunContext context) {
int statusCode = -1;
Map<String, Object> localVariables = context.getLocalVariables();
if (context.getContextDef() instanceof PipTask taskDef) {
log.info(taskDef.getTaskName());
Map<String, Object> taskProperties = taskDef.getTaskProperties();
Object commandScriptObj = taskProperties.get(TestCaseGenerationConstant.COMMAND_SCRIPT);
// Object machineIdObj = taskProperties.get(DIYImageExecuteCommandConstant.MACHINE_ID);
String commandScript = commandScriptObj instanceof String ? ((String) commandScriptObj) : null;
PipPipeline pipeline = (PipPipeline) getContextManager().getContext(taskDef.getPipelineId()).getContextDef();
String machineId = pipeline.getMachineId();
if (StringUtils.isEmpty(commandScript)||StringUtils.isEmpty(machineId)) {
// 缺少参数
toBadEnding();
}
try {
//将节点的配置信息反编译成对象
log.info("构建脚本" + commandScript);
//如果machineId为0则说明该节点没有配置机器则使用开始节点的机器
//获取机器
MachineInfo machineInfoDO = this.getMachineInfoService().getById(machineId);
statusCode = shell(machineInfoDO, CryptogramUtil.doDecrypt(machineInfoDO.getPassword()), context,
"echo \"自定义镜像执行命令\"",
commandScript
);
} catch (Exception e) {
String errorMessage = "该节点配置信息为空,请先配置该节点信息" + "\r\n";
log.error("执行ssh失败:", e);
append(context, errorMessage);
toBadEnding();
}
if (statusCode == 0) {
log.info("节点执行完成");
} else {
log.error("节点执行失败");
}
localVariables.put(DIYImageExecuteCommandConstant.STATUS_CODE, statusCode);
}
}
}

View File

@ -2,6 +2,8 @@ package cd.casic.ci.process.process.dataObject.log;
import cd.casic.ci.process.constant.CommandConstant;
import cd.casic.framework.commons.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -10,6 +12,7 @@ import lombok.EqualsAndHashCode;
public class PipTaskLog extends BaseDO {
private String taskId;
private String content;
@TableId(type = IdType.ASSIGN_ID)
private String id;
public void append(String content){
this.content += CommandConstant.ENTER;

View File

@ -34,7 +34,7 @@ public class MachineInfo extends BaseDO {
* id
*/
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String id;
/**
* 主机ip

View File

@ -135,5 +135,8 @@ public class PipPipeline extends PipBaseElement {
* 运行实例编号
*/
private String instanceNum;
/**
* 机器id
* */
private String machineId;
}

View File

@ -0,0 +1,266 @@
package cd.casic.ci.process.util;
import cd.casic.framework.commons.exception.ServiceException;
import com.jcraft.jsch.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class SftpUploadUtil {
private static final int DEFAULT_SFTP_PORT = 22;
/**
* 通过 SFTP 上传文件到远程服务器
*
* @param remoteHost 远程服务器IP或主机名
* @param remotePort 远程服务器端口 (通常是 22) null <= 0 时使用默认端口 22
* @param username 远程服务器用户名
* @param password 远程服务器密码 (如果使用密码认证)
* @param sshKeyPath SSH Key 文件路径 (如果使用密钥认证password 参数可以为 null)
* @param localFilePath 本地要上传的文件路径
* @param remoteDir 远程服务器存放文件的目录 (例如: /home/user/uploads/)
* @param remoteFileName 上传到远程服务器的文件名 ( null 或空字符串时使用本地文件名)
* @throws SftpUploadException 如果上传过程中发生任何错误
*/
public static void uploadFileViaSftp(
String remoteHost,
Integer remotePort,
String username,
String password,
String sshKeyPath,
String localFilePath,
String remoteDir,
String remoteFileName) throws SftpUploadException {
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
FileInputStream fis = null;
try {
JSch jsch = new JSch();
// 1. 添加身份认证信息 (密码或密钥)
if (sshKeyPath != null && !sshKeyPath.trim().isEmpty()) {
// 使用 SSH Key 认证
File sshKeyFile = new File(sshKeyPath);
if (!sshKeyFile.exists() || !sshKeyFile.isFile()) {
throw new SftpUploadException("SSH Key 文件不存在或不是一个有效文件: " + sshKeyPath);
}
jsch.addIdentity(sshKeyPath);
System.out.println("使用 SSH Key 认证: " + sshKeyPath);
} else if (password == null || password.trim().isEmpty()) {
// 如果没有提供密码或密钥路径则认证信息不全
throw new SftpUploadException("必须提供密码或 SSH Key 路径进行 SFTP 认证.");
}
// 如果提供了密码将在 getSession 后设置因为 getSession 需要用户名主机和端口先建立连接意图
// 2. 获取 Session
int port = (remotePort != null && remotePort > 0) ? remotePort : DEFAULT_SFTP_PORT;
session = jsch.getSession(username, remoteHost, port);
System.out.println("尝试连接 SFTP 服务器: " + username + "@" + remoteHost + ":" + port);
// 如果使用密码认证且提供了密码
if (password != null && !password.trim().isEmpty() && (sshKeyPath == null || sshKeyPath.trim().isEmpty())) {
session.setPassword(password);
System.out.println("使用密码认证.");
}
// 设置连接不进行主机密钥检查 (生产环境不推荐应该配置 known_hosts)
// 在实际应用中应该引导用户信任主机密钥或提前将主机密钥加入 known_hosts
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no"); // !!! 生产环境请谨慎使用或配置正确的主机密钥检查 !!!
session.setConfig(config);
// 3. 连接 Session
session.connect();
System.out.println("SFTP Session 连接成功.");
// 4. 打开 SFTP Channel
channel = session.openChannel("sftp");
channel.connect();
System.out.println("SFTP Channel 打开成功.");
channelSftp = (ChannelSftp) channel;
// 5. 检查并切换到远程目录
try {
channelSftp.cd(remoteDir);
System.out.println("已切换到远程目录: " + remoteDir);
} catch (SftpException e) {
// 如果远程目录不存在尝试创建
System.err.println("远程目录不存在: " + remoteDir + ",尝试创建...");
try {
// 尝试递归创建目录 (如果需要)
createRemoteDirRecursive(channelSftp, remoteDir);
channelSftp.cd(remoteDir); // 创建后再次切换
System.out.println("远程目录创建成功并已切换: " + remoteDir);
} catch (SftpException e2) {
// 创建目录失败
throw new SftpUploadException("远程目录创建失败: " + remoteDir, e2);
}
}
// 6. 获取本地文件流
File localFile = new File(localFilePath);
if (!localFile.exists() || !localFile.isFile()) {
throw new SftpUploadException("本地文件不存在或不是一个有效文件: " + localFilePath);
}
fis = new FileInputStream(localFile);
System.out.println("本地文件流获取成功: " + localFilePath);
// 7. 确定远程文件名
String finalRemoteFileName = (remoteFileName != null && !remoteFileName.trim().isEmpty()) ?
remoteFileName : localFile.getName();
System.out.println("最终上传到远程的文件名为: " + finalRemoteFileName);
// 8. 上传文件
channelSftp.put(fis, finalRemoteFileName);
System.out.println("文件上传成功!");
} catch (JSchException e) {
throw new SftpUploadException("SFTP 连接或认证失败: " + e.getMessage(), e);
} catch (SftpException e) {
throw new SftpUploadException("SFTP 操作失败 (如切换目录或上传文件): " + e.getMessage(), e);
} catch (FileNotFoundException e) {
throw new SftpUploadException("本地文件未找到: " + e.getMessage(), e);
} catch (IOException e) {
throw new SftpUploadException("文件流读写异常: " + e.getMessage(), e);
} catch (SftpUploadException e) {
// 重新抛出自定义异常
throw e;
} catch (Exception e) {
// 捕获其他未知异常
throw new SftpUploadException("SFTP 上传过程中发生未知异常: " + e.getMessage(), e);
} finally {
// 9. 关闭资源 (确保在任何情况下都关闭)
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
System.err.println("关闭本地文件流失败: " + e.getMessage());
e.printStackTrace(); // 打印堆栈以便调试
}
}
if (channelSftp != null) {
channelSftp.disconnect();
System.out.println("SFTP Channel 已断开.");
}
if (channel != null) {
channel.disconnect();
System.out.println("SFTP Channel 资源已释放.");
}
if (session != null) {
session.disconnect();
System.out.println("SFTP Session 已断开.");
}
}
}
/**
* 辅助方法递归创建远程目录
* @param channelSftp ChannelSftp 实例
* @param remoteDir 要创建的目录路径
* @throws SftpException 如果创建失败
*/
private static void createRemoteDirRecursive(ChannelSftp channelSftp, String remoteDir) throws SftpException {
// 标准化路径去掉末尾的 /
String cleanRemoteDir = remoteDir.endsWith("/") ? remoteDir.substring(0, remoteDir.length() - 1) : remoteDir;
String[] pathElements = cleanRemoteDir.split("/");
StringBuilder currentDir = new StringBuilder();
try {
channelSftp.cd("/"); // 先回到根目录
} catch (SftpException e) {
// 理论上不应该失败除非根目录都不可访问
throw new ServiceException();
}
for (String dir : pathElements) {
if (dir == null || dir.isEmpty()) {
continue; // 跳过空的路径元素比如路径以/开头
}
currentDir.append("/").append(dir);
try {
channelSftp.cd(currentDir.toString());
// System.out.println("目录已存在: " + currentDir.toString());
} catch (SftpException e) {
if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
// 目录不存在创建它
try {
System.out.println("创建目录: " + currentDir.toString());
channelSftp.mkdir(currentDir.toString());
channelSftp.cd(currentDir.toString()); // 创建后进入该目录
System.out.println("目录创建成功并进入: " + currentDir.toString());
} catch (SftpException e2) {
throw new SftpException(e2.id, "无法创建远程目录: " + currentDir.toString(), e2);
}
} else {
// 其他 SFTP 异常
throw new SftpException(e.id, "切换或检查远程目录失败: " + currentDir.toString(), e);
}
}
}
}
// 自定义异常类用于封装上传过程中的错误
public static class SftpUploadException extends Exception {
public SftpUploadException(String message) {
super(message);
}
public SftpUploadException(String message, Throwable cause) {
super(message, cause);
}
}
// 示例用法
public static void main(String[] args) {
// 使用密码认证示例
try {
System.out.println("--- 开始通过密码认证 SFTP 上传 ---");
SftpUploadUtil.uploadFileViaSftp(
"your-remote-server-ip", // 替换为你的远程服务器IP或主机名
22, // SFTP端口 (如果不是22请修改)
"your-username", // 替换为你的 SFTP 用户名
"your-password", // 替换为你的 SFTP 密码
null, // SSH Key 路径 (密码认证时为 null)
"path/to/your/local/file.txt", // 替换为你要上传的本地文件路径
"/upload/target/directory/", // 替换为远程服务器上的目标目录 (确保用户有写入权限)
"uploaded_file.txt" // 上传到远程服务器的文件名 (null 或空则使用本地文件名)
);
System.out.println("文件通过密码认证 SFTP 上传成功!");
} catch (SftpUploadException e) {
System.err.println("文件通过密码认证 SFTP 上传失败: " + e.getMessage());
e.printStackTrace();
}
System.out.println("\n------------------------------------\n");
// 使用 SSH Key 认证示例 (假设你有一个私钥文件)
// 请确保你的 SSH Key 不需要密码 (passphrase)
try {
System.out.println("--- 开始通过 SSH Key 认证 SFTP 上传 ---");
SftpUploadUtil.uploadFileViaSftp(
"your-remote-server-ip", // 替换为你的远程服务器IP或主机名
null, // SFTP端口 (使用默认端口 22)
"your-username", // 替换为你的 SFTP 用户名
null, // 密码 (SSH Key 认证时为 null)
"/path/to/your/private/key",// 替换为你的本地私钥文件路径 (例如: /home/user/.ssh/id_rsa)
"path/to/another/local/file.log", // 替换为另一个你要上传的本地文件路径
"/upload/other/files/", // 替换为另一个远程目录
null // 远程文件名使用本地文件名
);
System.out.println("文件通过 SSH Key 认证 SFTP 上传成功!");
} catch (SftpUploadException e) {
System.err.println("文件通过 SSH Key 认证 SFTP 上传失败: " + e.getMessage());
e.printStackTrace();
}
System.out.println("\n------------------------------------\n");
}
}

View File

@ -0,0 +1,30 @@
package cd.casic.server;
import cd.casic.ci.process.process.dataObject.machine.MachineInfo;
import cd.casic.ci.process.process.service.machine.MachineInfoService;
import cd.casic.ci.process.util.CryptogramUtil;
import cd.casic.ci.process.util.SftpUploadUtil;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestClassOrder;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.stereotype.Service;
import org.springframework.test.context.ActiveProfiles;
import java.io.File;
@SpringBootTest(classes = {OpsServerApplication.class})
@ActiveProfiles("local")
public class SftpTest {
@Resource
MachineInfoService machineInfoService;
@Test
public void test01() throws SftpUploadUtil.SftpUploadException {
MachineInfo byId = machineInfoService.getById("1");
File file = new File("src/test/java/cd/casic/server/text.txt");
System.out.println(file.getAbsolutePath());
System.out.println(file.exists());
System.out.println(file.getName());
SftpUploadUtil.uploadFileViaSftp(byId.getMachineHost(),byId.getSshPort(),byId.getUsername(), CryptogramUtil.doDecrypt(byId.getPassword()),null,file.getAbsolutePath(),"/home/casic/706/ai_test_527","到此一游.txt");
}
}