Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions build-image-coding.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -euo pipefail
export DOCKER_BUILDKIT=1

DOCKERHUB_USER="${DOCKERHUB_USER:-yunomix2834}"
IMAGE_TAG="${IMAGE_TAG:-$(date +%Y%m%d.%H%M%S)}"

# Xác định DOCKER_GID an toàn
if [[ "$OSTYPE" == "darwin"* ]]; then
DOCKER_GID=999
elif [ -S /var/run/docker.sock ]; then
DOCKER_GID=$(stat -c '%g' /var/run/docker.sock 2>/dev/null || echo 999)
else
DOCKER_GID=999
fi

login() {
[ -n "$DOCKERHUB_TOKEN" ] && echo "$DOCKERHUB_TOKEN" | docker login -u "$DOCKERHUB_USER" --password-stdin
}

build_push_java() {
local module=$1
local build_args=("--build-arg" "MODULE=$module")

if [[ "$module" == "coding-service" ]]; then
build_args+=(
"--build-arg" "DOCKER_HOST_GID=${DOCKER_GID}"
)
fi

docker buildx build \
-f docker/java-service-coding.Dockerfile \
"${build_args[@]}" \
-t "$DOCKERHUB_USER/codecampus-$module:$IMAGE_TAG" \
--push .
}

main() {
login
echo "Building with DOCKER_GID=${DOCKER_GID}"

build_push_java coding-service
}

main "$@"
17 changes: 1 addition & 16 deletions build-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,6 @@ export DOCKER_BUILDKIT=1
DOCKERHUB_USER="${DOCKERHUB_USER:-yunomix2834}"
IMAGE_TAG="${IMAGE_TAG:-$(date +%Y%m%d.%H%M%S)}"

# Xác định DOCKER_GID an toàn
if [[ "$OSTYPE" == "darwin"* ]]; then
DOCKER_GID=999
elif [ -S /var/run/docker.sock ]; then
DOCKER_GID=$(stat -c '%g' /var/run/docker.sock 2>/dev/null || echo 999)
else
DOCKER_GID=999
fi

