Skip to content

Commit

Permalink
fix: backend linting
Browse files Browse the repository at this point in the history
  • Loading branch information
francisvaut committed May 21, 2024
1 parent cbc203c commit 6f96e4a
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 6 deletions.
29 changes: 24 additions & 5 deletions backend/api/tasks/docker_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,44 @@
from api.logic.get_file_path import get_docker_image_tag
from api.models.docker import DockerImage, StateEnum
from celery import shared_task
from notifications.signals import NotificationType, notification_create
from ypovoli.settings import MEDIA_ROOT


# TODO: Remove built image when it's deleted from the database
@shared_task
def task_docker_image_build(docker_image: DockerImage):
# Set state
docker_image.state = StateEnum.BUILDING
docker_image.save()

notification_type = NotificationType.DOCKER_IMAGE_BUILD_SUCCESS

# Build the image
try:
client = docker.from_env()
client.images.build(path=MEDIA_ROOT, dockerfile=docker_image.file.path,
tag=get_docker_image_tag(docker_image), rm=True, quiet=True, forcerm=True)
docker_image.state = StateEnum.READY
except (docker.errors.APIError, docker.errors.BuildError, docker.errors.APIError, TypeError):
except (docker.errors.APIError, docker.errors.BuildError, TypeError):
docker_image.state = StateEnum.ERROR
# TODO: Sent notification
notification_type = NotificationType.DOCKER_IMAGE_BUILD_ERROR
finally:
# Update the state
docker_image.save()

# Update the state
docker_image.save()
# Send notification
notification_create.send(
sender=DockerImage,
type=notification_type,
queryset=[docker_image.owner],
arguments={"name": docker_image.name},
)


@shared_task
def task_docker_image_remove(docker_image: DockerImage):
try:
client = docker.from_env()
client.images.remove(get_docker_image_tag(docker_image))
except docker.errors.APIError:
pass
51 changes: 50 additions & 1 deletion backend/api/tasks/extra_check.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import io
import os
import shutil
import zipfile
from time import sleep
Expand All @@ -14,6 +16,7 @@
from django.core.files.base import ContentFile
from docker.models.containers import Container
from docker.types import LogConfig
from notifications.signals import NotificationType, notification_create
from requests.exceptions import ConnectionError


Expand All @@ -33,12 +36,22 @@ def task_extra_check_start(structure_check_result: bool, extra_check_result: Ext
extra_check_result.error_message = ErrorMessageEnum.DOCKER_IMAGE_ERROR
extra_check_result.save()

notification_create.send(
sender=ExtraCheckResult,
type=NotificationType.EXTRA_CHECK_FAIL,
queryset=list(extra_check_result.submission.group.students.all()),
arguments={"name": extra_check_result.extra_check.name},
)

return structure_check_result

# Will probably never happen but doesn't hurt to check
while extra_check_result.submission.running_checks:
sleep(1)

# Notification type
notification_type = NotificationType.EXTRA_CHECK_SUCCESS

# Lock
extra_check_result.submission.running_checks = True

Expand All @@ -48,13 +61,17 @@ def task_extra_check_start(structure_check_result: bool, extra_check_result: Ext

submission_directory = "/".join(extra_check_result.submission.zip.path.split("/")
[:-1]) + "/submission/" # Directory where the files will be extracted
artifacts_directory = f"{submission_directory}/artifacts" # Directory where the artifacts will be stored
extra_check_name = extra_check_result.extra_check.file.name.split("/")[-1] # Name of the extra check file
submission_uuid = extra_check_result.submission.zip.path.split("/")[-2] # Uuid of the submission

# Unzip the files
with zipfile.ZipFile(extra_check_result.submission.zip.path, 'r') as zip:
zip.extractall(submission_directory)

# Create artifacts directory
os.makedirs(artifacts_directory, exist_ok=True)

container: Container | None = None

try:
Expand All @@ -76,6 +93,9 @@ def task_extra_check_start(structure_check_result: bool, extra_check_result: Ext
f"{get_submission_full_dir_path(extra_check_result.submission)}/submission": {
"bind": "/submission", "mode": "rw"
},
f"{get_submission_full_dir_path(extra_check_result.submission)}/submission/artifacts": {
"bind": "/submission/artifacts", "mode": "rw"
},
get_extra_check_file_full_path(extra_check_result.extra_check): {
"bind": f"/submission/{extra_check_name}", "mode": "ro"
}
Expand Down Expand Up @@ -104,43 +124,52 @@ def task_extra_check_start(structure_check_result: bool, extra_check_result: Ext
case 1:
extra_check_result.result = StateEnum.FAILED
extra_check_result.error_message = ErrorMessageEnum.CHECK_ERROR
notification_type = NotificationType.EXTRA_CHECK_FAIL

# Time limit
case 2:
extra_check_result.result = StateEnum.FAILED
extra_check_result.error_message = ErrorMessageEnum.TIME_LIMIT
notification_type = NotificationType.EXTRA_CHECK_FAIL

# Memory limit
case 3:
extra_check_result.result = StateEnum.FAILED
extra_check_result.error_message = ErrorMessageEnum.MEMORY_LIMIT
notification_type = NotificationType.EXTRA_CHECK_FAIL

# Catch all non zero exit codes
case _:
extra_check_result.result = StateEnum.FAILED
extra_check_result.error_message = ErrorMessageEnum.RUNTIME_ERROR
notification_type = NotificationType.EXTRA_CHECK_FAIL

# Docker image error
except (docker.errors.APIError, docker.errors.ImageNotFound):
extra_check_result.result = StateEnum.FAILED
extra_check_result.error_message = ErrorMessageEnum.DOCKER_IMAGE_ERROR
notification_type = NotificationType.EXTRA_CHECK_FAIL

# Runtime error
except docker.errors.ContainerError:
extra_check_result.result = StateEnum.FAILED
extra_check_result.error_message = ErrorMessageEnum.RUNTIME_ERROR
notification_type = NotificationType.EXTRA_CHECK_FAIL

# Timeout error
except ConnectionError:
extra_check_result.result = StateEnum.FAILED
extra_check_result.error_message = ErrorMessageEnum.TIME_LIMIT
notification_type = NotificationType.EXTRA_CHECK_FAIL

# Unknown error
except Exception:
extra_check_result.result = StateEnum.FAILED
extra_check_result.error_message = ErrorMessageEnum.UNKNOWN
notification_type = NotificationType.EXTRA_CHECK_FAIL

# Cleanup and data saving
# Start by saving any logs
finally:
logs: str
if container:
Expand All @@ -153,7 +182,27 @@ def task_extra_check_start(structure_check_result: bool, extra_check_result: Ext
logs = "Container error"

extra_check_result.log_file.save(submission_uuid, content=ContentFile(logs), save=False)
extra_check_result.save()

# Send notification
notification_create.send(
sender=ExtraCheckResult,
type=notification_type,
queryset=list(extra_check_result.submission.group.students.all()),
arguments={"name": extra_check_result.extra_check.name},
)

# Zip and save any possible artifacts
memory_zip = io.BytesIO()
if os.listdir(artifacts_directory):
with zipfile.ZipFile(memory_zip, 'w') as zip:
for root, _, files in os.walk(artifacts_directory):
for file in files:
zip.write(os.path.join(root, file), os.path.relpath(os.path.join(root, file), artifacts_directory))

memory_zip.seek(0)
extra_check_result.artifact.save(submission_uuid, ContentFile(memory_zip.read()), False)

extra_check_result.save()

# Remove directory
try:
Expand Down

0 comments on commit 6f96e4a

Please sign in to comment.