diff --git a/docker/compose.yml b/docker/compose.yml index 54a9723..d0713bb 100644 --- a/docker/compose.yml +++ b/docker/compose.yml @@ -3,10 +3,10 @@ services: image: ghcr.io/gurkengewuerz/gitcodejudge-server:latest restart: unless-stopped networks: [traefik] - volumes: - ${CONTAINER_DIR}/judge/tests:/test_cases - ${CONTAINER_DIR}/judge/db:/db + - ${CONTAINER_DIR}/judge/repos:/repos - /var/run/docker.sock:/var/run/docker.sock:ro environment: - BASE_URL=https://$VIRTUAL_HOST diff --git a/internal/judge/container.go b/internal/judge/container.go new file mode 100644 index 0000000..b01615e --- /dev/null +++ b/internal/judge/container.go @@ -0,0 +1,105 @@ +package judge + +import ( + "bufio" + "errors" + "fmt" + log "github.com/sirupsen/logrus" + "os" + "strings" +) + +var ( + isDocker bool + dockerRepoPath string +) + +// init runs when the package is initialized +func init() { + var err error + isDocker, err = checkIfDocker() + if err != nil { + log.WithError(err).Warn("Failed to check if running in Docker") + isDocker = false + } + + if isDocker { + dockerRepoPath, err = findDockerVolumePath("/repos") + if err != nil { + log.WithError(err).Fatal("Failed to find Docker volume path for /repos") + panic("Docker volume /repos must be mounted") + } + log.WithFields(log.Fields{ + "isDocker": isDocker, + "dockerRepoPath": dockerRepoPath, + }).Info("Docker environment detected") + } +} + +// getTempDir returns the appropriate temporary directory path based on the environment +func getTempDir(prefix string) (string, error) { + if isDocker { + // When in Docker, create temp dir under the host path + return os.MkdirTemp(dockerRepoPath, prefix) + } + // Default behavior when not in Docker + return os.MkdirTemp("", prefix) +} + +// checkIfDocker checks if the current process is running inside a Docker container +func checkIfDocker() (bool, error) { + // Method 1: Check for .dockerenv file + if _, err := os.Stat("/.dockerenv"); err == nil { + return true, nil + } + + // Method 2: Check cgroup + file, err := os.Open("/proc/1/cgroup") + if err != nil { + return false, err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + if strings.Contains(scanner.Text(), "docker") { + return true, nil + } + } + + return false, nil +} + +// findDockerVolumePath finds the host path of a mounted Docker volume +func findDockerVolumePath(containerPath string) (string, error) { + // Read mountinfo to find the host path + file, err := os.Open("/proc/self/mountinfo") + if err != nil { + return "", err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + fields := strings.Fields(scanner.Text()) + if len(fields) < 5 { + continue + } + + mountPoint := fields[4] + if mountPoint == containerPath { + // The source path is typically in the 3rd field + sourcePath := fields[3] + if sourcePath == "" { + return "", errors.New("empty source path for volume") + } + return sourcePath, nil + } + } + + if err := scanner.Err(); err != nil { + return "", fmt.Errorf("error reading mountinfo: %v", err) + } + + return "", fmt.Errorf("volume path %s not found in mountinfo", containerPath) +} diff --git a/internal/judge/docker.go b/internal/judge/docker.go index b1eae94..b529ccf 100644 --- a/internal/judge/docker.go +++ b/internal/judge/docker.go @@ -1,21 +1,21 @@ package judge import ( - "bytes" - "context" - "fmt" - "github.com/docker/docker/api/types/image" - "github.com/docker/docker/pkg/stdcopy" - "github.com/gurkengewuerz/GitCodeJudge/internal/config" - "github.com/gurkengewuerz/GitCodeJudge/internal/models" - log "github.com/sirupsen/logrus" - "io" - "os" - "path/filepath" - "time" - - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/client" + "bytes" + "context" + "fmt" + "github.com/docker/docker/api/types/image" + "github.com/docker/docker/pkg/stdcopy" + "github.com/gurkengewuerz/GitCodeJudge/internal/config" + "github.com/gurkengewuerz/GitCodeJudge/internal/models" + log "github.com/sirupsen/logrus" + "io" + "os" + "path/filepath" + "time" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/client" ) type DockerExecutor struct { @@ -41,7 +41,7 @@ func NewDockerExecutor(network string, timeoutSeconds int) (*DockerExecutor, err func (e *DockerExecutor) RunCode(ctx context.Context, testCase models.TestCase) (*models.ExecutionResult, error) { // Create temp directory for code and test files - tmpDir, err := os.MkdirTemp("", "judge-*") + tmpDir, err := getTempDir("judge-*") if err != nil { return nil, fmt.Errorf("failed to create temp dir: %v", err) } diff --git a/internal/judge/executor.go b/internal/judge/executor.go index f19a4f8..622f11f 100644 --- a/internal/judge/executor.go +++ b/internal/judge/executor.go @@ -46,7 +46,7 @@ func Trim(s string) string { } func (e *Executor) Execute(submission models.Submission) (*models.TestResult, error) { - repoTmpDir, err := os.MkdirTemp("", "jrepo-*") + repoTmpDir, err := getTempDir("jrepo-*") if err != nil { return nil, fmt.Errorf("failed to create temp dir: %v", err) }