diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..c1c9f4dc --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.git* diff --git a/.gitignore b/.gitignore index 011edeca..3c7f32b3 100644 --- a/.gitignore +++ b/.gitignore @@ -68,4 +68,3 @@ custom_settings.py docker-compose.yml *.zip rsyncd.passwd -oj.conf \ No newline at end of file diff --git a/README.md b/README.md index 763300ea..5f413d9b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# OnlineJudge [![Build Status](https://travis-ci.org/QingdaoU/OnlineJudge.svg?branch=master)](https://travis-ci.org/QingdaoU/OnlineJudge) +# OnlineJudge 由于作者工作学习繁忙, 目前只能保证有时间的时候修复部分BUG。 @@ -18,7 +18,7 @@ - 提供 Virtual Judge 和单点登录使用 API,不再繁琐的进行模拟登陆 - 后台管理判题服务器,轻松分离 web 和判题服务器 -安装文档: https://github.com/QingdaoU/OnlineJudge/wiki +安装文档: https://github.com/QingdaoU/OnlineJudgeDeploy OpenAPI文档: https://github.com/QingdaoU/OnlineJudgeOpenAPI @@ -44,4 +44,4 @@ TODO: ![](http://7xk96g.com1.z0.glb.clouddn.com/oj-preview/FireShot%20Capture%2033%20-%20%E5%9C%A8%E7%BA%BF%E8%AF%84%E6%B5%8B%E7%B3%BB%E7%BB%9F%20-%20%E5%90%8E%E5%8F%B0%E7%AE%A1%E7%90%86%20-%20https___qduoj.com_admin_%23problem_problem_list.png) -![](http://7xk96g.com1.z0.glb.clouddn.com/oj-preview/FireShot%20Capture%2034%20-%20%E5%9C%A8%E7%BA%BF%E8%AF%84%E6%B5%8B%E7%B3%BB%E7%BB%9F%20-%20%E5%90%8E%E5%8F%B0%E7%AE%A1%E7%90%86%20-%20https___qduoj.com_admin_%23contest_contest_list.png) \ No newline at end of file +![](http://7xk96g.com1.z0.glb.clouddn.com/oj-preview/FireShot%20Capture%2034%20-%20%E5%9C%A8%E7%BA%BF%E8%AF%84%E6%B5%8B%E7%B3%BB%E7%BB%9F%20-%20%E5%90%8E%E5%8F%B0%E7%AE%A1%E7%90%86%20-%20https___qduoj.com_admin_%23contest_contest_list.png) diff --git a/build.sh b/build.sh new file mode 100755 index 00000000..d9903816 --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +docker build -t registry.cn-hangzhou.aliyuncs.com/qduoj/oj_web_server -f dockerfiles/oj_web_server/Dockerfile . diff --git a/dockerfiles/judger/Dockerfile b/dockerfiles/judger/Dockerfile index 3c01c3a5..055a7b5e 100644 --- a/dockerfiles/judger/Dockerfile +++ b/dockerfiles/judger/Dockerfile @@ -1,20 +1,15 @@ -FROM ubuntu:14.04 +FROM ubuntu:16.04 ENV DEBIAN_FRONTEND noninteractive -RUN rm /etc/apt/sources.list -COPY sources.list /etc/apt/ -RUN apt-get update -RUN apt-get -y install software-properties-common python-software-properties python python-dev gcc g++ git libtool python-pip libseccomp-dev -RUN add-apt-repository -y ppa:webupd8team/java -RUN echo debconf shared/accepted-oracle-license-v1-1 select true | sudo debconf-set-selections -RUN echo debconf shared/accepted-oracle-license-v1-1 seen true | sudo debconf-set-selections -RUN apt-get update -RUN apt-get install -y oracle-java7-installer -RUN cd /tmp && git clone https://github.com/QingdaoU/Judger && cd Judger && python setup.py install +RUN apt-get update && apt-get -y install software-properties-common python-software-properties python python-dev gcc g++ git libtool python-pip libseccomp-dev +RUN add-apt-repository -y ppa:webupd8team/java && echo debconf shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && echo debconf shared/accepted-oracle-license-v1-1 seen true | debconf-set-selections +RUN apt-get update && apt-get install -y oracle-java8-installer +RUN cd /tmp && git clone -b master https://github.com/QingdaoU/Judger && cd Judger && python setup.py install RUN mkdir -p /var/judger/run/ && mkdir /var/judger/test_case/ && mkdir /var/judger/code/ RUN chmod -R 777 /var/judger/run/ -COPY policy /var/judger/run/ -COPY supervisord.conf /etc +COPY dockerfiles/judger/policy /var/judger/run/ +COPY dockerfiles/judger/supervisord.conf /etc RUN pip install supervisor +ADD . /var/judger/code WORKDIR /var/judger/code/judge/ EXPOSE 8080 -CMD bash /var/judger/code/dockerfiles/judger/run.sh \ No newline at end of file +CMD bash /var/judger/code/dockerfiles/judger/run.sh diff --git a/dockerfiles/oj_web_server/Dockerfile b/dockerfiles/oj_web_server/Dockerfile index def778d6..56d191db 100644 --- a/dockerfiles/oj_web_server/Dockerfile +++ b/dockerfiles/oj_web_server/Dockerfile @@ -1,15 +1,10 @@ -FROM python:2.7 +FROM ubuntu:16.04 ENV PYTHONBUFFERED 1 -RUN mkdir -p /code/log /code/test_case /code/upload -WORKDIR /code -ADD requirements.txt /code/ -RUN pip install -i http://pypi.douban.com/simple -r requirements.txt --trusted-host pypi.douban.com -RUN rm /etc/apt/sources.list -ADD sources.list /etc/apt/ +RUN apt-get update && apt-get install -y nginx python-pip libmysqlclient-dev curl nodejs RUN curl -sL https://deb.nodesource.com/setup | bash - -RUN apt-get -y install nodejs -ADD gunicorn.conf /etc -ADD supervisord.conf /etc -ADD task_queue.conf /etc -EXPOSE 8080 -CMD bash /code/dockerfiles/oj_web_server/run.sh \ No newline at end of file +RUN apt-get install nodejs +ADD . /code +WORKDIR /code +RUN pip install -i https://pypi.douban.com/simple -r dockerfiles/oj_web_server/requirements.txt +RUN python tools/release_static.py +CMD bash /code/dockerfiles/oj_web_server/run.sh diff --git a/dockerfiles/oj_web_server/gunicorn.conf b/dockerfiles/oj_web_server/gunicorn.conf deleted file mode 100644 index 18dbab32..00000000 --- a/dockerfiles/oj_web_server/gunicorn.conf +++ /dev/null @@ -1,12 +0,0 @@ -[program:gunicorn] -command=gunicorn oj.wsgi:application -b 0.0.0.0:8080 --reload -directory=/code/ -user=nobody -numprocs=1 -stdout_logfile=/code/log/gunicorn.log -stderr_logfile=/code/log/gunicorn.log -autostart=true -autorestart=true -startsecs=5 -stopwaitsecs = 5 -killasgroup=true \ No newline at end of file diff --git a/dockerfiles/oj_web_server/oj.conf b/dockerfiles/oj_web_server/oj.conf new file mode 100644 index 00000000..c22e9382 --- /dev/null +++ b/dockerfiles/oj_web_server/oj.conf @@ -0,0 +1,85 @@ +worker_processes 1; +user www-data; +error_log /dev/stderr warn; +daemon off; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + # access_log /dev/stdout main; + access_log off; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + gzip on; + gzip_types application/javascript text/css; + + upstream backend { + server 127.0.0.1:8080; + keepalive 32; + } + + server { + listen 80 default_server; + server_name _; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $http_host; + client_max_body_size 200M; + + location /static/upload { + expires max; + alias /code/upload; + } + location /static { + etag off; + expires max; + alias /code/static/release; + } + location / { + proxy_pass http://backend; + proxy_set_header Host $host; + } + } + + server { + listen 443 ssl http2 default_server; + server_name _; + ssl_certificate /code/ssl/server.crt; + ssl_certificate_key /code/ssl/server.key; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $http_host; + client_max_body_size 200M; + + location /static/upload { + expires max; + alias /code/upload; + } + location /static { + etag off; + expires max; + alias /code/static/release; + } + location / { + proxy_pass http://backend; + proxy_set_header Host $host; + } + } +} + diff --git a/dockerfiles/oj_web_server/oj.example.conf b/dockerfiles/oj_web_server/oj.example.conf deleted file mode 100644 index 30fa3603..00000000 --- a/dockerfiles/oj_web_server/oj.example.conf +++ /dev/null @@ -1,18 +0,0 @@ -server { - listen 80 default_server; - server_name _; - location /static/upload { - expires max; - alias /home/upload; - } - location /static { - etag off; - expires max; - alias /home/OnlineJudge/static/release; - } - location / { - client_max_body_size 100m; - proxy_pass http://oj_web_server:8080; - proxy_set_header Host $host; - } -} diff --git a/dockerfiles/oj_web_server/requirements.txt b/dockerfiles/oj_web_server/requirements.txt index 0abcfcf3..3b505741 100644 --- a/dockerfiles/oj_web_server/requirements.txt +++ b/dockerfiles/oj_web_server/requirements.txt @@ -2,7 +2,7 @@ django==1.9.6 MySQL-python redis django-redis-sessions -djangorestframework +djangorestframework==3.2.5 django-rest-swagger gunicorn coverage diff --git a/dockerfiles/oj_web_server/run.sh b/dockerfiles/oj_web_server/run.sh index 04b6d695..2c65fdc5 100644 --- a/dockerfiles/oj_web_server/run.sh +++ b/dockerfiles/oj_web_server/run.sh @@ -1,10 +1,26 @@ #!/usr/bin/env bash -if [ ! -f "/code/oj/custom_settings.py" ]; then - cp /code/oj/custom_settings.example.py /code/oj/custom_settings.py - echo "SECRET_KEY=\"`cat /dev/urandom | head -1 | md5sum | head -c 32`\"" >> /code/oj/custom_settings.py +if [ ! -f "/code/oj/secret_key.py" ]; then + echo "SECRET_KEY=\"`cat /dev/urandom | head -1 | md5sum | head -c 32`\"" >> /code/oj/secret_key.py fi + +ca_base_dir="/code/ssl" +if [ ! -f "$ca_base_dir/server.key" ]; then + openssl req -x509 -newkey rsa:2048 -keyout "$ca_base_dir/server.key" -out "$ca_base_dir/server.crt" -days 1000 \ + -subj "/C=CN/ST=Beijing/L=Beijing/O=Beijing OnlineJudge Technology Co., Ltd./OU=Service Infrastructure Department/CN=`hostname`" -nodes +fi + find /code -name "*.pyc" -delete -python -m compileall /code -chown -R nobody:nogroup /code/log /code/test_case /code/upload -echo "Waiting MySQL and Redis to start" -exec supervisord \ No newline at end of file +# python -m compileall /code +chown -R nobody:nogroup /code/log /code/test_case /code/upload /code/ssl +cd /code +n=0 +until [ $n -ge 5 ] +do + python tools/create_db.py && + python manage.py migrate --no-input && + python manage.py migrate --database=submission --no-input && + python manage.py initadmin && break + n=$(($n+1)) + sleep 8 +done +exec supervisord -c /code/dockerfiles/oj_web_server/supervisord.conf diff --git a/dockerfiles/oj_web_server/sources.list b/dockerfiles/oj_web_server/sources.list deleted file mode 100644 index 67caf139..00000000 --- a/dockerfiles/oj_web_server/sources.list +++ /dev/null @@ -1,8 +0,0 @@ -deb http://mirrors.aliyun.com/debian wheezy main contrib non-free -deb-src http://mirrors.aliyun.com/debian wheezy main contrib non-free - -deb http://mirrors.aliyun.com/debian wheezy-updates main contrib non-free -deb-src http://mirrors.aliyun.com/debian wheezy-updates main contrib non-free - -deb http://mirrors.aliyun.com/debian-security wheezy/updates main contrib non-free -deb-src http://mirrors.aliyun.com/debian-security wheezy/updates main contrib non-free \ No newline at end of file diff --git a/dockerfiles/oj_web_server/supervisord.conf b/dockerfiles/oj_web_server/supervisord.conf index 4026c19e..fa0ee039 100644 --- a/dockerfiles/oj_web_server/supervisord.conf +++ b/dockerfiles/oj_web_server/supervisord.conf @@ -5,11 +5,44 @@ logfile_backups=10 loglevel=info pidfile=/code/log/supervisord.pid nodaemon=true -user=nobody childlogdir=/code/log/ [supervisorctl] serverurl=unix:///tmp/supervisor.sock -[include] -files=gunicorn.conf task_queue.conf \ No newline at end of file +[program:gunicorn] +command=gunicorn oj.wsgi:application --user nobody -b 127.0.0.1:8080 --reload +directory=/code/ +numprocs=1 +stdout_logfile=/code/log/gunicorn.log +stderr_logfile=/code/log/gunicorn.log +autostart=true +autorestart=true +startsecs=5 +stopwaitsecs = 5 +killasgroup=true + +[program:task_queue] +command=celery -A oj worker -l warning +directory=/code/ +user=nobody +numprocs=1 +stdout_logfile=/code/log/task_queue.log +stderr_logfile=/code/log/task_queue.log +autostart=true +autorestart=true +startsecs=5 +stopwaitsecs = 5 +killasgroup=true + +[program:nginx] +command=nginx -c /code/dockerfiles/oj_web_server/oj.conf +directory=/code/ +numprocs=1 +stdout_logfile=/code/log/nginx.log +stderr_logfile=/code/log/nginx.log +autostart=true +autorestart=true +startsecs=5 +stopwaitsecs = 5 +killasgroup=true diff --git a/dockerfiles/oj_web_server/task_queue.conf b/dockerfiles/oj_web_server/task_queue.conf deleted file mode 100644 index dd51bebc..00000000 --- a/dockerfiles/oj_web_server/task_queue.conf +++ /dev/null @@ -1,12 +0,0 @@ -[program:task_queue] -command=celery -A oj worker --autoscale=30,4 -l DEBUG -directory=/code/ -user=nobody -numprocs=1 -stdout_logfile=/code/log/task_queue.log -stderr_logfile=/code/log/task_queue.log -autostart=true -autorestart=true -startsecs=5 -stopwaitsecs = 5 -killasgroup=true \ No newline at end of file diff --git a/judge_dispatcher/serializers.py b/judge_dispatcher/serializers.py index 4328eee9..5efa79cd 100644 --- a/judge_dispatcher/serializers.py +++ b/judge_dispatcher/serializers.py @@ -6,7 +6,7 @@ from .models import JudgeServer class CreateJudgesSerializer(serializers.Serializer): name = serializers.CharField(max_length=30) - ip = serializers.IPAddressField() + ip = serializers.CharField(max_length=128) port = serializers.IntegerField() # 这个服务器最大可能运行的判题实例数量 max_instance_number = serializers.IntegerField() @@ -16,7 +16,7 @@ class CreateJudgesSerializer(serializers.Serializer): class EditJudgesSerializer(serializers.Serializer): id = serializers.IntegerField() name = serializers.CharField(max_length=30) - ip = serializers.IPAddressField() + ip = serializers.CharField(max_length=128) port = serializers.IntegerField() # 这个服务器最大可能运行的判题实例数量 max_instance_number = serializers.IntegerField() diff --git a/oj/secret_key.example.py b/oj/secret_key.example.py new file mode 100644 index 00000000..cfe94f90 --- /dev/null +++ b/oj/secret_key.example.py @@ -0,0 +1 @@ +SECRET_KEY="123456" diff --git a/oj/server_settings.py b/oj/server_settings.py index 9ec8dcfb..e54635b4 100644 --- a/oj/server_settings.py +++ b/oj/server_settings.py @@ -7,8 +7,8 @@ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': "oj", - 'CONN_MAX_AGE': 0.1, - 'HOST': os.environ["MYSQL_PORT_3306_TCP_ADDR"], + 'CONN_MAX_AGE': 10, + 'HOST': "oj_mysql", 'PORT': 3306, 'USER': os.environ["MYSQL_ENV_MYSQL_USER"], 'PASSWORD': os.environ["MYSQL_ENV_MYSQL_ROOT_PASSWORD"] @@ -16,8 +16,8 @@ DATABASES = { 'submission': { 'NAME': 'oj_submission', 'ENGINE': 'django.db.backends.mysql', - 'CONN_MAX_AGE': 0.1, - 'HOST': os.environ["MYSQL_PORT_3306_TCP_ADDR"], + 'CONN_MAX_AGE': 10, + 'HOST': "oj_mysql", 'PORT': 3306, 'USER': os.environ["MYSQL_ENV_MYSQL_USER"], 'PASSWORD': os.environ["MYSQL_ENV_MYSQL_ROOT_PASSWORD"] @@ -25,13 +25,13 @@ DATABASES = { } REDIS_CACHE = { - "host": os.environ["REDIS_PORT_6379_TCP_ADDR"], + "host": "oj_redis", "port": 6379, "db": 1 } REDIS_QUEUE = { - "host": os.environ["REDIS_PORT_6379_TCP_ADDR"], + "host": "oj_redis", "port": 6379, "db": 2 } diff --git a/oj/settings.py b/oj/settings.py index 847c19e5..e52963b9 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -23,6 +23,7 @@ elif ENV == "server": from .server_settings import * from .custom_settings import * +from .secret_key import * BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -124,18 +125,6 @@ LOGGING = { # 日志格式 }, 'handlers': { - 'django_error': { - 'level': 'DEBUG', - 'class': 'logging.handlers.RotatingFileHandler', - 'filename': LOG_PATH + 'django.log', - 'formatter': 'standard' - }, - 'app_info': { - 'level': 'DEBUG', - 'class': 'logging.handlers.RotatingFileHandler', - 'filename': LOG_PATH + 'app_info.log', - 'formatter': 'standard' - }, 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', @@ -144,12 +133,12 @@ LOGGING = { }, 'loggers': { 'app_info': { - 'handlers': ['app_info', "console"], + 'handlers': ["console"], 'level': 'DEBUG', 'propagate': True }, 'django.request': { - 'handlers': ['django_error', 'console'], + 'handlers': ['console'], 'level': 'DEBUG', 'propagate': True, }, diff --git a/static/src/js/app/oj/account/login.js b/static/src/js/app/oj/account/login.js index 3e35fd05..8f9787ac 100644 --- a/static/src/js/app/oj/account/login.js +++ b/static/src/js/app/oj/account/login.js @@ -28,7 +28,7 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c return temp.indexOf("&")>=0 ? temp.split("&")[0] : temp; } var from = getLocationVal("__from"); - if(from != ""){ + if(from != "" && from.substring(0, 1) == "/"){ window.location.href = from; } else{ @@ -48,4 +48,4 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c } }); -}); \ No newline at end of file +}); diff --git a/template/src/admin/judges/judges.html b/template/src/admin/judges/judges.html index 82d8f84e..364089af 100644 --- a/template/src/admin/judges/judges.html +++ b/template/src/admin/judges/judges.html @@ -47,8 +47,8 @@
- - + +
@@ -100,8 +100,8 @@
- - + +
diff --git a/template/src/oj/problem/_submit_problem.html b/template/src/oj/problem/_submit_problem.html index f21f45df..079ffb76 100644 --- a/template/src/oj/problem/_submit_problem.html +++ b/template/src/oj/problem/_submit_problem.html @@ -2,13 +2,13 @@
@@ -22,4 +22,4 @@ 提交代码 - \ No newline at end of file + diff --git a/template/src/utils/help.html b/template/src/utils/help.html index 3c9a1539..5ed1ed02 100644 --- a/template/src/utils/help.html +++ b/template/src/utils/help.html @@ -25,11 +25,11 @@

编译参数