login() {
[ -n "$DOCKERHUB_TOKEN" ] && echo "$DOCKERHUB_TOKEN" | docker login -u "$DOCKERHUB_USER" --password-stdin
}
Expand All @@ -22,12 +13,6 @@ build_push_java() {
local module=$1
local build_args=("--build-arg" "MODULE=$module")

if [[ "$module" == "coding-service" ]]; then
build_args+=(
"--build-arg" "DOCKER_HOST_GID=${DOCKER_GID}"
)
fi

docker buildx build \
-f docker/java-service.Dockerfile \
"${build_args[@]}" \
Expand All @@ -39,7 +24,7 @@ main() {
login
echo "Building with DOCKER_GID=${DOCKER_GID}"

for svc in search-service profile-service identity-service; do
for svc in search-service; do
echo "Building $svc..."
build_push_java "$svc"
done
Expand Down
38 changes: 0 additions & 38 deletions build-service.sh

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

@Service
Expand All @@ -56,12 +54,13 @@ private static Path createWorkDir() throws IOException {
// Đảm bảo thư mục RUNNER_ROOT tồn tại và có quyền
if (!Files.exists(RUNNER_ROOT)) {
Files.createDirectories(RUNNER_ROOT);
Set<PosixFilePermission> rootPerms =
PosixFilePermissions.fromString("rwxrwxrwx");
Files.setPosixFilePermissions(RUNNER_ROOT, rootPerms);
Files.setPosixFilePermissions(
RUNNER_ROOT, PosixFilePermissions.fromString("rwxrwxrwx"));
}

Path workDir = Files.createTempDirectory(RUNNER_ROOT, "pg_");
Files.setPosixFilePermissions(
workDir, PosixFilePermissions.fromString(
"rwxrwxrwx"));
return workDir;
}

Expand All @@ -82,7 +81,12 @@ public SubmitCodeResponse judgeCodeSubmission(
.build();
codeSubmissionRepository.saveAndFlush(codeSubmission);

final int memoryMbLimit = codingExercise.getMemoryLimit() > 0 ?
codingExercise.getMemoryLimit() : 256;
final float cpusLimit = 0.5f;

int passedCount = 0;
int peakMemoryKb = 0;
List<TestCaseResultSyncDto> testCaseResultSyncDtoList =
new ArrayList<>();

Expand All @@ -95,33 +99,23 @@ public SubmitCodeResponse judgeCodeSubmission(
request.getLanguage(),
request.getSourceCode(),
workDir);
} catch (InterruptedException | IOException e) {
// compile failure từ DockerSandboxService.exec → log rồi rethrow
safeDeleteDir(workDir);
throw new RuntimeException(e);
} finally {
safeDeleteDir(workDir);
}

/* ====== Default limit khi client không set ====== */
int memoryMb = request.getMemoryMb() > 0 ? request.getMemoryMb() : 256;
float cpus = request.getCpus() > 0 ? request.getCpus() : 0.5f;

try {
for (TestCase testCase : codingExercise.getTestCases()) {
CodeResult codeResult = dockerSandboxService.runTest(
bin,
testCase,
memoryMb,
cpus);
memoryMbLimit,
cpusLimit);

if (codeResult.isPassed()) {
passedCount++;
}
peakMemoryKb = Math.max(peakMemoryKb, codeResult.getMemoryKb());

CodeSubmissionResult codeSubmissionResult =
CodeSubmissionResult.builder()
.submission(codeSubmission).testCase(testCase)
.submission(codeSubmission)
.testCase(testCase)
.passed(codeResult.isPassed())
.runtimeMs(codeResult.getRuntimeMs())
.memoryKb(codeResult.getMemoryKb())
Expand All @@ -144,7 +138,8 @@ public SubmitCodeResponse judgeCodeSubmission(
codeResult.getError())
.build());
}

} catch (InterruptedException | IOException e) {
throw new RuntimeException(e);
} finally {
safeDeleteDir(workDir);
}
Expand Down Expand Up @@ -174,6 +169,9 @@ public SubmitCodeResponse judgeCodeSubmission(
.setTimeTakenSeconds(
request.getTimeTakenSeconds())
.addAllResults(testCaseResultSyncDtoList)
.setPeakMemoryKb(peakMemoryKb)
.setCpus(cpusLimit)
.setMemoryMb(memoryMbLimit)
.build())
.build());

Expand All @@ -193,6 +191,9 @@ public SubmitCodeResponse judgeCodeSubmission(
.setErrorMessage(r.getErrorMessage())
.build())
.toList())
.setMemoryMb(memoryMbLimit)
.setCpus(cpusLimit)
.setPeakMemoryKb(peakMemoryKb)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.PosixFilePermission;
Expand Down Expand Up @@ -43,14 +44,12 @@ private static Path createWorkDir() throws IOException {
// Đảm bảo thư mục RUNNER_ROOT tồn tại và có quyền
if (!Files.exists(RUNNER_ROOT)) {
Files.createDirectories(RUNNER_ROOT);
Files.setPosixFilePermissions(
RUNNER_ROOT, PosixFilePermissions.fromString("rwxrwxrwx"));
}

// Tạo thư mục work với quyền 777
Path workDir = Files.createTempDirectory(RUNNER_ROOT, "pg_");
Set<PosixFilePermission> perms =
PosixFilePermissions.fromString("rwxrwxrwx");
Files.setPosixFilePermissions(workDir, perms);

Files.setPosixFilePermissions(
workDir, PosixFilePermissions.fromString("rwxrwxrwx"));
return workDir;
}

Expand Down Expand Up @@ -89,17 +88,18 @@ public CompiledArtifact compile(

// 3. Tên nhị phân / jar random để tránh trùng
String binName = "bin_" + UUID.randomUUID();
String inPath = DockerHelper.inVolumePath(workDir);
final boolean inDocker = !DockerHelper.selfContainer().isBlank();
final String inPath = inDocker
? DockerHelper.inVolumePath(workDir)
: workDir.toString();

List<String> runBase = DockerHelper.selfContainer().isBlank()
List<String> runBase = inDocker
? DockerHelper.cmd("run", "--rm",
"-v", RUNNER_VOLUME + ":/work",
"-w", inPath,
SANDBOX_IMAGE)
: DockerHelper.cmd("run", "--rm",
"--volumes-from", DockerHelper.selfContainer(),
"-w", inPath,
SANDBOX_IMAGE);
"-w", inPath, SANDBOX_IMAGE)
: DockerHelper.cmd("run", "--rm",
"-v", RUNNER_ROOT + ":" + RUNNER_ROOT,
"-w", inPath, SANDBOX_IMAGE);

