197 lines
7.6 KiB
Java
197 lines
7.6 KiB
Java
package cd.casic.server;
|
|
import com.github.dockerjava.api.DockerClient;
|
|
import com.github.dockerjava.api.command.CreateContainerResponse;
|
|
import com.github.dockerjava.api.command.ExecCreateCmdResponse;
|
|
import com.github.dockerjava.api.model.Bind;
|
|
import com.github.dockerjava.api.model.Frame;
|
|
import com.github.dockerjava.api.model.HostConfig;
|
|
import com.github.dockerjava.core.DockerClientBuilder;
|
|
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.springframework.boot.test.context.SpringBootTest;
|
|
import org.springframework.test.context.ActiveProfiles;
|
|
|
|
import java.io.IOException;
|
|
import java.net.URI;
|
|
import java.net.URISyntaxException;
|
|
import java.util.concurrent.TimeUnit;
|
|
@SpringBootTest(classes = {OpsServerApplication.class})
|
|
@ActiveProfiles("local")
|
|
public class DockerTest {
|
|
// TODO 测试通过,明天继续整通用的
|
|
public static String executeParsedDockerCommand(
|
|
String dockerHostUri,
|
|
String dockerRunCommand,
|
|
String[] commandInContainer,
|
|
int execTimeoutMinutes) {
|
|
|
|
// 1. 解析docker run命令
|
|
String[] parts = dockerRunCommand.split("\\s+");
|
|
if (parts.length < 6 || !"docker".equals(parts[0]) || !"run".equals(parts[1])) {
|
|
throw new RuntimeException("Invalid docker run command format");
|
|
}
|
|
|
|
// 2. 提取参数
|
|
String volumeArg = null;
|
|
String imageName = null;
|
|
String initialCommand = null;
|
|
|
|
for (int i = 2; i < parts.length; i++) {
|
|
if ("-v".equals(parts[i]) && i + 1 < parts.length) {
|
|
volumeArg = parts[++i];
|
|
} else if ("-it".equals(parts[i])) {
|
|
// 跳过交互式参数
|
|
} else if (imageName == null) {
|
|
imageName = parts[i];
|
|
} else if (initialCommand == null) {
|
|
initialCommand = parts[i];
|
|
}
|
|
}
|
|
|
|
if (volumeArg == null || imageName == null) {
|
|
throw new RuntimeException("Missing required parameters in docker run command");
|
|
}
|
|
|
|
// 3. 解析卷挂载参数
|
|
String[] volumeParts = volumeArg.split(":");
|
|
if (volumeParts.length != 2) {
|
|
throw new RuntimeException("Invalid volume format, expected host_path:container_path");
|
|
}
|
|
String hostPath = volumeParts[0];
|
|
String containerPath = volumeParts[1];
|
|
|
|
ApacheDockerHttpClient httpClient;
|
|
try {
|
|
httpClient = new ApacheDockerHttpClient.Builder().dockerHost(new URI(dockerHostUri)).build();
|
|
} catch (URISyntaxException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
DockerClient dockerClient = DockerClientBuilder.getInstance().withDockerHttpClient(httpClient).build();
|
|
try {
|
|
// 5. 创建容器
|
|
HostConfig hostConfig = HostConfig.newHostConfig()
|
|
.withBinds(Bind.parse(volumeArg));
|
|
|
|
CreateContainerResponse container = dockerClient.createContainerCmd(imageName)
|
|
.withHostConfig(hostConfig)
|
|
.withCmd(initialCommand)
|
|
.withTty(true)
|
|
.exec();
|
|
|
|
String containerId = container.getId();
|
|
|
|
// 6. 启动容器
|
|
dockerClient.startContainerCmd(containerId).exec();
|
|
|
|
try {
|
|
// 7. 构建要在容器内执行的完整命令
|
|
String[] fullCommand = new String[commandInContainer.length + 2];
|
|
fullCommand[0] = "sh";
|
|
fullCommand[1] = "-c";
|
|
fullCommand[2] = "cd " + containerPath + " && " + StringUtils.join(commandInContainer, " ");
|
|
// System.arraycopy(commandInContainer, 0, fullCommand, 3, commandInContainer.length - 1);
|
|
|
|
// 8. 创建exec实例
|
|
ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(containerId)
|
|
.withAttachStdout(true)
|
|
.withAttachStderr(true)
|
|
.withCmd(fullCommand)
|
|
.exec();
|
|
|
|
// 9. 执行命令并获取输出
|
|
String output = dockerClient.execStartCmd(execCreateCmdResponse.getId())
|
|
.exec(new ExecStartResultCallback())
|
|
.awaitOutput(execTimeoutMinutes, TimeUnit.MINUTES);
|
|
|
|
return output;
|
|
} finally {
|
|
// 10. 清理容器
|
|
dockerClient.stopContainerCmd(containerId).exec();
|
|
dockerClient.removeContainerCmd(containerId).exec();
|
|
}
|
|
} finally {
|
|
try {
|
|
dockerClient.close();
|
|
} catch (IOException e) {
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
private static class ExecStartResultCallback extends com.github.dockerjava.api.async.ResultCallback.Adapter<Frame> {
|
|
private final StringBuilder output = new StringBuilder();
|
|
|
|
@Override
|
|
public void onNext(Frame frame) {
|
|
output.append(new String(frame.getPayload()));
|
|
}
|
|
|
|
public String awaitOutput(long timeout, TimeUnit timeUnit) {
|
|
try {
|
|
super.awaitCompletion(timeout, timeUnit);
|
|
} catch (InterruptedException e) {
|
|
Thread.currentThread().interrupt();
|
|
throw new RuntimeException("Command execution interrupted", e);
|
|
}
|
|
return output.toString();
|
|
}
|
|
}
|
|
|
|
// 示例用法
|
|
@Test
|
|
public void test() {
|
|
// *** 请将此处的远程 Docker TCP 地址替换为您实际的值 ***
|
|
String remoteDockerHostUri = "tcp://175.6.27.228:22375"; // <-- !!! REPLACE THIS !!!
|
|
|
|
// *** 提供您希望解析的 docker run 命令字符串 ***
|
|
// 注意:此解析器仅支持简化的格式
|
|
String dockerRunCmdString = "docker run -v /home/yunqi/:/test -it aflplusplus/aflplusplus bash";
|
|
System.out.println("待解析并执行的 Docker run 命令: " + dockerRunCmdString);
|
|
|
|
|
|
// 要在容器内执行的 afl-fuzz 命令及其参数
|
|
// 这部分仍然需要单独提供,因为解析器不负责从 docker run 命令中提取后续要 exec 的命令
|
|
String[] aflFuzzCommand = {
|
|
"afl-fuzz",
|
|
"-i", "case",
|
|
"-o", "ai_afl",
|
|
"-t", "3000",
|
|
"-Q",
|
|
"./CaseGenerator/testdata/libpng/libpng/pngfix",
|
|
"@@"
|
|
};
|
|
System.out.print("将在容器内执行的命令: ");
|
|
for (String arg : aflFuzzCommand) {
|
|
System.out.print(arg + " ");
|
|
}
|
|
System.out.println();
|
|
|
|
|
|
// 命令执行超时时间(分钟)
|
|
int commandTimeoutMinutes = 60; // 例如,给 afl-fuzz 60 分钟运行时间
|
|
|
|
try {
|
|
// 调用解析并执行的方法
|
|
System.out.println("\n开始执行解析后的 Docker 命令序列...");
|
|
String aflOutput = executeParsedDockerCommand(
|
|
remoteDockerHostUri,
|
|
dockerRunCmdString,
|
|
aflFuzzCommand,
|
|
commandTimeoutMinutes
|
|
);
|
|
|
|
System.out.println("\n--- AFL-fuzz 命令的标准输出 ---");
|
|
System.out.println(aflOutput);
|
|
System.out.println("------------------------------");
|
|
|
|
} catch (RuntimeException e) {
|
|
System.err.println("\n--- 执行过程中发生错误 ---");
|
|
System.err.println(e.getMessage());
|
|
e.printStackTrace();
|
|
System.err.println("---------------------------");
|
|
}
|
|
}
|
|
|
|
}
|