diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..976fbbc --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +# top +/woj + +# runner +resource/runner/.mark.container +resource/runner/problem/* +resource/runner/tmp/* +resource/runner/user/* diff --git a/.idea/jsonSchemas.xml b/.idea/jsonSchemas.xml new file mode 100644 index 0000000..3120128 --- /dev/null +++ b/.idea/jsonSchemas.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Makefile b/Makefile index f8da8e8..45de93c 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,12 @@ GO := go -LDFLAGS += -X cmd.BuildTime=$(shell date -u '+%Y-%m-%d-%I-%M-%S') -LDFLAGS += -X cmd.Version=$(shell cat VERSION)+$(shell git rev-parse --short HEAD) -LDFLAGS += -X cmd.SentryDSN=$(shell cat dsn.txt) +PKG_BASE := $(shell head -n 1 go.mod | awk '{print $$2}') +BUILD_TIME := $(shell date -u '+%Y%m%d-%I%M%S') +VERSION := $(shell cat VERSION)+$(shell git rev-parse --short HEAD) + +LDFLAGS += -X $(PKG_BASE)/cmd.BuildTime=$(BUILD_TIME) +LDFLAGS += -X $(PKG_BASE)/cmd.Version=$(VERSION) +LDFLAGS += -X $(PKG_BASE)/cmd.SentryDSN=$(shell cat dsn.txt) LDFLAGS += -s -w GOBUILD := $(GO) build -ldflags '$(LDFLAGS)' @@ -18,8 +22,7 @@ build: swagger dep $(GOBUILD) -o woj ./cmd/woj clean: - rm -f runner - rm -f server + rm -f woj dep: go mod download diff --git a/Runner.Dockerfile b/Runner.Dockerfile new file mode 100644 index 0000000..b58e46a --- /dev/null +++ b/Runner.Dockerfile @@ -0,0 +1,35 @@ +# builder +FROM docker.io/library/golang:alpine AS builder + +ENV GOPROXY=https://goproxy.cn +WORKDIR /builder + +RUN apk add --no-cache git make +RUN go install github.com/swaggo/swag/cmd/swag@latest + +COPY go.mod /builder/go.mod +COPY go.sum /builder/go.sum +RUN go mod download + +COPY . /builder +RUN make build + + +# main image +FROM quay.io/podman/stable + +# pkill +RUN yum -y install jq procps-ng && yum -y clean all && rm -rf /var/cache + +WORKDIR /app + +# prepare images +COPY --from=builder /builder/resource/runner /app/resource/runner +RUN bash -c "cd /app/resource/runner/scripts && ./prepare_images.sh save" + +# sources +COPY --from=builder /builder/config.docker.yaml /app +COPY --from=builder /builder/docker-entrypoint.sh /app +COPY --from=builder /builder/woj /app + +ENTRYPOINT ["/app/docker-entrypoint.sh"] diff --git a/Dockerfile b/Server.Dockerfile similarity index 75% rename from Dockerfile rename to Server.Dockerfile index 71692e5..e82eeae 100644 --- a/Dockerfile +++ b/Server.Dockerfile @@ -1,5 +1,5 @@ # builder -FROM golang:alpine AS builder +FROM docker.io/library/golang:alpine AS builder ENV GOPROXY=https://goproxy.cn WORKDIR /builder @@ -16,16 +16,14 @@ RUN make build # main image -FROM alpine:latest +FROM docker.io/library/alpine WORKDIR /app -RUN apk --no-cache add tzdata ca-certificates libc6-compat +RUN apk --no-cache add tzdata ca-certificates libc6-compat bash COPY --from=builder /builder/config.docker.yaml /app COPY --from=builder /builder/docker-entrypoint.sh /app COPY --from=builder /builder/resource/frontend /app/resource/frontend -COPY --from=builder /builder/resource/runner /app/resource/runner - COPY --from=builder /builder/woj /app ENTRYPOINT ["/app/docker-entrypoint.sh"] diff --git a/build_image.sh b/build_image.sh new file mode 100755 index 0000000..d522837 --- /dev/null +++ b/build_image.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +. resource/runner/scripts/common.sh + +# version +VERSION="$(cat VERSION)" +log_info "VERSION: $VERSION" + +function build_base() { + log_info "[+] Building Base Images" + pushd resource/runner/scripts || exit 1 + $DOCKER build -t git.0x7f.app/woj/ubuntu-full:latest -f scripts/ubuntu-full.Dockerfile . || + (log_error "Build Full Image failed" && exit 1) + $DOCKER build -t git.0x7f.app/woj/ubuntu-run:latest -f scripts/ubuntu-run.Dockerfile . || + (log_error "Build Tiny Image failed" && exit 1) + popd +} + +function push_base() { + log_info "[+] Pushing Base Images" + $DOCKER push "git.0x7f.app/woj/ubuntu-full:latest" + $DOCKER push "git.0x7f.app/woj/ubuntu-run:latest" +} + +function build_server() { + log_info "[+] Building Server" + $DOCKER build -t "git.0x7f.app/woj/woj-server:$VERSION" -f Server.Dockerfile . || + (log_error "[!] Failed to build Server" && exit 1) +} + +function build_runner() { + log_info "[+] Building Runner" + $DOCKER build \ + --cap-add=sys_admin,mknod \ + --device=/dev/fuse \ + --security-opt label=disable \ + -t "git.0x7f.app/woj/woj-runner:$VERSION" \ + -f Runner.Dockerfile . || + (log_error "[!] Failed to build Runner" && exit 1) +} + +function push_server() { + log_info "[+] Pushing Server Images" + $DOCKER push "git.0x7f.app/woj/woj-server:$VERSION" +} + +function push_runner() { + log_info "[+] Pushing Runner Images" + $DOCKER push "git.0x7f.app/woj/woj-runner:$VERSION" +} + +# build_base +# push_base +build_server +push_server +build_runner +push_runner diff --git a/cmd/common.go b/cmd/common.go index a0b8f8e..dc74753 100644 --- a/cmd/common.go +++ b/cmd/common.go @@ -59,7 +59,7 @@ func init() { } func getBuildTime() time.Time { - build, err := time.Parse("2006-01-02-15-04-05", BuildTime) + build, err := time.Parse("20060102-150405", BuildTime) if err != nil { log.Printf("failed to parse build time: %v", err) build = time.Now() diff --git a/docker-compose.yml b/docker-compose.yml index ac68d45..98b43dc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,9 @@ -version: "3" - services: server: - build: . + image: git.0x7f.app/woj/woj-server:1.1.0 restart: unless-stopped healthcheck: - test: [ "CMD", "wget", "-q", "http://127.0.0.1:8000/health" ] + test: [ "CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8000/health" ] interval: 5s command: web environment: @@ -14,7 +12,7 @@ services: - DATABASE_USER=dev - DATABASE_PASSWORD=password - DATABASE_NAME=dev - - STORAGE_ENDPOINT=minio:9000 + - STORAGE_ENDPOINT=storage:9000 - STORAGE_ACCESS_KEY=access_key - STORAGE_SECRET_KEY=secret_key - STORAGE_BUCKET=woj @@ -23,6 +21,8 @@ services: - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro depends_on: + runner: + condition: service_started storage: condition: service_healthy cache: @@ -32,22 +32,36 @@ services: ports: - "8000:8000" - #runner: - # build: . - # restart: unless-stopped - # command: runner - # environment: - # - REDIS_ADDRESS_PORT=cache:6379 - # - DEVELOPMENT=true - # volumes: - # - runner:/app/resource/runner/user - # - /etc/timezone:/etc/timezone:ro - # - /etc/localtime:/etc/localtime:ro - # depends_on: - # - cache + runner: + image: git.0x7f.app/woj/woj-runner:1.1.0 + restart: unless-stopped + command: runner + security_opt: + - "label=disable" + cap_add: + - SYS_ADMIN + - MKNOD + devices: + - "/dev/fuse" + environment: + - REDIS_ADDRESS_PORT=cache:6379 + - STORAGE_ENDPOINT=storage:9000 + - STORAGE_ACCESS_KEY=access_key + - STORAGE_SECRET_KEY=secret_key + - STORAGE_BUCKET=woj + - DEVELOPMENT=true + volumes: + - runner:/app/resource/runner/user + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + depends_on: + storage: + condition: service_healthy + cache: + condition: service_healthy storage: - image: minio/minio:latest + image: quay.io/minio/minio:latest restart: unless-stopped healthcheck: test: [ "CMD", "curl", "-f", "http://127.0.0.1:9000/minio/health/live" ] @@ -55,13 +69,13 @@ services: entrypoint: sh command: -c 'mkdir -p /data/woj && minio server /data' environment: - MINIO_ACCESS_KEY: "access_key" - MINIO_SECRET_KEY: "secret_key" + MINIO_ROOT_USER: "access_key" + MINIO_ROOT_PASSWORD: "secret_key" volumes: - storage:/data cache: - image: redis:alpine + image: docker.io/library/redis:alpine restart: unless-stopped healthcheck: test: [ "CMD", "redis-cli", "ping" ] @@ -70,7 +84,7 @@ services: - cache:/data db: - image: postgres:alpine + image: docker.io/library/postgres:alpine restart: unless-stopped healthcheck: test: [ "CMD", "pg_isready", "-U", "dev" ] @@ -86,4 +100,4 @@ volumes: runner: storage: cache: - db: \ No newline at end of file + db: diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 4728bdd..e950e71 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -1,4 +1,4 @@ -#!/bin/ash +#!/bin/bash set -eo pipefail COLOR_RED="\e[0;31m" diff --git a/internal/service/runner/deps.go b/internal/service/runner/deps.go index c968ec0..1aee7f9 100644 --- a/internal/service/runner/deps.go +++ b/internal/service/runner/deps.go @@ -18,7 +18,7 @@ func (s *service) EnsureDeps(force bool) e.Status { return e.Success } - script := filepath.Join(ScriptsDir, "prepare_container.sh") + script := filepath.Join(ScriptsDir, "prepare_images.sh") cmd := exec.Command(script) cmd.Dir = ScriptsDir err := cmd.Run() diff --git a/resource/runner/.gitignore b/resource/runner/.gitignore index 8a603d9..0f3e631 100644 --- a/resource/runner/.gitignore +++ b/resource/runner/.gitignore @@ -1,7 +1,4 @@ # docker image mark .mark.* -# tmp dockerfile -ubuntu-full.Dockerfile -ubuntu-run.Dockerfile # other tmp files *.zip diff --git a/resource/runner/scripts/common.sh b/resource/runner/scripts/common.sh index 72dd11c..408ed96 100755 --- a/resource/runner/scripts/common.sh +++ b/resource/runner/scripts/common.sh @@ -10,5 +10,8 @@ function log_warn() { echo -e "${COLOR_YELLOW}$*${COLOR_NONE}" 1>&2; } function log_error() { echo -e "${COLOR_RED}$*${COLOR_NONE}" 1>&2; } # Docker or Podman -DOCKER="docker" -if [ "$USE_PODMAN" ]; then DOCKER="podman"; fi +DOCKER="podman" +if [ "$USE_DOCKER" ]; then + log_error "docker is deprecated" + log_info "Use podman instead" +fi diff --git a/resource/runner/scripts/prepare_container.sh b/resource/runner/scripts/prepare_container.sh deleted file mode 100755 index 0987ee4..0000000 --- a/resource/runner/scripts/prepare_container.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash - -. common.sh - -cd "$(dirname "$0")"/../ || exit 1 - -# Check Mark -if [ -f ./.mark.container ]; then - log_warn "Docker containers already prepared" - log_warn "If you want to re-prepare the containers, please remove the file $(pwd)/.mark.container" - exit 1 -fi - -log_info "Preparing container..." -log_info "Using $DOCKER - $($DOCKER --version)" - -# Full -log_info "Building Full Image" -cat <ubuntu-full.Dockerfile -FROM docker.io/library/ubuntu:22.04 -WORKDIR /woj/ - -# Install dependencies -RUN apt-get update && apt-get upgrade -y && apt-get install -y gcc g++ clang make cmake autoconf m4 libtool gperf git parallel python3 && apt-get clean && rm -rf /var/lib/apt/lists - -# Copy source code -RUN mkdir -p /woj/framework && mkdir -p /woj/problem -COPY framework /woj/framework - -# Build -RUN cd /woj/framework/template && ./setup.sh -RUN cd /woj/framework/scripts && ./setup.sh - -# Environment -ENV WOJ_LAUNCHER=/woj/framework/scripts/woj_launcher -ENV WOJ_SANDBOX=/woj/framework/scripts/libwoj_sandbox.so -ENV TEMPLATE=/woj/framework/template -ENV TESTLIB=/woj/framework/template/testlib -ENV PREFIX=/woj/problem -EOF -$DOCKER build -t woj/ubuntu-full -f ubuntu-full.Dockerfile . || exit 1 -rm ubuntu-full.Dockerfile - -# Tiny -log_info "Building Tiny Image" -cat <ubuntu-run.Dockerfile -FROM woj/ubuntu-full:latest AS builder -FROM docker.io/library/ubuntu:22.04 -WORKDIR /woj/problem -RUN mkdir -p /woj/framework/scripts -COPY --from=builder /woj/framework/scripts/libwoj_sandbox.so /woj/framework/scripts/ -COPY --from=builder /woj/framework/scripts/woj_launcher /woj/framework/scripts/ -EOF -$DOCKER build -t woj/ubuntu-run -f ubuntu-run.Dockerfile . || exit 1 -rm ubuntu-run.Dockerfile - -touch ./.mark.container - -log_info "Done" diff --git a/resource/runner/scripts/prepare_images.sh b/resource/runner/scripts/prepare_images.sh new file mode 100755 index 0000000..f03c696 --- /dev/null +++ b/resource/runner/scripts/prepare_images.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +. common.sh + +cd "$(dirname "$0")"/../ || exit 1 + +# Check Mark +if [ -f ./.mark.image ]; then + log_warn "Docker images already prepared" + log_warn "If you want to re-prepare the images, please remove the file $(pwd)/.mark.image" + exit 1 +fi + +log_info "Preparing image..." +log_info "Checking $DOCKER - $($DOCKER --version)" + +# Full +if [ -f ./tmp/ubuntu-full.tar.gz ]; then + log_info "Importing Full Image" + gzip -d -c ./tmp/ubuntu-full.tar.gz | $DOCKER load || (log_error "Import Full Image failed" && exit 1) +else + log_info "Pulling Full Image" + if ! $DOCKER pull git.0x7f.app/woj/ubuntu-full:latest; then + log_warn "Pull failed, building from scratch" + log_info "Building Full Image" + $DOCKER build -t git.0x7f.app/woj/ubuntu-full:latest -f scripts/ubuntu-full.Dockerfile . || (log_error "Build Full Image failed" && exit 1) + fi +fi + +# Tiny +if [ -f ./tmp/ubuntu-tiny.tar.gz ]; then + log_info "Importing Tiny Image" + gzip -d -c ./tmp/ubuntu-tiny.tar.gz | $DOCKER load || (log_error "Import Tiny Image failed" && exit 1) +else + log_info "Pulling Tiny Image" + if ! $DOCKER pull git.0x7f.app/woj/ubuntu-run:latest; then + log_warn "Pull failed, building from scratch" + log_info "Building Tiny Image" + $DOCKER build -t git.0x7f.app/woj/ubuntu-run:latest -f scripts/ubuntu-run.Dockerfile . || (log_error "Build Tiny Image failed" && exit 1) + fi +fi + +# Mark +if [ "$1" == "save" ]; then + log_info "Saving Images" + $DOCKER save git.0x7f.app/woj/ubuntu-full:latest | gzip -9 >./tmp/ubuntu-full.tar.gz + $DOCKER save git.0x7f.app/woj/ubuntu-run:latest | gzip -9 >./tmp/ubuntu-tiny.tar.gz +else + touch ./.mark.image +fi + +log_info "Done" diff --git a/resource/runner/scripts/problem.sh b/resource/runner/scripts/problem.sh index ef407a2..a9f2754 100755 --- a/resource/runner/scripts/problem.sh +++ b/resource/runner/scripts/problem.sh @@ -9,67 +9,67 @@ # $3: language # exports: Info_Script, Info_Cmp, Info_Num, Info_Limit_Time, Info_Limit_Memory, Info_Limit_NProc function get_problem_info() { - local err + local err - if [ ! -f "$1/problem/$2/config.json" ]; then - log_error "problem $2 not found" - return 1 - fi + if [ ! -f "$1/problem/$2/config.json" ]; then + log_error "problem $2 not found" + return 1 + fi - parse_language_info "$1" "$2" "$3" - err=$? - if [ "$err" -ne 0 ]; then - return "$err" - fi + parse_language_info "$1" "$2" "$3" + err=$? + if [ "$err" -ne 0 ]; then + return "$err" + fi - parse_limits "$1" "$2" - err=$? - if [ "$err" -ne 0 ]; then - return "$err" - fi + parse_limits "$1" "$2" + err=$? + if [ "$err" -ne 0 ]; then + return "$err" + fi } function parse_language_info() { - export Info_Script - export Info_Cmp + export Info_Script + export Info_Cmp - local lang_config - local lang_type - local lang_script + local lang_config + local lang_type + local lang_script - lang_config=$(jq ".Languages[] | select(.Lang == \"$3\")" "$1/problem/$2/config.json") - if [ -z "$lang_config" ]; then - log_error "language $3 is not supported" - return 1 - fi + lang_config=$(jq ".Languages[] | select(.Lang == \"$3\")" "$1/problem/$2/config.json") + if [ -z "$lang_config" ]; then + log_error "language $3 is not supported" + return 1 + fi - Info_Cmp=$(echo "$lang_config" | jq -r ".Cmp") + Info_Cmp=$(echo "$lang_config" | jq -r ".Cmp") - lang_type=$(echo "$lang_config" | jq -r ".Type") - lang_script=$(echo "$lang_config" | jq -r ".Script") + lang_type=$(echo "$lang_config" | jq -r ".Type") + lang_script=$(echo "$lang_config" | jq -r ".Script") - if [ "$lang_type" == "custom" ]; then - Info_Script="/woj/problem/judge/$lang_script" - elif [ "$lang_type" == "default" ]; then - Info_Script="/woj/framework/template/default/$3.Makefile" - else - log_warn "Config file might be corrupted!" - log_error "Unknown language type: $lang_type" - return 1 - fi + if [ "$lang_type" == "custom" ]; then + Info_Script="/woj/problem/judge/$lang_script" + elif [ "$lang_type" == "default" ]; then + Info_Script="/woj/framework/template/default/$3.Makefile" + else + log_warn "Config file might be corrupted!" + log_error "Unknown language type: $lang_type" + return 1 + fi } function parse_limits() { - export Info_Limit_Time - export Info_Limit_Memory - export Info_Limit_NProc - export Info_Num + export Info_Limit_Time + export Info_Limit_Memory + export Info_Limit_NProc + export Info_Num - local cfg - cfg="$1/problem/$2/config.json" + local cfg + cfg="$1/problem/$2/config.json" - Info_Limit_Time=$(jq ".Runtime.TimeLimit" "$cfg") - Info_Limit_Memory=$(jq ".Runtime.MemoryLimit" "$cfg") - Info_Limit_NProc=$(jq ".Runtime.NProcLimit" "$cfg") - Info_Num=$(jq ".Tasks | length" "$1/problem/$2/config.json") + Info_Limit_Time=$(jq ".Runtime.TimeLimit" "$cfg") + Info_Limit_Memory=$(jq ".Runtime.MemoryLimit" "$cfg") + Info_Limit_NProc=$(jq ".Runtime.NProcLimit" "$cfg") + Info_Num=$(jq ".Tasks | length" "$1/problem/$2/config.json") } diff --git a/resource/runner/scripts/problem_compile.sh b/resource/runner/scripts/problem_compile.sh index 8f35ac6..a25ccfc 100755 --- a/resource/runner/scripts/problem_compile.sh +++ b/resource/runner/scripts/problem_compile.sh @@ -6,8 +6,8 @@ WORKSPACE=$(cd "$(dirname "$0")"/.. && pwd) . "$WORKSPACE"/scripts/problem.sh if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ] || [ "$2" == "" ] || [ ! -d "$WORKSPACE/user/$2" ] || [ -z "$3" ]; then - log_warn "Usage: $0 " - exit 1 + log_warn "Usage: $0 " + exit 1 fi get_problem_info "$WORKSPACE" "$1" "$3" @@ -20,11 +20,11 @@ rm -f "$EXE_FILE" && touch "$EXE_FILE" export TIMEOUT=${4:-60} docker_run \ - -v "$WORKSPACE"/problem/"$1"/judge:/woj/problem/judge:ro \ - -v "$SRC_FILE":/woj/problem/user/"$2"."$3":ro \ - -v "$EXE_FILE":/woj/problem/user/"$2".out \ - -e USER_PROG="$2" \ - -e LANG="$3" \ - woj/ubuntu-full \ - sh -c \ - "cd /woj/problem/user && make -f $Info_Script compile" + -v "$WORKSPACE"/problem/"$1"/judge:/woj/problem/judge:ro \ + -v "$SRC_FILE":/woj/problem/user/"$2"."$3":ro \ + -v "$EXE_FILE":/woj/problem/user/"$2".out \ + -e USER_PROG="$2" \ + -e LANG="$3" \ + git.0x7f.app/woj/ubuntu-full \ + sh -c \ + "cd /woj/problem/user && make -f $Info_Script compile" diff --git a/resource/runner/scripts/problem_judge.sh b/resource/runner/scripts/problem_judge.sh index 0142ee2..b262d6f 100755 --- a/resource/runner/scripts/problem_judge.sh +++ b/resource/runner/scripts/problem_judge.sh @@ -6,35 +6,35 @@ WORKSPACE=$(cd "$(dirname "$0")"/.. && pwd) . "$WORKSPACE"/scripts/problem.sh if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ] || [ "$2" == "" ] || [ ! -d "$WORKSPACE/user/$2" ] || [ -z "$3" ]; then - log_warn "Usage: $0 " - exit 1 + log_warn "Usage: $0 " + exit 1 fi get_problem_info "$WORKSPACE" "$1" "$3" export TIMEOUT=${4:-60} for test_num in $(seq "$Info_Num"); do - std_file="$WORKSPACE/problem/$1/data/output/$test_num.output" - ans_file="$WORKSPACE/user/$2/$test_num.out.usr" - jdg_file="$WORKSPACE/user/$2/$test_num.judge" + std_file="$WORKSPACE/problem/$1/data/output/$test_num.output" + ans_file="$WORKSPACE/user/$2/$test_num.out.usr" + jdg_file="$WORKSPACE/user/$2/$test_num.judge" - if [ ! -f "$std_file" ] || [ ! -f "$ans_file" ]; then - log_error "Missing test case $test_num" - exit 1 - fi + if [ ! -f "$std_file" ] || [ ! -f "$ans_file" ]; then + log_error "Missing test case $test_num" + exit 1 + fi - log_info "Judging test case $test_num" + log_info "Judging test case $test_num" - touch "$jdg_file" + touch "$jdg_file" - docker_run \ - -v "$WORKSPACE"/problem/"$1"/judge:/woj/problem/judge:ro \ - -v "$WORKSPACE"/problem/"$1"/data:/woj/problem/data:ro \ - -v "$ans_file":/woj/problem/user/"$test_num".out.usr \ - -v "$jdg_file":/woj/problem/user/"$test_num".judge \ - -e TEST_NUM="$test_num" \ - -e CMP="$Info_Cmp" \ - woj/ubuntu-full \ - sh -c \ - "cd /woj/problem/user && make -f $Info_Script judge" + docker_run \ + -v "$WORKSPACE"/problem/"$1"/judge:/woj/problem/judge:ro \ + -v "$WORKSPACE"/problem/"$1"/data:/woj/problem/data:ro \ + -v "$ans_file":/woj/problem/user/"$test_num".out.usr \ + -v "$jdg_file":/woj/problem/user/"$test_num".judge \ + -e TEST_NUM="$test_num" \ + -e CMP="$Info_Cmp" \ + git.0x7f.app/woj/ubuntu-full \ + sh -c \ + "cd /woj/problem/user && make -f $Info_Script judge" done diff --git a/resource/runner/scripts/problem_prebuild.sh b/resource/runner/scripts/problem_prebuild.sh index 3b97164..e054688 100755 --- a/resource/runner/scripts/problem_prebuild.sh +++ b/resource/runner/scripts/problem_prebuild.sh @@ -5,28 +5,28 @@ WORKSPACE=$(cd "$(dirname "$0")"/.. && pwd) . "$WORKSPACE"/scripts/common.sh if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ]; then - log_warn "Usage: $0 " - exit 1 + log_warn "Usage: $0 " + exit 1 fi if [ -f "$WORKSPACE/problem/$1/.mark.prebuild" ]; then - log_warn "Problem $1 already prebuilt" - log_warn "If you want to re-prebuild the problem, please remove the file $WORKSPACE/problem/$1/.mark.prebuild" - exit 0 + log_warn "Problem $1 already prebuilt" + log_warn "If you want to re-prebuild the problem, please remove the file $WORKSPACE/problem/$1/.mark.prebuild" + exit 0 fi if [ ! -f "$WORKSPACE/problem/$1/judge/prebuild.Makefile" ]; then - log_warn "Problem $1 does not have prebuild scripts" - log_warn "$WORKSPACE/problem/$1/.mark.prebuild" - exit 0 + log_warn "Problem $1 does not have prebuild scripts" + log_warn "$WORKSPACE/problem/$1/.mark.prebuild" + exit 0 fi export TIMEOUT=${2:-300} docker_run \ - -v "$WORKSPACE/problem/$1/data":/woj/problem/data \ - -v "$WORKSPACE/problem/$1/judge":/woj/problem/judge \ - -e PREFIX=/woj/problem \ - woj/ubuntu-full \ - sh -c "cd /woj/problem/judge && make -f prebuild.Makefile prebuild && touch .mark.prebuild" + -v "$WORKSPACE/problem/$1/data":/woj/problem/data \ + -v "$WORKSPACE/problem/$1/judge":/woj/problem/judge \ + -e PREFIX=/woj/problem \ + git.0x7f.app/woj/ubuntu-full \ + sh -c "cd /woj/problem/judge && make -f prebuild.Makefile prebuild && touch .mark.prebuild" mv "$WORKSPACE/problem/$1/judge/.mark.prebuild" "$WORKSPACE/problem/$1/.mark.prebuild" || exit 1 diff --git a/resource/runner/scripts/problem_run.sh b/resource/runner/scripts/problem_run.sh index 3fb4ae3..03da64d 100755 --- a/resource/runner/scripts/problem_run.sh +++ b/resource/runner/scripts/problem_run.sh @@ -6,20 +6,20 @@ WORKSPACE=$(cd "$(dirname "$0")"/.. && pwd) . "$WORKSPACE"/scripts/problem.sh if [ "$1" == "" ] || [ ! -d "$WORKSPACE/problem/$1" ] || [ "$2" == "" ] || [ ! -d "$WORKSPACE/user/$2" ] || [ -z "$3" ]; then - log_warn "Usage: $0 " - exit 1 + log_warn "Usage: $0 " + exit 1 fi if [ ! -f "$WORKSPACE/problem/$1/.mark.prebuild" ]; then - log_warn "Problem $1 has not been prebuilt" - log_warn "Please run 'problem_prebuild.sh $1' first" - exit 1 + log_warn "Problem $1 has not been prebuilt" + log_warn "Please run 'problem_prebuild.sh $1' first" + exit 1 fi if [ ! -f "$WORKSPACE/user/$2/$2.out" ]; then - log_warn "User $2 has not been compiled" - log_warn "Please run 'problem_compile.sh ...' first" - exit 1 + log_warn "User $2 has not been compiled" + log_warn "Please run 'problem_compile.sh ...' first" + exit 1 fi parse_limits "$WORKSPACE" "$1" @@ -35,37 +35,37 @@ TIMEOUT=$(((LIMIT_TIME + 1000) / 1000 + 4)) log_info "Timeout: $TIMEOUT" for test_num in $(seq "$Info_Num"); do - test_case="$WORKSPACE/problem/$1/data/input/$test_num.input" - exe_file="$WORKSPACE/user/$2/$2.out" - ans_file="$WORKSPACE/user/$2/$test_num.out.usr" - ifo_file="$WORKSPACE/user/$2/$test_num.info" + test_case="$WORKSPACE/problem/$1/data/input/$test_num.input" + exe_file="$WORKSPACE/user/$2/$2.out" + ans_file="$WORKSPACE/user/$2/$test_num.out.usr" + ifo_file="$WORKSPACE/user/$2/$test_num.info" - if [ ! -f "$test_case" ]; then - log_error "Test case $test_num does not exist" - exit 1 - fi + if [ ! -f "$test_case" ]; then + log_error "Test case $test_num does not exist" + exit 1 + fi - log_info "Running test case $test_num" - rm -f "$ans_file" && touch "$ans_file" - rm -f "$ifo_file" && touch "$ifo_file" - docker_run \ - --cpus 1 \ - --network none \ - -v "$test_case":/woj/problem/data/input/"$test_num".input:ro \ - -v "$exe_file":/woj/user/"$2".out:ro \ - -v "$ans_file":/woj/user/"$test_num".out.usr \ - -v "$ifo_file":/woj/user/"$test_num".info \ - woj/ubuntu-run \ - sh -c \ - "cd /woj/user && /woj/framework/scripts/woj_launcher \ - --memory_limit=$Info_Limit_Memory \ - --nproc_limit=$Info_Limit_NProc \ - --time_limit=$Info_Limit_Time \ - --sandbox_path=/woj/framework/scripts/libwoj_sandbox.so \ - --sandbox_template=$3 \ - --sandbox_action=nothing \ - --file_input=/woj/problem/data/input/$test_num.input \ - --file_output=/woj/user/$test_num.out.usr \ - --file_info=/woj/user/$test_num.info \ - --program=/woj/user/$2.out" + log_info "Running test case $test_num" + rm -f "$ans_file" && touch "$ans_file" + rm -f "$ifo_file" && touch "$ifo_file" + docker_run \ + --cpus 1 \ + --network none \ + -v "$test_case":/woj/problem/data/input/"$test_num".input:ro \ + -v "$exe_file":/woj/user/"$2".out:ro \ + -v "$ans_file":/woj/user/"$test_num".out.usr \ + -v "$ifo_file":/woj/user/"$test_num".info \ + git.0x7f.app/woj/ubuntu-run \ + sh -c \ + "cd /woj/user && /woj/framework/scripts/woj_launcher \ + --memory_limit=$Info_Limit_Memory \ + --nproc_limit=$Info_Limit_NProc \ + --time_limit=$Info_Limit_Time \ + --sandbox_path=/woj/framework/scripts/libwoj_sandbox.so \ + --sandbox_template=$3 \ + --sandbox_action=nothing \ + --file_input=/woj/problem/data/input/$test_num.input \ + --file_output=/woj/user/$test_num.out.usr \ + --file_info=/woj/user/$test_num.info \ + --program=/woj/user/$2.out" done diff --git a/resource/runner/scripts/run_timeout.sh b/resource/runner/scripts/run_timeout.sh index 1f48957..20b64f2 100755 --- a/resource/runner/scripts/run_timeout.sh +++ b/resource/runner/scripts/run_timeout.sh @@ -3,17 +3,17 @@ . common.sh function docker_run() { - local timeout=${TIMEOUT:-10} - local log_file=${LOG_FILE:-"/dev/stderr"} - local log_limit=${LOG_LIMIT:-4K} - log_info "$DOCKER run with timeout $timeout" - CONTAINER_NAME=$(uuidgen) - ( - sleep "$timeout" - $DOCKER kill "$CONTAINER_NAME" - ) & - $DOCKER run --rm --name "$CONTAINER_NAME" "$@" 2>&1 | head -c "$log_limit" >"$log_file" - pkill -P $$ - $DOCKER kill "$CONTAINER_NAME" >/dev/null 2>&1 - return 0 + local timeout=${TIMEOUT:-10} + local log_file=${LOG_FILE:-"/dev/stderr"} + local log_limit=${LOG_LIMIT:-4K} + log_info "$DOCKER run with timeout $timeout" + CONTAINER_NAME=$(uuidgen) + ( + sleep "$timeout" + $DOCKER kill "$CONTAINER_NAME" + ) & + $DOCKER run --rm --name "$CONTAINER_NAME" "$@" 2>&1 | head -c "$log_limit" >"$log_file" + pkill -P $$ + $DOCKER kill "$CONTAINER_NAME" >/dev/null 2>&1 + return 0 } diff --git a/resource/runner/scripts/ubuntu-full.Dockerfile b/resource/runner/scripts/ubuntu-full.Dockerfile new file mode 100644 index 0000000..a7391da --- /dev/null +++ b/resource/runner/scripts/ubuntu-full.Dockerfile @@ -0,0 +1,20 @@ +FROM docker.io/library/ubuntu:22.04 +WORKDIR /woj/ + +# Install dependencies +RUN apt-get update && apt-get upgrade -y && apt-get install -y gcc g++ clang make cmake autoconf m4 libtool gperf git parallel python3 && apt-get clean && rm -rf /var/lib/apt/lists + +# Copy source code +RUN mkdir -p /woj/framework && mkdir -p /woj/problem +COPY framework /woj/framework + +# Build +RUN cd /woj/framework/template && ./setup.sh +RUN cd /woj/framework/scripts && ./setup.sh + +# Environment +ENV WOJ_LAUNCHER=/woj/framework/scripts/woj_launcher +ENV WOJ_SANDBOX=/woj/framework/scripts/libwoj_sandbox.so +ENV TEMPLATE=/woj/framework/template +ENV TESTLIB=/woj/framework/template/testlib +ENV PREFIX=/woj/problem diff --git a/resource/runner/scripts/ubuntu-run.Dockerfile b/resource/runner/scripts/ubuntu-run.Dockerfile new file mode 100644 index 0000000..44839ba --- /dev/null +++ b/resource/runner/scripts/ubuntu-run.Dockerfile @@ -0,0 +1,8 @@ +FROM woj/ubuntu-full:latest AS builder +FROM docker.io/library/ubuntu:22.04 + +WORKDIR /woj/problem +RUN mkdir -p /woj/framework/scripts + +COPY --from=builder /woj/framework/scripts/libwoj_sandbox.so /woj/framework/scripts/ +COPY --from=builder /woj/framework/scripts/woj_launcher /woj/framework/scripts/