ProcessBuilder compilePb = switch (language) {
case "cpp" -> new ProcessBuilder(
Expand Down Expand Up @@ -130,24 +130,27 @@ public CodeResult runTest(
int memoryMb,
float cpus) {
String container = "judge_" + UUID.randomUUID();
String inPath = DockerHelper.inVolumePath(compiledArtifact.workDir());
boolean inDocker = !DockerHelper.selfContainer().isBlank();
String inPath = inDocker
? DockerHelper.inVolumePath(compiledArtifact.workDir())
: compiledArtifact.workDir().toString();

try {
/* 1. khởi tạo container rỗng, giới hạn RAM + CPU, network none */
List<String> startArgs = DockerHelper.selfContainer().isBlank()
// 1) khởi tạo container rỗng, giới hạn RAM + CPU, network none
List<String> startArgs = inDocker
? DockerHelper.cmd("run", "-dit",
"--memory=%sm".formatted(memoryMb),
"--cpus=" + cpus,
"--network", "none",
"-v", RUNNER_VOLUME + ":/work",
"--volumes-from", DockerHelper.selfContainer(),
"-w", inPath,
"--name", container,
SANDBOX_IMAGE, "bash")
: DockerHelper.cmd("run", "-dit",
"--memory=%sm".formatted(memoryMb),
"--cpus=" + cpus,
"--network", "none",
"--volumes-from", DockerHelper.selfContainer(),
"-v", inPath + ":" + inPath,
"-w", inPath,
"--name", container,
SANDBOX_IMAGE, "bash");
Expand All @@ -161,7 +164,7 @@ public CodeResult runTest(
default -> throw new IllegalStateException();
};

/* Chạy */
// 2) run + feed input
long startTime = System.nanoTime();
Process run = new ProcessBuilder(
Stream.concat(
Expand All @@ -180,17 +183,28 @@ public CodeResult runTest(
int exitCode = run.waitFor();
long endTime = System.nanoTime();

// 3) đo memory trước khi rm
int memoryKb = 0;
try {
memoryKb = readContainerMemKb(container);
} catch (Exception e) {
log.warn("Read memory usage failed: {}", e.toString());
}

boolean passed =
exitCode == 0 && equal(out, testCase.getExpectedOutput());

return new CodeResult(
passed,
(int) ((endTime - startTime) / 1_000_000),
0, out.trim(), err.trim());
memoryKb, out.trim(), err.trim());

} catch (Exception ex) {
log.error("Sandbox error", ex);
return new CodeResult(false, 0, 0, "", ex.getMessage());
return new CodeResult(
false,
0, 0,
"", ex.getMessage());
} finally {
silent(DockerHelper.cmd("rm", "-f", container)
.toArray(new String[0]));
Expand All @@ -210,6 +224,20 @@ void exec(ProcessBuilder processBuilder)
}
}

int readContainerMemKb(String container)
throws IOException, InterruptedException {
Process process = new ProcessBuilder(
DockerHelper.cmd("exec", container, "bash", "-c",
"cat /sys/fs/cgroup/memory.current || cat /sys/fs/cgroup/memory/memory.usage_in_bytes"))
.start();

String output = new String(process.getInputStream().readAllBytes(),
StandardCharsets.UTF_8).trim();
process.waitFor();
long bytes = Long.parseLong(output);
return (int) (bytes / 1024);
}

String read(InputStream inputStream)
throws IOException {
return new String(inputStream.readAllBytes());
Expand Down
Binary file not shown.
3 changes: 0 additions & 3 deletions common-events/target/maven-archiver/pom.properties

This file was deleted.

This file was deleted.

Loading