diff options
-rw-r--r-- | Dockerfile | 22 | ||||
-rwxr-xr-x | compile-and-run.sh | 24 | ||||
-rw-r--r-- | compose.yml | 7 | ||||
-rw-r--r-- | entrypoint.sh | 6 | ||||
-rw-r--r-- | generate-status-object.php | 30 | ||||
-rw-r--r-- | httpd-foreground | 7 | ||||
-rw-r--r-- | httpd.conf | 97 | ||||
-rw-r--r-- | public/index.php | 61 |
8 files changed, 204 insertions, 50 deletions
diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..387023f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM docker:27-dind AS apache +USER root +RUN apk update && \ + apk add --no-cache \ + bash \ + coreutils \ + su-exec \ + apache2 \ + php83-apache2 \ + php83-session +RUN adduser -D apache2 && \ + addgroup apache2 docker +RUN mkdir -p /root/.docker && \ + chmod -R 0777 /root/.docker +RUN chmod 4755 /sbin/su-exec +COPY --chmod=777 httpd-foreground /usr/local/bin/ +COPY --chmod=777 entrypoint.sh /usr/local/bin/ +COPY --chmod=777 . /opt/application +COPY httpd.conf /etc/apache2/httpd.conf +ENV IS_IN_DOCKER=1 +EXPOSE 80 +CMD ["/usr/local/bin/entrypoint.sh"] diff --git a/compile-and-run.sh b/compile-and-run.sh index 64bacb1..423206e 100755 --- a/compile-and-run.sh +++ b/compile-and-run.sh @@ -2,6 +2,8 @@ source ./functions.sh +unset DOCKER_HOST + if [ "$1" == "" ]; then echo "Parameter 1 is empty" exit 1 @@ -28,7 +30,8 @@ exec_path="$(realpath "$exec_path")" results_path="$(realpath "$results_path")" pushd containers/compiler > /dev/null -compiler_image=$(docker build -q .) || exit 1 +compiler_image="ic$runner_id" +docker build -q -t $compiler_image . || exit 1 catch compiler_stdout compiler_stderr docker run \ --rm \ --network none \ @@ -47,12 +50,13 @@ printf '%s' "$compiler_stdout" > $results_path/c.0 printf '%s' "$compiler_stderr" > $results_path/c.1 if [ $compiler_status -eq 0 ]; then - runner_image=$(\ - docker build \ - --build-arg "EXEC_DIR_HOST=$exec_path_relative" \ - -q \ - -f "containers/runner/Dockerfile" . - ) || exit 1 + runner_image="ir$runner_id" + docker build \ + --build-arg "EXEC_DIR_HOST=$exec_path_relative" \ + -q \ + -t "$runner_image" \ + -f "containers/runner/Dockerfile" . \ + || exit 1 catch runner_stdout runner_stderr timeout 60 docker run \ --rm \ -h "java-runner-$runner_id" \ @@ -60,7 +64,7 @@ if [ $compiler_status -eq 0 ]; then --cpus=0.25 \ --network none \ -e "APPLICATION_NAME=$application_name" \ - $runner_image + "$runner_image" runner_status=$? docker image rm -f $runner_image > /dev/null || exit 1 @@ -68,7 +72,3 @@ if [ $compiler_status -eq 0 ]; then printf '%s' "$runner_stdout" > $results_path/r.0 printf '%s' "$runner_stderr" > $results_path/r.1 fi - -php generate-status-object.php $runner_id - -rm -rf "$runner_dir" diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..056bd4f --- /dev/null +++ b/compose.yml @@ -0,0 +1,7 @@ +services: + main: + build: . + privileged: true + ports: + - 13821:80 + environment: {} diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..7914676 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +cd /usr/local/bin/ +./dockerd-entrypoint.sh & +./httpd-foreground & +wait diff --git a/generate-status-object.php b/generate-status-object.php deleted file mode 100644 index 9d19070..0000000 --- a/generate-status-object.php +++ /dev/null @@ -1,30 +0,0 @@ -<?php - -if (empty($argv[1])) { - file_put_contents("php://stderr", "No runner ID specified"); - exit(1); -} - -define("WORK_DIR", __DIR__ . "/_runners/" . $argv[1] . "/results"); - -function get(string $name): ?string { - $file = WORK_DIR . "/" . $name; - if (!is_file($file)) - return null; - return file_get_contents($file); -} - -$data = [ - "compile" => [ - "status" => get("c.s"), - "stdout" => get("c.0"), - "stderr" => get("c.1"), - ], - "run" => [ - "status" => get("r.s"), - "stdout" => get("r.0"), - "stderr" => get("r.1"), - ], -]; - -echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT) . PHP_EOL; diff --git a/httpd-foreground b/httpd-foreground new file mode 100644 index 0000000..e896168 --- /dev/null +++ b/httpd-foreground @@ -0,0 +1,7 @@ +#!/bin/sh +set -e + +# Apache gets grumpy about PID files pre-existing +rm -f /usr/local/apache2/logs/httpd.pid + +exec httpd -DFOREGROUND "$@" diff --git a/httpd.conf b/httpd.conf new file mode 100644 index 0000000..0ddc08d --- /dev/null +++ b/httpd.conf @@ -0,0 +1,97 @@ +ServerTokens OS + +ServerRoot /var/www + +Listen 80 + +LoadModule mpm_prefork_module modules/mod_mpm_prefork.so +LoadModule authn_file_module modules/mod_authn_file.so +LoadModule authn_core_module modules/mod_authn_core.so +LoadModule authz_host_module modules/mod_authz_host.so +LoadModule authz_groupfile_module modules/mod_authz_groupfile.so +LoadModule authz_user_module modules/mod_authz_user.so +LoadModule authz_core_module modules/mod_authz_core.so +LoadModule access_compat_module modules/mod_access_compat.so +LoadModule auth_basic_module modules/mod_auth_basic.so +LoadModule reqtimeout_module modules/mod_reqtimeout.so +LoadModule filter_module modules/mod_filter.so +LoadModule mime_module modules/mod_mime.so +LoadModule log_config_module modules/mod_log_config.so +LoadModule env_module modules/mod_env.so +LoadModule headers_module modules/mod_headers.so +LoadModule setenvif_module modules/mod_setenvif.so +LoadModule version_module modules/mod_version.so +LoadModule unixd_module modules/mod_unixd.so +LoadModule status_module modules/mod_status.so +LoadModule autoindex_module modules/mod_autoindex.so +LoadModule dir_module modules/mod_dir.so +LoadModule alias_module modules/mod_alias.so + +LoadModule negotiation_module modules/mod_negotiation.so + +<IfModule unixd_module> +User apache2 +Group apache2 + +</IfModule> + +ServerAdmin you@example.com + +ServerSignature On + +ServerName localhost:80 + +<Directory /> + AllowOverride none + Require all denied +</Directory> + +DocumentRoot "/opt/application/public" +<Directory "/opt/application/public"> + Options FollowSymLinks + + AllowOverride All + + Require all granted +</Directory> + +<IfModule dir_module> + DirectoryIndex index.php index.html +</IfModule> + +# <Files ".ht*"> +# Require all denied +# </Files> + +#ErrorLog logs/error.log +ErrorLog /proc/self/fd/2 + +LogLevel warn + +<IfModule log_config_module> + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined + LogFormat "%h %l %u %t \"%r\" %>s %b" common + + <IfModule logio_module> + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio + </IfModule> + + #CustomLog logs/access.log combined + CustomLog /proc/self/fd/1 combined +</IfModule> + +<IfModule headers_module> + RequestHeader unset Proxy early +</IfModule> + +<IfModule mime_module> + TypesConfig /etc/apache2/mime.types + AddType application/x-compress .Z + AddType application/x-gzip .gz .tgz +</IfModule> + +<IfModule mime_magic_module> + MIMEMagicFile /etc/apache2/magic +</IfModule> + +IncludeOptional /etc/apache2/conf.d/*.conf diff --git a/public/index.php b/public/index.php index 0b3cabc..5a77566 100644 --- a/public/index.php +++ b/public/index.php @@ -3,6 +3,13 @@ session_name("a3e0f0ee-9f5a-4be2-88cb-3b7ceb626d00"); session_start(); +function get(string $id, string $name): ?string { + $file = __DIR__ . "/../_runners/$id/results/" . $name; + if (!is_file($file)) + return null; + return file_get_contents($file); +} + function csrf_token(): string { return $_SESSION["csrf-token"] = base64_encode(random_bytes(30)); } @@ -53,24 +60,62 @@ if (isset($_POST["code"]) && strlen($_POST["code"]) <= 16383) { exit; } - $srcDir = __DIR__ . "/../_runners/$id/src"; + $runnerDir = __DIR__ . "/../_runners/$id"; + $srcDir = $runnerDir . "/src"; mkdir($srcDir, recursive: true); file_put_contents($srcDir . "/Program.java", $code); + $isInDocker = getenv("IS_IN_DOCKER") === "1"; + + if ($isInDocker) + file_put_contents("php://stderr", "[debug] In Docker\n"); chdir(__DIR__ . "/.."); - $resultStr = shell_exec("./compile-and-run.sh '$id' Program 2>/dev/null"); + + $stderrFile = sys_get_temp_dir() . "/tmp{$id}.2"; + exec( + ($isInDocker ? "su-exec root " : "") . + "./compile-and-run.sh '$id' Program 2>'$stderrFile'", $resultStr, $code); + $resultStr = implode("\n", $resultStr); + if (is_file($stderrFile)) { + $stderrContents = file_get_contents($stderrFile); + unlink($stderrFile); + if (!empty($stderrContents)) { + file_put_contents("php://stderr", "compile-and-run.sh failed: $stderrContents\n"); + if ($code != 0) { + echo json_encode([ + "ok" => false, + "message" => "Execution failed:\n$stderrContents", + "csrf" => csrf_token(), + ]); + exit; + } + } + } chdir(__DIR__); + file_put_contents("php://stderr", "result: $result\n"); $csrf = csrf_token(); - if (is_string($resultStr)) { - $result = json_decode($resultStr, true); - $result["runner"] = $id; - $result["ok"] = true; - $result["csrf"] = $csrf; - } + + $result = [ + "compile" => [ + "status" => get($id, "c.s"), + "stdout" => get($id, "c.0"), + "stderr" => get($id, "c.1"), + ], + "run" => [ + "status" => get($id, "r.s"), + "stdout" => get($id, "r.0"), + "stderr" => get($id, "r.1"), + ], + "runner" => $id, + "ok" => true, + "csrf" => $csrf, + ]; + + delTree($runnerDir); echo json_encode($result); exit; |