#!/bin/bash set -eo pipefail COLOR_RED="\e[0;31m" COLOR_GREEN="\e[0;32m" COLOR_YELLOW="\e[0;33m" COLOR_NONE="\e[0m" function log_info() { echo -e "${COLOR_GREEN}$*${COLOR_NONE}" 1>&2; } function log_warn() { echo -e "${COLOR_YELLOW}$*${COLOR_NONE}" 1>&2; } function log_error() { echo -e "${COLOR_RED}$*${COLOR_NONE}" 1>&2; } function check_env() { # $1 -> var name # $2 -> default value # $3 -> quota or not val=$(eval "echo -n \${$1}") if test -z "$val"; then log_warn "Environment variable $1 is not set, using default value \"$2\"" export "$1"="$2" else log_info "Using $1=$val" fi if "$3"; then val=$(eval "echo -n \${$1}") # shellcheck disable=SC2140 export "$1"="'$val'" fi # echo -n ">>>>> " # eval "echo -n \${$1}" # echo " <<<<<" } function extract_web_server() { check_env "WEB_SERVER_ADDRESS" "0.0.0.0" true check_env "WEB_SERVER_PORT" 8000 false check_env "WEB_SERVER_PUBLIC_BASE" "http://127.0.0.1:8000" true check_env "WEB_SERVER_TRUSTED_PLATFORM" "" true check_env "WEB_SERVER_JWT_SIGNING_KEY" "$(head -n 10 /dev/urandom | md5sum | cut -c 1-32)" true check_env "WEB_SERVER_JWT_EXPIRE_HOUR" 12 false check_env "WEB_SERVER_OAUTH_DOMAIN" "" true check_env "WEB_SERVER_OAUTH_CLIENT_ID" "" true check_env "WEB_SERVER_OAUTH_CLIENT_SECRET" "" true } function extract_redis() { check_env "REDIS_DB" 0 false check_env "REDIS_QUEUE_DB" 1 false check_env "REDIS_ADDRESS" "redis" true check_env "REDIS_PORT" 6379 false check_env "REDIS_PASSWORD" "" true } function extract_database() { check_env "DATABASE_HOST" "postgres" true check_env "DATABASE_PORT" 5432 false check_env "DATABASE_USER" "dev" true check_env "DATABASE_PASSWORD" "password" true check_env "DATABASE_NAME" "dev" true check_env "DATABASE_PREFIX" "oj_" true check_env "DATABASE_MAX_OPEN_CONNS" 100 false check_env "DATABASE_MAX_IDLE_CONNS" 60 false check_env "DATABASE_CONN_MAX_LIFETIME" 60 false check_env "DATABASE_TIMEZONE" "Asia/Shanghai" true } function extract_storage() { check_env "STORAGE_ENDPOINT" "minio:9000" true check_env "STORAGE_USE_SSL" "false" false check_env "STORAGE_ACCESS_KEY" "access_key" true check_env "STORAGE_SECRET_KEY" "secret_key" true check_env "STORAGE_BUCKET" "woj" true } function extract_runner() { check_env "CGROUP_PATH" "/sys/fs/cgroup/nsjail" true check_env "RUNNER_CONCURRENCY" 0 false } function extract_metrics() { check_env "METRICS_NAMESPACE" "woj" true check_env "METRICS_SUBSYSTEM" "server" true } function extract_misc() { check_env "DEVELOPMENT" false false } function generate_config() { if [ -f '/app/config.yaml' ]; then log_info "config.yaml already exists, skip" return fi # extract env vars extract_web_server extract_redis extract_database extract_storage extract_runner extract_metrics extract_misc # dump script rm -f /tmp/tmp.yaml ( echo "cat </app/config.yaml" cat /app/config.docker.yaml echo "EOF" ) >/tmp/tmp.yaml # dump env vars log_info "creating config.yaml" . /tmp/tmp.yaml || { log_error "failed to create config.yaml"; exit 1; } # cleanup rm -f /tmp/tmp.yaml } setup_cgroups() { # taken from https://github.com/moby/moby/blob/ee6cbc540e9c62feb143c2a8d3f0c86d2a468767/hack/dind#L59-L69 # cgroup v2: enable nesting if [ -f /sys/fs/cgroup/cgroup.controllers ]; then # move the processes from the root group to the /init group, # otherwise writing subtree_control fails with EBUSY. # An error during moving non-existent process (i.e., "cat") is ignored. mkdir -p /sys/fs/cgroup/init xargs -rn1 < /sys/fs/cgroup/cgroup.procs > /sys/fs/cgroup/init/cgroup.procs || : # enable controllers sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/cgroup.controllers \ > /sys/fs/cgroup/cgroup.subtree_control fi # create nsjail group mkdir -p /sys/fs/cgroup/nsjail sed -e 's/ / +/g' -e 's/^/+/' < /sys/fs/cgroup/nsjail/cgroup.controllers > /sys/fs/cgroup/nsjail/cgroup.subtree_control } setup_user_runner() { # runner use debian as base image groupadd --gid 1000 woj || true useradd --gid 1000 --uid 1000 woj || true # runner data chown -R woj:woj /app/resource/runner/problem chown -R woj:woj /app/resource/runner/tmp chown -R woj:woj /app/resource/runner/user # rootfs mount path chown -R woj:woj /app/resource/runner/framework/rootfs/full/woj chown -R woj:woj /app/resource/runner/framework/rootfs/run/woj # cgroups chown -R woj:woj /sys/fs/cgroup/nsjail chown -R woj:root /sys/fs/cgroup/cgroup.procs # create run dir: nsjail will try to use it mkdir -p /run/user/1000 chown -R woj:woj /run/user/1000 chmod 700 /run/user/1000 } setup_user_server() { # server use alpine as base image addgroup -g 1000 -S woj || true adduser -u 1000 -S -G woj woj || true } setup_user() { if [ -n "$RUNNER_IMAGE" ]; then setup_user_runner else setup_user_server fi } if [ -n "$RUNNER_IMAGE" ]; then setup_cgroups; fi generate_config setup_user log_info "starting woj" if [ -n "$RUNNER_IMAGE" ]; then EXEC=gosu; else EXEC=su-exec; fi exec $EXEC woj /app/woj "$@"