From 121c29c2f3582af0ad21e3f97499b59921fabab3 Mon Sep 17 00:00:00 2001 From: ITQ Date: Sun, 2 Mar 2025 23:28:14 +0300 Subject: [PATCH] its okay --- compose.yaml | 7 +++++- infrastructure/checker/.env.template | 2 ++ services/backend/api/v1/task/views.py | 6 ++--- services/backend/apps/task/tasks.py | 8 +++--- services/checker/config.py | 18 ++++++++++++++ services/checker/main.py | 36 ++++++++++++++++----------- services/checker/pyproject.toml | 1 + 7 files changed, 55 insertions(+), 23 deletions(-) create mode 100644 infrastructure/checker/.env.template create mode 100644 services/checker/config.py diff --git a/compose.yaml b/compose.yaml index e4401a3..eabd04b 100644 --- a/compose.yaml +++ b/compose.yaml @@ -375,13 +375,18 @@ services: build: context: ./services/checker dockerfile: Dockerfile - restart: unless-stopped + env_file: + - path: ./infrastructure/checker/.env.template + required: true + - path: ./infrastructure/checker/.env + required: false ports: - name: web target: 8000 published: 8009 host_ip: 0.0.0.0 protocol: tcp + restart: unless-stopped volumes: - type: bind source: /var/run/docker.sock diff --git a/infrastructure/checker/.env.template b/infrastructure/checker/.env.template new file mode 100644 index 0000000..7c6f9d3 --- /dev/null +++ b/infrastructure/checker/.env.template @@ -0,0 +1,2 @@ +REGISTRY_LOGIN=devitq +REGISTRY_PASSWORD=14zQrbzDTM0WXK@CogMQikAvP74Rj4 diff --git a/services/backend/api/v1/task/views.py b/services/backend/api/v1/task/views.py index 91f7477..afa91cf 100644 --- a/services/backend/api/v1/task/views.py +++ b/services/backend/api/v1/task/views.py @@ -19,6 +19,7 @@ from apps.task.models import ( CompetitionTaskAttachment, CompetitionTaskSubmission, ) +from apps.task.tasks import analyze_data_task router = Router(tags=["competition"]) @@ -123,6 +124,7 @@ def submit_task( status=CompetitionTaskSubmission.StatusChoices.CHECKING, content=content, ) + analyze_data_task.delay(submission_id=submission.id) return TaskSubmissionOut(submission_id=submission.id) @@ -154,6 +156,4 @@ def get_submissions_history(request, competition_id: UUID, task_id: UUID): ) def get_task_attachments(request, competition_id: UUID, task_id: UUID): task = get_object_or_404(CompetitionTask, id=task_id) - return status.OK, CompetitionTaskAttachment.objects.filter( - task=task - ).all() + return status.OK, CompetitionTaskAttachment.objects.filter(task=task).all() diff --git a/services/backend/apps/task/tasks.py b/services/backend/apps/task/tasks.py index 0c0a6a9..2f3d50c 100644 --- a/services/backend/apps/task/tasks.py +++ b/services/backend/apps/task/tasks.py @@ -1,4 +1,4 @@ -import requests +import httpx from celery import shared_task from django.core.files.base import ContentFile @@ -17,7 +17,7 @@ def analyze_data_task(self, submission_id): for f in submission.task.attachments.filter(public=True) ] - response = requests.post( + response = httpx.post( f"{settings.CHECKER_API_ENDPOINT}/execute", files=[("files", (f.name, f)) for f in files] + [ @@ -40,10 +40,10 @@ def analyze_data_task(self, submission_id): ) submission.status = CompetitionTaskSubmission.StatusChoices.CHECKED - except requests.exceptions.RequestException as e: + except httpx.RequestError as e: self.retry(countdown=2**self.request.retries) except Exception as e: - submission.result = {"error": str(e)} + submission.result = {"error": str(e), "success": False} submission.status = CompetitionTaskSubmission.StatusChoices.CHECKED submission.earned_points = 0 finally: diff --git a/services/checker/config.py b/services/checker/config.py new file mode 100644 index 0000000..b297cc8 --- /dev/null +++ b/services/checker/config.py @@ -0,0 +1,18 @@ +import os +from pathlib import Path + +from dotenv import load_dotenv + +BASE_DIR = Path(__file__).resolve().parent + +load_dotenv(BASE_DIR / ".env") + +REGISTRY_LOGIN = os.getenv("REGISTRY_USERNAME", None) + +REGISTRY_PASSWORD = os.getenv("REGISTRY_USERNAME", None) + +REGISTRY_URL = os.getenv("REGISTRY_URL", "gitlab.prodcontest.ru:5050") + +DOCKER_IMAGE = os.getenv( + "IMAGE", default="gitlab.prodcontest.ru:5050/team-15/project/custom-python" +) diff --git a/services/checker/main.py b/services/checker/main.py index 4b01fac..f30a3de 100644 --- a/services/checker/main.py +++ b/services/checker/main.py @@ -10,19 +10,25 @@ import tempfile import logging from urllib.parse import urlparse import re - -app = FastAPI() -docker_client = docker.from_env() -logger = logging.getLogger(__name__) -logging.basicConfig(level=logging.INFO) +import config -DOCKER_IMAGE = "gitlab.python:3-slim" CONTAINER_TIMEOUT = 60 MAX_FILE_SIZE = 4 * 1024 * 1024 ALLOWED_FILENAME_CHARS = r"[^a-zA-Z0-9_\-.]" +app = FastAPI() +docker_client = docker.from_env() +logger = logging.getLoggerQ(__name__) +logging.basicConfig(level=logging.INFO) +docker_client.login( + username=config.REGISTRY_LOGIN, + password=config.REGISTRY_PASSWORD, + registry=config.REGISTRY_URL, +) + + class FileDetails(BaseModel): url: HttpUrl = Field( ..., description="URL to download the file from (supports HTTP/HTTPS)" @@ -130,7 +136,7 @@ def run_container_safely( volumes[host_path] = {"bind": container_path, "mode": "ro"} container = docker_client.containers.run( - image=DOCKER_IMAGE, + image=config.DOCKER_IMAGE, command=command, volumes=volumes, working_dir="/execution", @@ -166,6 +172,14 @@ def run_container_safely( pass +def validate_file_path(path: str) -> bool: + return ( + not os.path.isabs(path) + and os.path.basename(path) == path + and all(c.isalnum() or c in {"_", "-", "."} for c in path) + ) + + @app.post("/execute", response_model=ExecutionResponse) async def execute_code(request: ExecutionRequest) -> ExecutionResponse: try: @@ -279,11 +293,3 @@ async def health_check() -> HealthCheckResponse: return HealthCheckResponse(status="healthy", docker="connected") except docker.errors.DockerException: return HealthCheckResponse(status="degraded", docker="unavailable") - - -def validate_file_path(path: str) -> bool: - return ( - not os.path.isabs(path) - and os.path.basename(path) == path - and all(c.isalnum() or c in {"_", "-", "."} for c in path) - ) diff --git a/services/checker/pyproject.toml b/services/checker/pyproject.toml index 2e47424..aaa49d4 100644 --- a/services/checker/pyproject.toml +++ b/services/checker/pyproject.toml @@ -7,6 +7,7 @@ dependencies = [ "aiohttp>=3.11.13", "docker>=7.1.0", "fastapi>=0.115.11", + "python-dotenv>=1.0.1", "python-multipart>=0.0.20", "regex>=2024.11.6", "uvicorn>=0.34.0",