mirror of
https://github.com/QingdaoU/OnlineJudge.git
synced 2025-01-16 01:13:47 +00:00
add judge_server related api
This commit is contained in:
parent
294fd8b5b2
commit
f56d75cf91
33
conf/migrations/0003_judgeserver.py
Normal file
33
conf/migrations/0003_judgeserver.py
Normal file
@ -0,0 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.10 on 2016-11-19 14:27
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('conf', '0002_auto_20161119_1657'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='JudgeServer',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('hostname', models.CharField(max_length=64)),
|
||||
('ip', models.CharField(max_length=32)),
|
||||
('judger_version', models.CharField(max_length=24)),
|
||||
('cpu_core', models.IntegerField()),
|
||||
('memory_usage', models.FloatField()),
|
||||
('cpu_usage', models.FloatField()),
|
||||
('last_heartbeat', models.DateTimeField()),
|
||||
('create_time', models.DateTimeField(auto_now_add=True)),
|
||||
('task_number', models.IntegerField()),
|
||||
],
|
||||
options={
|
||||
'db_table': 'judge_server',
|
||||
},
|
||||
),
|
||||
]
|
25
conf/migrations/0004_auto_20161120_1834.py
Normal file
25
conf/migrations/0004_auto_20161120_1834.py
Normal file
@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.10 on 2016-11-20 10:34
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('conf', '0003_judgeserver'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='judgeserver',
|
||||
name='service_url',
|
||||
field=models.CharField(blank=True, max_length=128, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='judgeserver',
|
||||
name='ip',
|
||||
field=models.CharField(blank=True, max_length=32, null=True),
|
||||
),
|
||||
]
|
25
conf/migrations/0005_judgeservertoken.py
Normal file
25
conf/migrations/0005_judgeservertoken.py
Normal file
@ -0,0 +1,25 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.10 on 2016-11-20 11:00
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('conf', '0004_auto_20161120_1834'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='JudgeServerToken',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('token', models.CharField(max_length=32)),
|
||||
],
|
||||
options={
|
||||
'db_table': 'judge_server_token',
|
||||
},
|
||||
),
|
||||
]
|
@ -28,3 +28,25 @@ class WebsiteConfig(models.Model):
|
||||
class Meta:
|
||||
db_table = "website_config"
|
||||
|
||||
|
||||
class JudgeServer(models.Model):
|
||||
hostname = models.CharField(max_length=64)
|
||||
ip = models.CharField(max_length=32, blank=True, null=True)
|
||||
judger_version = models.CharField(max_length=24)
|
||||
cpu_core = models.IntegerField()
|
||||
memory_usage = models.FloatField()
|
||||
cpu_usage = models.FloatField()
|
||||
last_heartbeat = models.DateTimeField()
|
||||
create_time = models.DateTimeField(auto_now_add=True)
|
||||
task_number = models.IntegerField(default=0)
|
||||
service_url = models.CharField(max_length=128, blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
db_table = "judge_server"
|
||||
|
||||
|
||||
class JudgeServerToken(models.Model):
|
||||
token = models.CharField(max_length=32)
|
||||
|
||||
class Meta:
|
||||
db_table = "judge_server_token"
|
||||
|
@ -1,12 +1,12 @@
|
||||
from utils.api import serializers
|
||||
from utils.api import serializers, DateTimeTZField
|
||||
|
||||
from .models import SMTPConfig, WebsiteConfig
|
||||
from .models import SMTPConfig, WebsiteConfig, JudgeServer
|
||||
|
||||
|
||||
class EditSMTPConfigSerializer(serializers.Serializer):
|
||||
server = serializers.CharField(max_length=128)
|
||||
port = serializers.IntegerField(default=25)
|
||||
email = serializers.CharField(max_length=128)
|
||||
email = serializers.EmailField(max_length=128)
|
||||
password = serializers.CharField(max_length=128, required=False, allow_null=True, allow_blank=True)
|
||||
tls = serializers.BooleanField()
|
||||
|
||||
@ -37,4 +37,23 @@ class CreateEditWebsiteConfigSerializer(serializers.Serializer):
|
||||
class WebsiteConfigSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = WebsiteConfig
|
||||
exclude = ["id"]
|
||||
exclude = ["id"]
|
||||
|
||||
|
||||
class JudgeServerSerializer(serializers.ModelSerializer):
|
||||
create_time = DateTimeTZField()
|
||||
last_heartbeat = DateTimeTZField()
|
||||
|
||||
class Meta:
|
||||
model = JudgeServer
|
||||
|
||||
|
||||
class JudgeServerHeartbeatSerializer(serializers.Serializer):
|
||||
hostname = serializers.CharField(max_length=64)
|
||||
judger_version = serializers.CharField(max_length=24)
|
||||
cpu_core = serializers.IntegerField(min_value=1)
|
||||
memory = serializers.FloatField(min_value=0, max_value=100)
|
||||
cpu = serializers.FloatField(min_value=0, max_value=100)
|
||||
action = serializers.ChoiceField(choices=("heartbeat", ))
|
||||
service_url = serializers.CharField(max_length=128, required=False)
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
from utils.api.tests import APITestCase
|
||||
import hashlib
|
||||
|
||||
from .models import SMTPConfig, WebsiteConfig
|
||||
from utils.api.tests import APITestCase
|
||||
from .models import SMTPConfig, JudgeServerToken, JudgeServer
|
||||
|
||||
|
||||
class SMTPConfigTest(APITestCase):
|
||||
@ -73,3 +74,51 @@ class WebsiteConfigAPITest(APITestCase):
|
||||
resp = self.client.get(url)
|
||||
self.assertSuccess(resp)
|
||||
self.assertEqual(resp.data["data"]["name_shortcut"], "oj")
|
||||
|
||||
|
||||
class JudgeServerStatusAPITest(APITestCase):
|
||||
def setUp(self):
|
||||
self.url = self.reverse("judge_server_api")
|
||||
self.user = self.create_super_admin()
|
||||
|
||||
def test_get_judge_server_status(self):
|
||||
self.assertFalse(JudgeServerToken.objects.exists())
|
||||
resp = self.client.get(self.url)
|
||||
self.assertSuccess(resp)
|
||||
self.assertListEqual(resp.data["data"]["servers"], [])
|
||||
self.assertEqual(JudgeServerToken.objects.first().token, resp.data["data"]["token"])
|
||||
|
||||
|
||||
class JudgeServerHeartbeatest(APITestCase):
|
||||
def setUp(self):
|
||||
self.url = self.reverse("judge_server_heartbeat_api")
|
||||
self.data = {"hostname": "testhostname", "judger_version": "1.0.4", "cpu_core": 4,
|
||||
"cpu": 90.5, "memory": 80.3, "action": "heartbeat"}
|
||||
self.token = "test"
|
||||
self.hashed_token = hashlib.sha256(self.token.encode("utf-8")).hexdigest()
|
||||
JudgeServerToken.objects.create(token=self.token)
|
||||
|
||||
def test_new_heartbeat(self):
|
||||
resp = self.client.post(self.url, data=self.data, **{"HTTP_X_JUDGE_SERVER_TOKEN": self.hashed_token})
|
||||
self.assertSuccess(resp)
|
||||
server = JudgeServer.objects.first()
|
||||
self.assertEqual(server.ip, "127.0.0.1")
|
||||
self.assertEqual(server.service_url ,None)
|
||||
|
||||
def test_new_heartbeat_service_url(self):
|
||||
service_url = "http://1.2.3.4:8000/api/judge"
|
||||
data = self.data
|
||||
data["service_url"] = service_url
|
||||
resp = self.client.post(self.url, data=self.data, **{"HTTP_X_JUDGE_SERVER_TOKEN": self.hashed_token})
|
||||
self.assertSuccess(resp)
|
||||
server = JudgeServer.objects.first()
|
||||
self.assertEqual(server.ip, None)
|
||||
self.assertEqual(server.service_url, service_url)
|
||||
|
||||
def test_update_heartbeat(self):
|
||||
self.test_new_heartbeat()
|
||||
data = self.data
|
||||
data["judger_version"] = "2.0.0"
|
||||
resp = self.client.post(self.url, data=data, **{"HTTP_X_JUDGE_SERVER_TOKEN": self.hashed_token})
|
||||
self.assertSuccess(resp)
|
||||
self.assertEqual(JudgeServer.objects.get(hostname=self.data["hostname"]).judger_version, data["judger_version"])
|
||||
|
@ -1,8 +1,9 @@
|
||||
from django.conf.urls import url
|
||||
|
||||
from ..views import WebsiteConfigAPI, SMTPAPI
|
||||
from ..views import WebsiteConfigAPI, SMTPAPI, JudgeServerAPI
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^smtp$', SMTPAPI.as_view(), name="smtp_admin_api"),
|
||||
url(r'^website$', WebsiteConfigAPI.as_view(), name="website_config_api"),
|
||||
url(r'^judge_server', JudgeServerAPI.as_view(), name="judge_server_api")
|
||||
]
|
||||
|
@ -1,7 +1,9 @@
|
||||
from django.conf.urls import url
|
||||
|
||||
from ..views import WebsiteConfigAPI
|
||||
from ..views import WebsiteConfigAPI, JudgeServerHeartbeatAPI
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^website$', WebsiteConfigAPI.as_view(), name="website_info_api"),
|
||||
url(r'^judge_server_heartbeat$', JudgeServerHeartbeatAPI.as_view(), name="judge_server_heartbeat_api")
|
||||
]
|
||||
|
@ -1,11 +1,16 @@
|
||||
from utils.api import APIView, validate_serializer
|
||||
import hashlib
|
||||
|
||||
from django.utils import timezone
|
||||
|
||||
from account.decorators import super_admin_required
|
||||
from utils.api import APIView, CSRFExemptAPIView, validate_serializer
|
||||
from utils.shortcuts import rand_str
|
||||
|
||||
from .models import SMTPConfig, WebsiteConfig
|
||||
from .models import SMTPConfig, WebsiteConfig, JudgeServer, JudgeServerToken
|
||||
from .serializers import (WebsiteConfigSerializer, CreateEditWebsiteConfigSerializer,
|
||||
CreateSMTPConfigSerializer, EditSMTPConfigSerializer,
|
||||
SMTPConfigSerializer, TestSMTPConfigSerializer)
|
||||
SMTPConfigSerializer, TestSMTPConfigSerializer,
|
||||
JudgeServerSerializer, JudgeServerHeartbeatSerializer)
|
||||
|
||||
|
||||
class SMTPAPI(APIView):
|
||||
@ -63,3 +68,65 @@ class WebsiteConfigAPI(APIView):
|
||||
WebsiteConfig.objects.all().delete()
|
||||
config = WebsiteConfig.objects.create(**data)
|
||||
return self.success(WebsiteConfigSerializer(config).data)
|
||||
|
||||
|
||||
class JudgeServerAPI(APIView):
|
||||
@super_admin_required
|
||||
def get(self, request):
|
||||
judge_server_token = JudgeServerToken.objects.first()
|
||||
if not judge_server_token:
|
||||
token = rand_str(12)
|
||||
JudgeServerToken.objects.create(token=token)
|
||||
else:
|
||||
token = judge_server_token.token
|
||||
servers = JudgeServer.objects.all().order_by("-last_heartbeat")
|
||||
return self.success({"token": token,
|
||||
"servers": JudgeServerSerializer(servers, many=True).data})
|
||||
|
||||
@super_admin_required
|
||||
def delete(self, request):
|
||||
pass
|
||||
|
||||
|
||||
class JudgeServerHeartbeatAPI(CSRFExemptAPIView):
|
||||
@validate_serializer(JudgeServerHeartbeatSerializer)
|
||||
def post(self, request):
|
||||
judge_server_token = JudgeServerToken.objects.first()
|
||||
if not judge_server_token:
|
||||
return self.error("Web server token not set")
|
||||
token = judge_server_token.token
|
||||
data = request.data
|
||||
judge_server_token = request.META.get("HTTP_X_JUDGE_SERVER_TOKEN")
|
||||
if hashlib.sha256(token.encode("utf-8")).hexdigest() != judge_server_token:
|
||||
return self.error("Invalid token")
|
||||
service_url = data.get("service_url")
|
||||
if service_url:
|
||||
ip = None
|
||||
else:
|
||||
ip = request.META["REMOTE_ADDR"]
|
||||
|
||||
try:
|
||||
server = JudgeServer.objects.get(hostname=data["hostname"])
|
||||
server.judger_version = data["judger_version"]
|
||||
server.cpu_core = data["cpu_core"]
|
||||
server.memory_usage = data["memory"]
|
||||
server.cpu_usage = data["cpu"]
|
||||
server.service_url= service_url
|
||||
server.ip = ip
|
||||
server.last_heartbeat = timezone.now()
|
||||
server.save()
|
||||
except JudgeServer.DoesNotExist:
|
||||
JudgeServer.objects.create(hostname=data["hostname"],
|
||||
judger_version=data["judger_version"],
|
||||
cpu_core=data["cpu_core"],
|
||||
memory_usage=data["memory"],
|
||||
cpu_usage=data["cpu"],
|
||||
ip=ip,
|
||||
service_url=service_url,
|
||||
last_heartbeat=timezone.now(),
|
||||
)
|
||||
return self.success()
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user