From cc6337dffbf745a1862120d5db9f499273098221 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Wed, 22 Mar 2023 19:30:43 +0100 Subject: [PATCH 01/68] Apply fixes --- cvat/apps/engine/backup.py | 17 ++++++++++------- cvat/apps/engine/mixins.py | 1 + cvat/apps/engine/utils.py | 25 +++++++++++++++++++------ cvat/apps/engine/views.py | 30 ++++++++++++++++-------------- cvat/apps/events/export.py | 4 ++-- cvat/requirements/base.txt | 4 ++-- 6 files changed, 50 insertions(+), 31 deletions(-) diff --git a/cvat/apps/engine/backup.py b/cvat/apps/engine/backup.py index 98c6fcc5457..e21a5f2bcaf 100644 --- a/cvat/apps/engine/backup.py +++ b/cvat/apps/engine/backup.py @@ -34,7 +34,9 @@ from cvat.apps.engine.serializers import (AttributeSerializer, DataSerializer, LabelSerializer, LabeledDataSerializer, SegmentSerializer, SimpleJobSerializer, TaskReadSerializer, ProjectReadSerializer, ProjectFileSerializer, TaskFileSerializer) -from cvat.apps.engine.utils import av_scan_paths, process_failed_job, configure_dependent_job, get_rq_job_meta +from cvat.apps.engine.utils import ( + av_scan_paths, process_failed_job, configure_dependent_job, get_rq_job_meta, handle_finished_or_failed_job +) from cvat.apps.engine.models import ( StorageChoice, StorageMethodChoice, DataChoice, Task, Project, Location, CloudStorage as CloudStorageModel) @@ -830,7 +832,7 @@ def export(db_instance, request, queue_name): rq_job.delete() else: if rq_job.is_finished: - file_path = rq_job.return_value + file_path = rq_job.return_value() if action == "download" and os.path.exists(file_path): rq_job.delete() @@ -867,7 +869,7 @@ def export(db_instance, request, queue_name): if os.path.exists(file_path): return Response(status=status.HTTP_201_CREATED) elif rq_job.is_failed: - exc_info = str(rq_job.exc_info) + exc_info = rq_job.meta.get('formatted_exception', str(rq_job.exc_info)) rq_job.delete() return Response(exc_info, status=status.HTTP_500_INTERNAL_SERVER_ERROR) @@ -940,13 +942,14 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati 'tmp_file_descriptor': fd, **get_rq_job_meta(request=request, db_obj=None) }, - depends_on=dependent_job + depends_on=dependent_job, + on_success=handle_finished_or_failed_job, + on_failure=handle_finished_or_failed_job ) else: if rq_job.is_finished: - project_id = rq_job.return_value - if rq_job.meta['tmp_file_descriptor']: os.close(rq_job.meta['tmp_file_descriptor']) - os.remove(rq_job.meta['tmp_file']) + project_id = rq_job.return_value() + handle_finished_or_failed_job(rq_job) rq_job.delete() return Response({'id': project_id}, status=status.HTTP_201_CREATED) elif rq_job.is_failed or \ diff --git a/cvat/apps/engine/mixins.py b/cvat/apps/engine/mixins.py index 5d4739f757e..35834323eb3 100644 --- a/cvat/apps/engine/mixins.py +++ b/cvat/apps/engine/mixins.py @@ -175,6 +175,7 @@ def init_tus_upload(self, request): return self._tus_response(status=status.HTTP_409_CONFLICT, data="File with same name already exists") + # TODO: check if rq job exists and is active file_size = int(request.META.get("HTTP_UPLOAD_LENGTH", "0")) if file_size > int(self._tus_max_file_size): return self._tus_response(status=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, diff --git a/cvat/apps/engine/utils.py b/cvat/apps/engine/utils.py index 8903a93f5eb..4d580ffa64c 100644 --- a/cvat/apps/engine/utils.py +++ b/cvat/apps/engine/utils.py @@ -12,7 +12,9 @@ import subprocess import os import urllib.parse +import logging from django.utils import timezone +from rq.job import Job from av import VideoFrame from PIL import Image @@ -124,17 +126,26 @@ def parse_exception_message(msg): pass return parsed_msg -def process_failed_job(rq_job): - if rq_job.meta['tmp_file_descriptor']: - os.close(rq_job.meta['tmp_file_descriptor']) - if os.path.exists(rq_job.meta['tmp_file']): - os.remove(rq_job.meta['tmp_file']) +def process_failed_job(rq_job: Job): + handle_finished_or_failed_job(rq_job) exc_info = str(rq_job.exc_info or rq_job.dependency.exc_info) if rq_job.dependency: rq_job.dependency.delete() rq_job.delete() - return parse_exception_message(exc_info) + msg = parse_exception_message(exc_info) + log = logging.getLogger('cvat.server.engine') + log.error(msg) + return msg + +def handle_finished_or_failed_job(rq_job: Job, *args, **kwargs): + # TODO check file from dependent job + if rq_job.meta['tmp_file_descriptor']: + os.close(rq_job.meta['tmp_file_descriptor']) + rq_job.meta['tmp_file_descriptor'] = None + rq_job.save() + if os.path.exists(rq_job.meta['tmp_file']): + os.remove(rq_job.meta['tmp_file']) def configure_dependent_job(queue, rq_id, rq_func, db_storage, filename, key, request): rq_job_id_download_file = rq_id + f'?action=download_{filename}' @@ -146,6 +157,8 @@ def configure_dependent_job(queue, rq_id, rq_func, db_storage, filename, key, re args=(db_storage, filename, key), job_id=rq_job_id_download_file, meta=get_rq_job_meta(request=request, db_obj=db_storage), + on_success=handle_finished_or_failed_job, + on_failure=handle_finished_or_failed_job, ) return rq_job_download_file diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index d2648e45782..227f9dd94a4 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -64,7 +64,7 @@ from utils.dataset_manifest import ImageManifestManager from cvat.apps.engine.utils import ( - av_scan_paths, process_failed_job, configure_dependent_job, parse_exception_message, get_rq_job_meta + av_scan_paths, process_failed_job, configure_dependent_job, parse_exception_message, get_rq_job_meta, handle_finished_or_failed_job ) from cvat.apps.engine import backup from cvat.apps.engine.mixins import PartialUpdateModelMixin, UploadMixin, AnnotationMixin, SerializeMixin, DestroyModelMixin, CreateModelMixin @@ -327,8 +327,7 @@ def dataset(self, request, pk): if rq_job is None: return Response(status=status.HTTP_404_NOT_FOUND) elif rq_job.is_finished: - if rq_job.meta['tmp_file_descriptor']: os.close(rq_job.meta['tmp_file_descriptor']) - os.remove(rq_job.meta['tmp_file']) + handle_finished_or_failed_job(rq_job) if rq_job.dependency: rq_job.dependency.delete() rq_job.delete() @@ -1318,17 +1317,15 @@ def get_serializer_class(self): # UploadMixin method def get_upload_dir(self): - task = self._object.segment.task - return task.get_tmp_dirname() + return self._object.get_tmp_dirname() # UploadMixin method def upload_finished(self, request): - task = self._object.segment.task if self.action == 'annotations': format_name = request.query_params.get("format", "") filename = request.query_params.get("filename", "") conv_mask_to_poly = strtobool(request.query_params.get('conv_mask_to_poly', 'True')) - tmp_dir = task.get_tmp_dirname() + tmp_dir = self._object.get_tmp_dirname() if os.path.isfile(os.path.join(tmp_dir, filename)): annotation_file = os.path.join(tmp_dir, filename) return _import_annotations( @@ -2232,7 +2229,7 @@ def actions(self, request, pk): return HttpResponseBadRequest(msg) def rq_exception_handler(rq_job, exc_type, exc_value, tb): - rq_job.exc_info = "".join( + rq_job.meta["formatted_exception"] = "".join( traceback.format_exception_only(exc_type, exc_value)) rq_job.save() @@ -2276,7 +2273,7 @@ def _import_annotations(request, rq_id, rq_func, db_obj, format_name, for chunk in anno_file.chunks(): f.write(chunk) else: - assert filename, 'The filename was not spesified' + assert filename, 'The filename was not specified' try: storage_id = location_conf['storage_id'] except KeyError: @@ -2306,12 +2303,13 @@ def _import_annotations(request, rq_id, rq_func, db_obj, format_name, args=(db_obj.pk, filename, format_name, conv_mask_to_poly), job_id=rq_id, depends_on=dependent_job, - meta={**meta, **get_rq_job_meta(request=request, db_obj=db_obj)} + meta={**meta, **get_rq_job_meta(request=request, db_obj=db_obj)}, + on_success=handle_finished_or_failed_job, + on_failure=handle_finished_or_failed_job ) else: if rq_job.is_finished: - if rq_job.meta['tmp_file_descriptor']: os.close(rq_job.meta['tmp_file_descriptor']) - os.remove(rq_job.meta['tmp_file']) + handle_finished_or_failed_job(rq_job) rq_job.delete() return Response(status=status.HTTP_201_CREATED) elif rq_job.is_failed or \ @@ -2324,6 +2322,8 @@ def _import_annotations(request, rq_id, rq_func, db_obj, format_name, exc_info = exc_info.replace(import_error_prefix + ': ', '') return Response(data=exc_info, status=status.HTTP_400_BAD_REQUEST) + elif "Failed to find 'coco' dataset" in exc_info: + return Response(data=exc_info, status=status.HTTP_400_BAD_REQUEST) else: return Response(data=exc_info, status=status.HTTP_500_INTERNAL_SERVER_ERROR) @@ -2359,7 +2359,7 @@ def _export_annotations(db_instance, rq_id, request, format_name, action, callba rq_job.delete() else: if rq_job.is_finished: - file_path = rq_job.return_value + file_path = rq_job.return_value() if action == "download" and osp.exists(file_path): rq_job.delete() @@ -2401,7 +2401,7 @@ def _export_annotations(db_instance, rq_id, request, format_name, action, callba if osp.exists(file_path): return Response(status=status.HTTP_201_CREATED) elif rq_job.is_failed: - exc_info = str(rq_job.exc_info) + exc_info = rq_job.meta.get('formatted_exception', str(rq_job.exc_info)) rq_job.delete() return Response(exc_info, status=status.HTTP_500_INTERNAL_SERVER_ERROR) @@ -2484,6 +2484,8 @@ def _import_project_dataset(request, rq_id, rq_func, db_obj, format_name, filena **get_rq_job_meta(request=request, db_obj=db_obj), }, depends_on=dependent_job, + on_success=handle_finished_or_failed_job, + on_failure=handle_finished_or_failed_job ) else: return Response(status=status.HTTP_409_CONFLICT, data='Import job already exists') diff --git a/cvat/apps/events/export.py b/cvat/apps/events/export.py index fc041e332ac..f40e609fc7f 100644 --- a/cvat/apps/events/export.py +++ b/cvat/apps/events/export.py @@ -136,7 +136,7 @@ def export(request, filter_query, queue_name): if rq_job: if rq_job.is_finished: - file_path = rq_job.return_value + file_path = rq_job.return_value() if action == "download" and os.path.exists(file_path): rq_job.delete() timestamp = datetime.strftime(datetime.now(), "%Y_%m_%d_%H_%M_%S") @@ -149,7 +149,7 @@ def export(request, filter_query, queue_name): if os.path.exists(file_path): return Response(status=status.HTTP_201_CREATED) elif rq_job.is_failed: - exc_info = str(rq_job.exc_info) + exc_info = rq_job.meta.get('formatted_exception', str(rq_job.exc_info)) rq_job.delete() return Response(exc_info, status=status.HTTP_500_INTERNAL_SERVER_ERROR) diff --git a/cvat/requirements/base.txt b/cvat/requirements/base.txt index e1a3cf2f500..994abe9d0bb 100644 --- a/cvat/requirements/base.txt +++ b/cvat/requirements/base.txt @@ -11,7 +11,7 @@ django-compressor==2.4 # https://dj-rest-auth.readthedocs.io/en/latest/installation.html#registration-optional django-allauth>=0.52.0 dj-rest-auth[with_social]==2.2.7 -django-rq==2.3.2 +django-rq==2.7.0 EasyProcess==0.3 Pillow==9.3.0 numpy==1.22.0 @@ -22,7 +22,7 @@ rcssmin==1.0.6 redis==3.5.3 rjsmin==1.1.0 requests==2.26.0 -rq==1.5.2 +rq==1.13.0 rq-scheduler==0.10.0 sqlparse==0.4.2 django-sendfile2==0.7.0 From e82e5e0caa2b17b6b6e8868ddb950c2e98855cbc Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Thu, 23 Mar 2023 12:26:25 +0100 Subject: [PATCH 02/68] Remove tmp_file_descriptor --- cvat/apps/engine/backup.py | 8 +++----- cvat/apps/engine/utils.py | 6 ------ cvat/apps/engine/views.py | 14 +++++--------- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/cvat/apps/engine/backup.py b/cvat/apps/engine/backup.py index e21a5f2bcaf..158c2740057 100644 --- a/cvat/apps/engine/backup.py +++ b/cvat/apps/engine/backup.py @@ -13,7 +13,7 @@ import uuid from zipfile import ZipFile from datetime import datetime -from tempfile import mkstemp +from tempfile import NamedTemporaryFile import django_rq from django.conf import settings @@ -898,7 +898,6 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati if not rq_job: org_id = getattr(request.iam_context['organization'], 'id', None) - fd = None dependent_job = None location = location_conf.get('location') @@ -907,7 +906,7 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati serializer = Serializer(data=request.data) serializer.is_valid(raise_exception=True) payload_file = serializer.validated_data[file_field_name] - fd, filename = mkstemp(prefix='cvat_', dir=settings.TMP_FILES_ROOT) + filename = NamedTemporaryFile(prefix='cvat_', dir=settings.TMP_FILES_ROOT, delete=False).name with open(filename, 'wb+') as f: for chunk in payload_file.chunks(): f.write(chunk) @@ -922,7 +921,7 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati ' but cloud storage id was not specified') db_storage = get_object_or_404(CloudStorageModel, pk=storage_id) key = filename - fd, filename = mkstemp(prefix='cvat_', dir=settings.TMP_FILES_ROOT) + filename = NamedTemporaryFile(prefix='cvat_', dir=settings.TMP_FILES_ROOT, delete=False).name dependent_job = configure_dependent_job( queue=queue, rq_id=rq_id, @@ -939,7 +938,6 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati job_id=rq_id, meta={ 'tmp_file': filename, - 'tmp_file_descriptor': fd, **get_rq_job_meta(request=request, db_obj=None) }, depends_on=dependent_job, diff --git a/cvat/apps/engine/utils.py b/cvat/apps/engine/utils.py index 4d580ffa64c..f97b58a37a7 100644 --- a/cvat/apps/engine/utils.py +++ b/cvat/apps/engine/utils.py @@ -139,11 +139,6 @@ def process_failed_job(rq_job: Job): return msg def handle_finished_or_failed_job(rq_job: Job, *args, **kwargs): - # TODO check file from dependent job - if rq_job.meta['tmp_file_descriptor']: - os.close(rq_job.meta['tmp_file_descriptor']) - rq_job.meta['tmp_file_descriptor'] = None - rq_job.save() if os.path.exists(rq_job.meta['tmp_file']): os.remove(rq_job.meta['tmp_file']) @@ -157,7 +152,6 @@ def configure_dependent_job(queue, rq_id, rq_func, db_storage, filename, key, re args=(db_storage, filename, key), job_id=rq_job_id_download_file, meta=get_rq_job_meta(request=request, db_obj=db_storage), - on_success=handle_finished_or_failed_job, on_failure=handle_finished_or_failed_job, ) return rq_job_download_file diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 227f9dd94a4..ad267a1b265 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -10,7 +10,7 @@ import traceback from datetime import datetime from distutils.util import strtobool -from tempfile import mkstemp +from tempfile import NamedTemporaryFile from django.db.models.query import Prefetch from django.shortcuts import get_object_or_404 @@ -2259,7 +2259,6 @@ def _import_annotations(request, rq_id, rq_func, db_obj, format_name, # If filename is specified we consider that file was uploaded via TUS, so it exists in filesystem # Then we dont need to create temporary file # Or filename specify key in cloud storage so we need to download file - fd = None dependent_job = None location = location_conf.get('location') if location_conf else Location.LOCAL @@ -2268,7 +2267,7 @@ def _import_annotations(request, rq_id, rq_func, db_obj, format_name, serializer = AnnotationFileSerializer(data=request.data) if serializer.is_valid(raise_exception=True): anno_file = serializer.validated_data['annotation_file'] - fd, filename = mkstemp(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT) + filename = NamedTemporaryFile(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT, delete=False).name with open(filename, 'wb+') as f: for chunk in anno_file.chunks(): f.write(chunk) @@ -2282,7 +2281,7 @@ def _import_annotations(request, rq_id, rq_func, db_obj, format_name, ' but cloud storage id was not specified') db_storage = get_object_or_404(CloudStorageModel, pk=storage_id) key = filename - fd, filename = mkstemp(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT) + filename = NamedTemporaryFile(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT, delete=False).name dependent_job = configure_dependent_job( queue=queue, rq_id=rq_id, @@ -2296,7 +2295,6 @@ def _import_annotations(request, rq_id, rq_func, db_obj, format_name, av_scan_paths(filename) meta = { 'tmp_file': filename, - 'tmp_file_descriptor': fd, } rq_job = queue.enqueue_call( func=rq_func, @@ -2442,14 +2440,13 @@ def _import_project_dataset(request, rq_id, rq_func, db_obj, format_name, filena rq_job = queue.fetch_job(rq_id) if not rq_job: - fd = None dependent_job = None location = location_conf.get('location') if location_conf else None if not filename and location != Location.CLOUD_STORAGE: serializer = DatasetFileSerializer(data=request.data) if serializer.is_valid(raise_exception=True): dataset_file = serializer.validated_data['dataset_file'] - fd, filename = mkstemp(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT) + filename = NamedTemporaryFile(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT, delete=False).name with open(filename, 'wb+') as f: for chunk in dataset_file.chunks(): f.write(chunk) @@ -2463,7 +2460,7 @@ def _import_project_dataset(request, rq_id, rq_func, db_obj, format_name, filena ' but cloud storage id was not specified') db_storage = get_object_or_404(CloudStorageModel, pk=storage_id) key = filename - fd, filename = mkstemp(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT) + filename = NamedTemporaryFile(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT, delete=False).name dependent_job = configure_dependent_job( queue=queue, rq_id=rq_id, @@ -2480,7 +2477,6 @@ def _import_project_dataset(request, rq_id, rq_func, db_obj, format_name, filena job_id=rq_id, meta={ 'tmp_file': filename, - 'tmp_file_descriptor': fd, **get_rq_job_meta(request=request, db_obj=db_obj), }, depends_on=dependent_job, From 2b504d324dafb6aa95efd4fcf54b3e37817a9f8d Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Thu, 23 Mar 2023 13:15:06 +0100 Subject: [PATCH 03/68] Add result_ttl && failure_ttl --- cvat/apps/dataset_manager/views.py | 2 ++ cvat/apps/engine/backup.py | 10 +++++++++- cvat/apps/engine/utils.py | 18 +++++++++++++++++- cvat/apps/engine/views.py | 15 ++++++++++++--- 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/cvat/apps/dataset_manager/views.py b/cvat/apps/dataset_manager/views.py index ba133cc6995..14147d43f31 100644 --- a/cvat/apps/dataset_manager/views.py +++ b/cvat/apps/dataset_manager/views.py @@ -44,6 +44,8 @@ def get_export_cache_dir(db_instance): PROJECT_CACHE_TTL = DEFAULT_CACHE_TTL / 3 JOB_CACHE_TTL = DEFAULT_CACHE_TTL +IMPORT_CACHE_FAILED_TTL = DEFAULT_CACHE_TTL.total_seconds() +IMPORT_CACHE_SUCCESS_TTL = timedelta(hours=1).total_seconds() def export(dst_format, project_id=None, task_id=None, job_id=None, server_url=None, save_images=False): try: diff --git a/cvat/apps/engine/backup.py b/cvat/apps/engine/backup.py index 158c2740057..8448a2ec660 100644 --- a/cvat/apps/engine/backup.py +++ b/cvat/apps/engine/backup.py @@ -27,6 +27,7 @@ from rest_framework.exceptions import ValidationError, PermissionDenied, NotFound from django_sendfile import sendfile from distutils.util import strtobool +from datetime import timedelta import cvat.apps.dataset_manager as dm from cvat.apps.engine import models @@ -51,6 +52,9 @@ class Version(Enum): V1 = '1.0' +IMPORT_CACHE_FAILED_TTL = timedelta(hours=10).total_seconds() +IMPORT_CACHE_SUCCESS_TTL = timedelta(hours=1).total_seconds() + def _get_label_mapping(db_labels): label_mapping = {db_label.id: db_label.name for db_label in db_labels} for db_label in db_labels: @@ -930,6 +934,8 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati filename=filename, key=key, request=request, + result_ttl=IMPORT_CACHE_SUCCESS_TTL, + failure_ttl=IMPORT_CACHE_FAILED_TTL ) rq_job = queue.enqueue_call( @@ -942,7 +948,9 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati }, depends_on=dependent_job, on_success=handle_finished_or_failed_job, - on_failure=handle_finished_or_failed_job + on_failure=handle_finished_or_failed_job, + result_ttl=IMPORT_CACHE_SUCCESS_TTL, + failure_ttl=IMPORT_CACHE_FAILED_TTL ) else: if rq_job.is_finished: diff --git a/cvat/apps/engine/utils.py b/cvat/apps/engine/utils.py index f97b58a37a7..63743c6c03d 100644 --- a/cvat/apps/engine/utils.py +++ b/cvat/apps/engine/utils.py @@ -15,6 +15,10 @@ import logging from django.utils import timezone from rq.job import Job +from django_rq.queues import DjangoRQ +from typing import Callable, Any +from django.http.request import HttpRequest +from datetime import timedelta from av import VideoFrame from PIL import Image @@ -142,7 +146,17 @@ def handle_finished_or_failed_job(rq_job: Job, *args, **kwargs): if os.path.exists(rq_job.meta['tmp_file']): os.remove(rq_job.meta['tmp_file']) -def configure_dependent_job(queue, rq_id, rq_func, db_storage, filename, key, request): +def configure_dependent_job( + queue: DjangoRQ, + rq_id: str, + rq_func: Callable[[Any, str, str], None], + db_storage: Any, + filename: str, + key: str, + request: HttpRequest, + result_ttl: timedelta, + failure_ttl: timedelta +) -> Job: rq_job_id_download_file = rq_id + f'?action=download_{filename}' rq_job_download_file = queue.fetch_job(rq_job_id_download_file) if not rq_job_download_file: @@ -153,6 +167,8 @@ def configure_dependent_job(queue, rq_id, rq_func, db_storage, filename, key, re job_id=rq_job_id_download_file, meta=get_rq_job_meta(request=request, db_obj=db_storage), on_failure=handle_finished_or_failed_job, + result_ttl=result_ttl, + failure_ttl=failure_ttl ) return rq_job_download_file diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index ad267a1b265..c2a0aa5ffa9 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -39,6 +39,7 @@ import cvat.apps.dataset_manager as dm import cvat.apps.dataset_manager.views # pylint: disable=unused-import +from cvat.apps.dataset_manager.views import IMPORT_CACHE_FAILED_TTL, IMPORT_CACHE_SUCCESS_TTL from cvat.apps.engine.cloud_provider import db_storage_to_storage_instance from cvat.apps.dataset_manager.bindings import CvatImportError from cvat.apps.dataset_manager.serializers import DatasetFormatsSerializer @@ -2290,6 +2291,8 @@ def _import_annotations(request, rq_id, rq_func, db_obj, format_name, filename=filename, key=key, request=request, + result_ttl=IMPORT_CACHE_SUCCESS_TTL, + failure_ttl=IMPORT_CACHE_FAILED_TTL ) av_scan_paths(filename) @@ -2303,7 +2306,9 @@ def _import_annotations(request, rq_id, rq_func, db_obj, format_name, depends_on=dependent_job, meta={**meta, **get_rq_job_meta(request=request, db_obj=db_obj)}, on_success=handle_finished_or_failed_job, - on_failure=handle_finished_or_failed_job + on_failure=handle_finished_or_failed_job, + result_ttl=IMPORT_CACHE_SUCCESS_TTL, + failure_ttl=IMPORT_CACHE_FAILED_TTL ) else: if rq_job.is_finished: @@ -2451,7 +2456,7 @@ def _import_project_dataset(request, rq_id, rq_func, db_obj, format_name, filena for chunk in dataset_file.chunks(): f.write(chunk) elif location == Location.CLOUD_STORAGE: - assert filename, 'The filename was not spesified' + assert filename, 'The filename was not specified' try: storage_id = location_conf['storage_id'] except KeyError: @@ -2469,6 +2474,8 @@ def _import_project_dataset(request, rq_id, rq_func, db_obj, format_name, filena filename=filename, key=key, request=request, + result_ttl=IMPORT_CACHE_SUCCESS_TTL, + failure_ttl=IMPORT_CACHE_FAILED_TTL ) rq_job = queue.enqueue_call( @@ -2481,7 +2488,9 @@ def _import_project_dataset(request, rq_id, rq_func, db_obj, format_name, filena }, depends_on=dependent_job, on_success=handle_finished_or_failed_job, - on_failure=handle_finished_or_failed_job + on_failure=handle_finished_or_failed_job, + result_ttl=IMPORT_CACHE_SUCCESS_TTL, + failure_ttl=IMPORT_CACHE_FAILED_TTL ) else: return Response(status=status.HTTP_409_CONFLICT, data='Import job already exists') From 549911bbc2c4dc9cd3421fa6b61a2536dff8d2f3 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 24 Mar 2023 00:27:21 +0100 Subject: [PATCH 04/68] Revert on_success on_failure usage due to their incorrect work --- cvat-core/src/server-proxy.ts | 24 ++++++++--- cvat/apps/dataset_manager/project.py | 6 ++- cvat/apps/dataset_manager/task.py | 8 ++-- cvat/apps/dataset_manager/util.py | 14 +++++++ cvat/apps/engine/backup.py | 24 ++++++++--- cvat/apps/engine/mixins.py | 23 +++++++++-- cvat/apps/engine/utils.py | 5 --- cvat/apps/engine/views.py | 59 +++++++++++++++------------- cvat/settings/base.py | 2 + 9 files changed, 112 insertions(+), 53 deletions(-) diff --git a/cvat-core/src/server-proxy.ts b/cvat-core/src/server-proxy.ts index f75316210aa..65f15aed273 100644 --- a/cvat-core/src/server-proxy.ts +++ b/cvat-core/src/server-proxy.ts @@ -768,15 +768,17 @@ async function importDataset( }; const url = `${backendAPI}/projects/${id}/dataset`; + let rqId: string; async function wait() { return new Promise((resolve, reject) => { async function requestStatus() { try { const response = await Axios.get(url, { - params: { ...params, action: 'import_status' }, + params: { ...params, action: 'import_status', rq_id: rqId }, }); if (response.status === 202) { + rqId = response.data.rq_id; if (response.data.message) { options.updateStatusCallback(response.data.message, response.data.progress || 0); } @@ -797,10 +799,11 @@ async function importDataset( if (isCloudStorage) { try { - await Axios.post(url, + const response = await Axios.post(url, new FormData(), { params, }); + rqId = response.data.rq_id; } catch (errorData) { throw generateError(errorData); } @@ -822,11 +825,12 @@ async function importDataset( headers: { 'Upload-Start': true }, }); await chunkUpload(file, uploadConfig); - await Axios.post(url, + const response = await Axios.post(url, new FormData(), { params, headers: { 'Upload-Finish': true }, }); + rqId = response.data.rq_id; } catch (errorData) { throw generateError(errorData); } @@ -1602,20 +1606,26 @@ async function uploadAnnotations( filename: typeof file === 'string' ? file : file.name, conv_mask_to_poly: options.convMaskToPoly, }; + let rqId: string; const url = `${backendAPI}/${session}s/${id}/annotations`; async function wait() { return new Promise((resolve, reject) => { async function requestStatus() { try { + const data = new FormData(); + if (rqId) { + data.set('rq_id', rqId); + } const response = await Axios.put( url, - new FormData(), + data, { params, }, ); if (response.status === 202) { + rqId = response.data.rq_id; setTimeout(requestStatus, 3000); } else { resolve(); @@ -1631,10 +1641,11 @@ async function uploadAnnotations( if (isCloudStorage) { try { - await Axios.post(url, + const response = await Axios.post(url, new FormData(), { params, }); + rqId = response.data.rq_id; } catch (errorData) { throw generateError(errorData); } @@ -1652,11 +1663,12 @@ async function uploadAnnotations( headers: { 'Upload-Start': true }, }); await chunkUpload(file, uploadConfig); - await Axios.post(url, + const response = await Axios.post(url, new FormData(), { params, headers: { 'Upload-Finish': true }, }); + rqId = response.data.rq_id; } catch (errorData) { throw generateError(errorData); } diff --git a/cvat/apps/dataset_manager/project.py b/cvat/apps/dataset_manager/project.py index e52fb2ebab8..3cde9e2b3cd 100644 --- a/cvat/apps/dataset_manager/project.py +++ b/cvat/apps/dataset_manager/project.py @@ -18,6 +18,7 @@ from .annotation import AnnotationIR from .bindings import ProjectData, load_dataset_data from .formats.registry import make_exporter, make_importer +from .util import remove_resources def export_project(project_id, dst_file, format_name, server_url=None, save_images=False): @@ -160,7 +161,8 @@ def data(self) -> dict: raise NotImplementedError() @transaction.atomic -def import_dataset_as_project(project_id, dataset_file, format_name, conv_mask_to_poly): +@remove_resources +def import_dataset_as_project(src_file, project_id, format_name, conv_mask_to_poly): rq_job = rq.get_current_job() rq_job.meta['status'] = 'Dataset import has been started...' rq_job.meta['progress'] = 0. @@ -170,5 +172,5 @@ def import_dataset_as_project(project_id, dataset_file, format_name, conv_mask_t project.init_from_db() importer = make_importer(format_name) - with open(dataset_file, 'rb') as f: + with open(src_file, 'rb') as f: project.import_dataset(f, importer, conv_mask_to_poly=conv_mask_to_poly) diff --git a/cvat/apps/dataset_manager/task.py b/cvat/apps/dataset_manager/task.py index f85005ff4cd..72b66874907 100644 --- a/cvat/apps/dataset_manager/task.py +++ b/cvat/apps/dataset_manager/task.py @@ -19,7 +19,7 @@ from .annotation import AnnotationIR, AnnotationManager from .bindings import TaskData, JobData from .formats.registry import make_exporter, make_importer -from .util import bulk_create +from .util import bulk_create, remove_resources class dotdict(OrderedDict): @@ -789,7 +789,8 @@ def export_task(task_id, dst_file, format_name, server_url=None, save_images=Fal task.export(f, exporter, host=server_url, save_images=save_images) @transaction.atomic -def import_task_annotations(task_id, src_file, format_name, conv_mask_to_poly): +@remove_resources +def import_task_annotations(src_file, task_id, format_name, conv_mask_to_poly): task = TaskAnnotation(task_id) task.init_from_db() @@ -798,7 +799,8 @@ def import_task_annotations(task_id, src_file, format_name, conv_mask_to_poly): task.import_annotations(f, importer, conv_mask_to_poly=conv_mask_to_poly) @transaction.atomic -def import_job_annotations(job_id, src_file, format_name, conv_mask_to_poly): +@remove_resources +def import_job_annotations(src_file, job_id, format_name, conv_mask_to_poly): job = JobAnnotation(job_id) job.init_from_db() diff --git a/cvat/apps/dataset_manager/util.py b/cvat/apps/dataset_manager/util.py index 8c4a4c7ed8e..739ab135079 100644 --- a/cvat/apps/dataset_manager/util.py +++ b/cvat/apps/dataset_manager/util.py @@ -6,6 +6,8 @@ import inspect import os, os.path as osp import zipfile +import functools +from contextlib import suppress from django.conf import settings @@ -35,3 +37,15 @@ def bulk_create(db_model, objects, flt_param): return db_model.objects.bulk_create(objects) return [] + + +def remove_resources(func): + @functools.wraps(func) + def wrapper(src_file, *args, **kwargs): + try: + func(src_file, *args, **kwargs) + finally: + with suppress(FileNotFoundError): + os.remove(src_file) + return None + return wrapper diff --git a/cvat/apps/engine/backup.py b/cvat/apps/engine/backup.py index 8448a2ec660..ace3cc7ba30 100644 --- a/cvat/apps/engine/backup.py +++ b/cvat/apps/engine/backup.py @@ -9,11 +9,13 @@ import re import shutil import tempfile +import functools from typing import Any, Dict, Iterable import uuid from zipfile import ZipFile from datetime import datetime from tempfile import NamedTemporaryFile +from contextlib import suppress import django_rq from django.conf import settings @@ -36,7 +38,7 @@ LabeledDataSerializer, SegmentSerializer, SimpleJobSerializer, TaskReadSerializer, ProjectReadSerializer, ProjectFileSerializer, TaskFileSerializer) from cvat.apps.engine.utils import ( - av_scan_paths, process_failed_job, configure_dependent_job, get_rq_job_meta, handle_finished_or_failed_job + av_scan_paths, process_failed_job, configure_dependent_job, get_rq_job_meta ) from cvat.apps.engine.models import ( StorageChoice, StorageMethodChoice, DataChoice, Task, Project, Location, @@ -55,6 +57,17 @@ class Version(Enum): IMPORT_CACHE_FAILED_TTL = timedelta(hours=10).total_seconds() IMPORT_CACHE_SUCCESS_TTL = timedelta(hours=1).total_seconds() +def remove_resources(func): + @functools.wraps(func) + def wrapper(filename, *args, **kwargs): + try: + result = func(filename, *args, **kwargs) + finally: + with suppress(FileNotFoundError): + os.remove(filename) + return result + return wrapper + def _get_label_mapping(db_labels): label_mapping = {db_label.id: db_label.name for db_label in db_labels} for db_label in db_labels: @@ -633,6 +646,7 @@ def import_task(self): return self._db_task @transaction.atomic +@remove_resources def _import_task(filename, user, org_id): av_scan_paths(filename) task_importer = TaskImporter(filename, user, org_id) @@ -752,6 +766,7 @@ def import_project(self): return self._db_project @transaction.atomic +@remove_resources def _import_project(filename, user, org_id): av_scan_paths(filename) project_importer = ProjectImporter(filename, user, org_id) @@ -947,15 +962,12 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati **get_rq_job_meta(request=request, db_obj=None) }, depends_on=dependent_job, - on_success=handle_finished_or_failed_job, - on_failure=handle_finished_or_failed_job, result_ttl=IMPORT_CACHE_SUCCESS_TTL, failure_ttl=IMPORT_CACHE_FAILED_TTL ) else: if rq_job.is_finished: project_id = rq_job.return_value() - handle_finished_or_failed_job(rq_job) rq_job.delete() return Response({'id': project_id}, status=status.HTTP_201_CREATED) elif rq_job.is_failed or \ @@ -981,7 +993,7 @@ def import_project(request, queue_name, filename=None): if 'rq_id' in request.data: rq_id = request.data['rq_id'] else: - rq_id = f"import:project.{uuid.uuid4()}-by-{request.user}" + rq_id = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format('project', uuid.uuid4(), 'backup', request.user) Serializer = ProjectFileSerializer file_field_name = 'project_file' @@ -1007,7 +1019,7 @@ def import_task(request, queue_name, filename=None): if 'rq_id' in request.data: rq_id = request.data['rq_id'] else: - rq_id = f"import:task.{uuid.uuid4()}-by-{request.user}" + rq_id = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format('task', uuid.uuid4(), 'backup', request.user) Serializer = TaskFileSerializer file_field_name = 'task_file' diff --git a/cvat/apps/engine/mixins.py b/cvat/apps/engine/mixins.py index 35834323eb3..247f4ad4f9a 100644 --- a/cvat/apps/engine/mixins.py +++ b/cvat/apps/engine/mixins.py @@ -7,6 +7,7 @@ import base64 from unittest import mock import uuid +import django_rq from django.conf import settings from django.core.cache import cache @@ -170,12 +171,26 @@ def init_tus_upload(self, request): if message_id: metadata["message_id"] = base64.b64decode(message_id) - file_exists = os.path.lexists(os.path.join(self.get_upload_dir(), filename)) + file_path = os.path.join(self.get_upload_dir(), filename) + file_exists = os.path.lexists(file_path) + + if file_exists: + # check whether the rw_job is in progress or has been finished/failed + object_class_name = self._object.__class__.__name__.lower() + import_type = request.path.strip('/').split('/')[-1] + if import_type != 'backup': + template = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format(object_class_name, self._object.pk, import_type, request.user) + queue = django_rq.get_queue(settings.CVAT_QUEUES.IMPORT_DATA.value) + finished_job_ids = queue.finished_job_registry.get_job_ids() + failed_job_ids = queue.failed_job_registry.get_job_ids() + if template in finished_job_ids or template in failed_job_ids: + os.remove(file_path) + file_exists = False + if file_exists: return self._tus_response(status=status.HTTP_409_CONFLICT, data="File with same name already exists") - # TODO: check if rq job exists and is active file_size = int(request.META.get("HTTP_UPLOAD_LENGTH", "0")) if file_size > int(self._tus_max_file_size): return self._tus_response(status=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, @@ -283,7 +298,7 @@ def export_annotations(self, request, db_obj, export_func, callback, get_data=No if serializer.is_valid(raise_exception=True): return Response(serializer.data) - def import_annotations(self, request, db_obj, import_func, rq_func, rq_id): + def import_annotations(self, request, db_obj, import_func, rq_func, rq_id_template): is_tus_request = request.headers.get('Upload-Length', None) is not None or \ request.method == 'OPTIONS' if is_tus_request: @@ -305,7 +320,7 @@ def import_annotations(self, request, db_obj, import_func, rq_func, rq_id): return import_func( request=request, - rq_id=rq_id, + rq_id_template=rq_id_template, rq_func=rq_func, db_obj=self._object, format_name=format_name, diff --git a/cvat/apps/engine/utils.py b/cvat/apps/engine/utils.py index 63743c6c03d..dfab982bbae 100644 --- a/cvat/apps/engine/utils.py +++ b/cvat/apps/engine/utils.py @@ -131,7 +131,6 @@ def parse_exception_message(msg): return parsed_msg def process_failed_job(rq_job: Job): - handle_finished_or_failed_job(rq_job) exc_info = str(rq_job.exc_info or rq_job.dependency.exc_info) if rq_job.dependency: rq_job.dependency.delete() @@ -142,9 +141,6 @@ def process_failed_job(rq_job: Job): log.error(msg) return msg -def handle_finished_or_failed_job(rq_job: Job, *args, **kwargs): - if os.path.exists(rq_job.meta['tmp_file']): - os.remove(rq_job.meta['tmp_file']) def configure_dependent_job( queue: DjangoRQ, @@ -166,7 +162,6 @@ def configure_dependent_job( args=(db_storage, filename, key), job_id=rq_job_id_download_file, meta=get_rq_job_meta(request=request, db_obj=db_storage), - on_failure=handle_finished_or_failed_job, result_ttl=result_ttl, failure_ttl=failure_ttl ) diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index c2a0aa5ffa9..0ddf1e639ef 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -65,7 +65,7 @@ from utils.dataset_manifest import ImageManifestManager from cvat.apps.engine.utils import ( - av_scan_paths, process_failed_job, configure_dependent_job, parse_exception_message, get_rq_job_meta, handle_finished_or_failed_job + av_scan_paths, process_failed_job, configure_dependent_job, parse_exception_message, get_rq_job_meta ) from cvat.apps.engine import backup from cvat.apps.engine.mixins import PartialUpdateModelMixin, UploadMixin, AnnotationMixin, SerializeMixin, DestroyModelMixin, CreateModelMixin @@ -235,6 +235,7 @@ class ProjectViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, ordering = "-id" lookup_fields = {'owner': 'owner__username', 'assignee': 'assignee__username'} iam_organization_field = 'organization' + IMPORT_RQ_ID_TEMPLATE = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format('project', {}, 'dataset', {}) def get_serializer_class(self): if self.request.method in SAFE_METHODS: @@ -310,7 +311,6 @@ def perform_create(self, serializer, **kwargs): url_path=r'dataset/?$') def dataset(self, request, pk): self._object = self.get_object() # force call of check_object_permissions() - rq_id = f"import:dataset-for-project.id{pk}-by-{request.user}" if request.method in {'POST', 'OPTIONS'}: return self.import_annotations( @@ -318,17 +318,19 @@ def dataset(self, request, pk): db_obj=self._object, import_func=_import_project_dataset, rq_func=dm.project.import_dataset_as_project, - rq_id=rq_id, + rq_id_template=self.IMPORT_RQ_ID_TEMPLATE ) else: action = request.query_params.get("action", "").lower() if action in ("import_status",): queue = django_rq.get_queue(settings.CVAT_QUEUES.IMPORT_DATA.value) + rq_id = request.query_params.get('rq_id') + if not rq_id: + return Response('The rq_id param should be specified in the query parameters', status=status.HTTP_400_BAD_REQUEST) rq_job = queue.fetch_job(rq_id) if rq_job is None: return Response(status=status.HTTP_404_NOT_FOUND) elif rq_job.is_finished: - handle_finished_or_failed_job(rq_job) if rq_job.dependency: rq_job.dependency.delete() rq_job.delete() @@ -391,7 +393,7 @@ def upload_finished(self, request): return _import_project_dataset( request=request, filename=uploaded_file, - rq_id=f"import:dataset-for-project.id{self._object.pk}-by-{request.user}", + rq_id_template=self.IMPORT_RQ_ID_TEMPLATE, rq_func=dm.project.import_dataset_as_project, db_obj=self._object, format_name=format_name, @@ -700,6 +702,7 @@ class TaskViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, ordering_fields = list(filter_fields) ordering = "-id" iam_organization_field = 'organization' + IMPORT_RQ_ID_TEMPLATE = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format('task', {}, 'annotations', {}) def get_serializer_class(self): if self.request.method in SAFE_METHODS: @@ -819,8 +822,7 @@ def upload_finished(self, request): return _import_annotations( request=request, filename=annotation_file, - rq_id=(f"import:annotations-for-task.id{self._object.pk}-" - f"in-{format_name.replace(' ', '_')}-by-{request.user}"), + rq_id_template=self.IMPORT_RQ_ID_TEMPLATE, rq_func=dm.task.import_task_annotations, db_obj=self._object, format_name=format_name, @@ -1054,7 +1056,7 @@ def annotations(self, request, pk): db_obj=self._object, import_func=_import_annotations, rq_func=dm.task.import_task_annotations, - rq_id = f"import:annotations-for-task.id{pk}-in-{format_name.replace(' ', '_')}-by-{request.user}" + rq_id_template=self.IMPORT_RQ_ID_TEMPLATE ) elif request.method == 'PUT': format_name = request.query_params.get('format', '') @@ -1067,7 +1069,7 @@ def annotations(self, request, pk): ) return _import_annotations( request=request, - rq_id = f"import:annotations-for-task.id{pk}-in-{format_name.replace(' ', '_')}-by-{request.user}", + rq_id_template=self.IMPORT_RQ_ID_TEMPLATE, rq_func=dm.task.import_task_annotations, db_obj=self._object, format_name=format_name, @@ -1300,6 +1302,7 @@ class JobViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, 'project_name': 'segment__task__project__name', 'assignee': 'assignee__username' } + IMPORT_RQ_ID_TEMPLATE = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format('job', {}, 'annotations', {}) def get_queryset(self): queryset = super().get_queryset() @@ -1332,8 +1335,7 @@ def upload_finished(self, request): return _import_annotations( request=request, filename=annotation_file, - rq_id=(f"import:annotations-for-job.id{self._object.pk}-" - f"in-{format_name.replace(' ', '_')}-by-{request.user}"), + rq_id_template=self.IMPORT_RQ_ID_TEMPLATE, rq_func=dm.task.import_job_annotations, db_obj=self._object, format_name=format_name, @@ -1440,13 +1442,13 @@ def annotations(self, request, pk): elif request.method == 'POST' or request.method == 'OPTIONS': format_name = request.query_params.get('format', '') + # TODO: fix return self.import_annotations( request=request, db_obj=self._object.segment.task, import_func=_import_annotations, rq_func=dm.task.import_job_annotations, - rq_id=(f"import:annotations-for-job.id{self._object.pk}-" - f"in-{format_name.replace(' ', '_')}-by-{request.user}"), + rq_id_template=self.IMPORT_RQ_ID_TEMPLATE ) elif request.method == 'PUT': @@ -1460,8 +1462,7 @@ def annotations(self, request, pk): ) return _import_annotations( request=request, - rq_id=(f"import:annotations-for-job.id{pk}-" - f"in-{format_name.replace(' ', '_')}-by-{request.user}"), + rq_id_template=self.IMPORT_RQ_ID_TEMPLATE, rq_func=dm.task.import_job_annotations, db_obj=self._object, format_name=format_name, @@ -2243,7 +2244,7 @@ def _download_file_from_bucket(db_storage, filename, key): with open(filename, 'wb+') as f: f.write(data.getbuffer()) -def _import_annotations(request, rq_id, rq_func, db_obj, format_name, +def _import_annotations(request, rq_id_template, rq_func, db_obj, format_name, filename=None, location_conf=None, conv_mask_to_poly=True): format_desc = {f.DISPLAY_NAME: f for f in dm.views.get_import_formats()}.get(format_name) @@ -2253,6 +2254,8 @@ def _import_annotations(request, rq_id, rq_func, db_obj, format_name, elif not format_desc.ENABLED: return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED) + rq_id = request.data.get('rq_id', rq_id_template.format(db_obj.pk, request.user)) + queue = django_rq.get_queue(settings.CVAT_QUEUES.IMPORT_DATA.value) rq_job = queue.fetch_job(rq_id) @@ -2301,18 +2304,15 @@ def _import_annotations(request, rq_id, rq_func, db_obj, format_name, } rq_job = queue.enqueue_call( func=rq_func, - args=(db_obj.pk, filename, format_name, conv_mask_to_poly), + args=(filename, db_obj.pk, format_name, conv_mask_to_poly), job_id=rq_id, depends_on=dependent_job, meta={**meta, **get_rq_job_meta(request=request, db_obj=db_obj)}, - on_success=handle_finished_or_failed_job, - on_failure=handle_finished_or_failed_job, result_ttl=IMPORT_CACHE_SUCCESS_TTL, failure_ttl=IMPORT_CACHE_FAILED_TTL ) else: if rq_job.is_finished: - handle_finished_or_failed_job(rq_job) rq_job.delete() return Response(status=status.HTTP_201_CREATED) elif rq_job.is_failed or \ @@ -2331,7 +2331,7 @@ def _import_annotations(request, rq_id, rq_func, db_obj, format_name, return Response(data=exc_info, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - return Response(status=status.HTTP_202_ACCEPTED) + return Response({'rq_id': rq_id}, status=status.HTTP_202_ACCEPTED) def _export_annotations(db_instance, rq_id, request, format_name, action, callback, filename, location_conf): @@ -2432,7 +2432,7 @@ def _export_annotations(db_instance, rq_id, request, format_name, action, callba result_ttl=ttl, failure_ttl=ttl) return Response(status=status.HTTP_202_ACCEPTED) -def _import_project_dataset(request, rq_id, rq_func, db_obj, format_name, filename=None, conv_mask_to_poly=True, location_conf=None): +def _import_project_dataset(request, rq_id_template, rq_func, db_obj, format_name, filename=None, conv_mask_to_poly=True, location_conf=None): format_desc = {f.DISPLAY_NAME: f for f in dm.views.get_import_formats()}.get(format_name) if format_desc is None: @@ -2441,10 +2441,17 @@ def _import_project_dataset(request, rq_id, rq_func, db_obj, format_name, filena elif not format_desc.ENABLED: return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED) + rq_id = rq_id_template.format(db_obj.pk, request.user) + queue = django_rq.get_queue(settings.CVAT_QUEUES.IMPORT_DATA.value) rq_job = queue.fetch_job(rq_id) - if not rq_job: + if not rq_job or rq_job.is_finished or rq_job.is_failed: + if rq_job and (rq_job.is_finished or rq_job.is_failed): + # for some reason the previous job has not been deleted + # (e.g the user closed the browser tab when job has been created + # but no one requests for checking status were not made) + rq_job.delete() dependent_job = None location = location_conf.get('location') if location_conf else None if not filename and location != Location.CLOUD_STORAGE: @@ -2480,19 +2487,17 @@ def _import_project_dataset(request, rq_id, rq_func, db_obj, format_name, filena rq_job = queue.enqueue_call( func=rq_func, - args=(db_obj.pk, filename, format_name, conv_mask_to_poly), + args=(filename, db_obj.pk, format_name, conv_mask_to_poly), job_id=rq_id, meta={ 'tmp_file': filename, **get_rq_job_meta(request=request, db_obj=db_obj), }, depends_on=dependent_job, - on_success=handle_finished_or_failed_job, - on_failure=handle_finished_or_failed_job, result_ttl=IMPORT_CACHE_SUCCESS_TTL, failure_ttl=IMPORT_CACHE_FAILED_TTL ) else: return Response(status=status.HTTP_409_CONFLICT, data='Import job already exists') - return Response(status=status.HTTP_202_ACCEPTED) + return Response({'rq_id': rq_id}, status=status.HTTP_202_ACCEPTED) diff --git a/cvat/settings/base.py b/cvat/settings/base.py index 4d1d5611305..558dd043178 100644 --- a/cvat/settings/base.py +++ b/cvat/settings/base.py @@ -338,6 +338,8 @@ class CVAT_QUEUES(Enum): 'cvat.apps.events.handlers.handle_rq_exception', ] +# import:---by- +COMMON_IMPORT_RQ_ID_TEMPLATE="import:{}-{}-{}-by-{}" # JavaScript and CSS compression # https://django-compressor.readthedocs.io From f99512dda779670e2e28532ba4d0c3eab2adff59 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 24 Mar 2023 13:34:11 +0100 Subject: [PATCH 05/68] Fix creating resources from backups with the same names at the same time --- cvat/apps/engine/backup.py | 4 ++++ cvat/apps/engine/mixins.py | 13 +++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/cvat/apps/engine/backup.py b/cvat/apps/engine/backup.py index ace3cc7ba30..1643af6e5a0 100644 --- a/cvat/apps/engine/backup.py +++ b/cvat/apps/engine/backup.py @@ -30,6 +30,7 @@ from django_sendfile import sendfile from distutils.util import strtobool from datetime import timedelta +from pathlib import Path import cvat.apps.dataset_manager as dm from cvat.apps.engine import models @@ -65,6 +66,9 @@ def wrapper(filename, *args, **kwargs): finally: with suppress(FileNotFoundError): os.remove(filename) + tmp_dir = Path(filename).parent + if str(tmp_dir.parent) == get_backup_dirname(): + tmp_dir.rmdir() return result return wrapper diff --git a/cvat/apps/engine/mixins.py b/cvat/apps/engine/mixins.py index 247f4ad4f9a..df8a07d7dc8 100644 --- a/cvat/apps/engine/mixins.py +++ b/cvat/apps/engine/mixins.py @@ -14,6 +14,8 @@ from distutils.util import strtobool from rest_framework import status, mixins from rest_framework.response import Response +from tempfile import mkdtemp +from pathlib import Path from cvat.apps.engine.models import Location from cvat.apps.engine.location import StorageType, get_location_configuration @@ -171,14 +173,20 @@ def init_tus_upload(self, request): if message_id: metadata["message_id"] = base64.b64decode(message_id) + import_type = request.path.strip('/').split('/')[-1] + if import_type == 'backup': + # we need to create unique temp dir here because + # users can try to import backups with the same name at the same time + unique_tmp_dir = Path(mkdtemp(prefix='cvat-', suffix='.backup', dir=self.get_upload_dir())) + filename = os.path.join(unique_tmp_dir.name, filename) + metadata['filename'] = filename file_path = os.path.join(self.get_upload_dir(), filename) file_exists = os.path.lexists(file_path) if file_exists: # check whether the rw_job is in progress or has been finished/failed - object_class_name = self._object.__class__.__name__.lower() - import_type = request.path.strip('/').split('/')[-1] if import_type != 'backup': + object_class_name = self._object.__class__.__name__.lower() template = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format(object_class_name, self._object.pk, import_type, request.user) queue = django_rq.get_queue(settings.CVAT_QUEUES.IMPORT_DATA.value) finished_job_ids = queue.finished_job_registry.get_job_ids() @@ -196,6 +204,7 @@ def init_tus_upload(self, request): return self._tus_response(status=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, data="File size exceeds max limit of {} bytes".format(self._tus_max_file_size)) + tus_file = TusFile.create_file(metadata, file_size, self.get_upload_dir()) location = request.build_absolute_uri() From da4be881f6128eb1d206e082d6f316fdf99e97a3 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 24 Mar 2023 13:53:11 +0100 Subject: [PATCH 06/68] Fix the last problem with uploading annotations --- cvat/apps/engine/views.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 0ddf1e639ef..310507907d4 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -2246,6 +2246,10 @@ def _download_file_from_bucket(db_storage, filename, key): def _import_annotations(request, rq_id_template, rq_func, db_obj, format_name, filename=None, location_conf=None, conv_mask_to_poly=True): + + def _is_there_past_non_deleted_job(): + return rq_job and request.method == 'POST' and (rq_job.is_finished or rq_job.is_failed) + format_desc = {f.DISPLAY_NAME: f for f in dm.views.get_import_formats()}.get(format_name) if format_desc is None: @@ -2259,6 +2263,10 @@ def _import_annotations(request, rq_id_template, rq_func, db_obj, format_name, queue = django_rq.get_queue(settings.CVAT_QUEUES.IMPORT_DATA.value) rq_job = queue.fetch_job(rq_id) + if _is_there_past_non_deleted_job(): + rq_job.delete() + rq_job = queue.fetch_job(rq_id) + if not rq_job: # If filename is specified we consider that file was uploaded via TUS, so it exists in filesystem # Then we dont need to create temporary file From afed207f827c6dab8519113d5c4449e2a7c2d27d Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 24 Mar 2023 14:33:07 +0100 Subject: [PATCH 07/68] [schema] Fix backup import --- cvat/apps/engine/views.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 310507907d4..4f4eb0b3e0b 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -26,7 +26,7 @@ from drf_spectacular.types import OpenApiTypes from drf_spectacular.utils import ( OpenApiParameter, OpenApiResponse, PolymorphicProxySerializer, - extend_schema_view, extend_schema + extend_schema_view, extend_schema, inline_serializer ) from drf_spectacular.plumbing import build_array_type, build_basic_type @@ -61,7 +61,7 @@ UserSerializer, PluginsSerializer, IssueReadSerializer, IssueWriteSerializer, CommentReadSerializer, CommentWriteSerializer, CloudStorageWriteSerializer, CloudStorageReadSerializer, DatasetFileSerializer, - ProjectFileSerializer, TaskFileSerializer) + ProjectFileSerializer, TaskFileSerializer, RqIdSerializer) from utils.dataset_manifest import ImageManifestManager from cvat.apps.engine.utils import ( @@ -497,8 +497,10 @@ def export_backup(self, request, pk=None): resource_type_field_name=None ), responses={ - '201': OpenApiResponse(description='The project has been imported'), # or better specify {id: project_id} - '202': OpenApiResponse(description='Importing a backup file has been started'), + '201': OpenApiResponse(inline_serializer("ImportedProjectIdSerializer", fields={ + "id": serializers.IntegerField(required=True), + }), description='The project has been imported'), + '202': OpenApiResponse(RqIdSerializer, description='Importing a backup file has been started'), }) @action(detail=False, methods=['OPTIONS', 'POST'], url_path=r'backup/?$', serializer_class=ProjectFileSerializer(required=False)) @@ -731,8 +733,10 @@ def get_queryset(self): ], request=TaskFileSerializer(required=False), responses={ - '201': OpenApiResponse(description='The task has been imported'), # or better specify {id: task_id} - '202': OpenApiResponse(description='Importing a backup file has been started'), + '201': OpenApiResponse(inline_serializer("ImportedTaskIdSerializer", fields={ + "id": serializers.IntegerField(required=True), + }), description='The task has been imported'), + '202': OpenApiResponse(RqIdSerializer, description='Importing a backup file has been started'), }) @action(detail=False, methods=['OPTIONS', 'POST'], url_path=r'backup/?$', serializer_class=TaskFileSerializer(required=False)) def import_backup(self, request, pk=None): From 362a1384256a4d84d4b220d425392013190e2469 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 27 Mar 2023 17:15:49 +0200 Subject: [PATCH 08/68] Fix rest api tests && server schema --- cvat-core/src/server-proxy.ts | 10 +---- cvat-sdk/cvat_sdk/core/uploading.py | 13 ++++-- cvat/apps/engine/serializers.py | 3 ++ cvat/apps/engine/views.py | 39 ++++++++++++------ cvat/schema.yml | 32 ++++++++++++++ tests/python/rest_api/test_projects.py | 4 +- .../rest_api/test_resource_import_export.py | 10 +++-- .../shared/assets/cvat_db/cvat_data.tar.bz2 | Bin 116785 -> 293246 bytes tests/python/shared/utils/config.py | 2 + 9 files changed, 86 insertions(+), 27 deletions(-) diff --git a/cvat-core/src/server-proxy.ts b/cvat-core/src/server-proxy.ts index 65f15aed273..10f2f69f636 100644 --- a/cvat-core/src/server-proxy.ts +++ b/cvat-core/src/server-proxy.ts @@ -778,7 +778,6 @@ async function importDataset( params: { ...params, action: 'import_status', rq_id: rqId }, }); if (response.status === 202) { - rqId = response.data.rq_id; if (response.data.message) { options.updateStatusCallback(response.data.message, response.data.progress || 0); } @@ -1613,19 +1612,14 @@ async function uploadAnnotations( return new Promise((resolve, reject) => { async function requestStatus() { try { - const data = new FormData(); - if (rqId) { - data.set('rq_id', rqId); - } const response = await Axios.put( url, - data, + new FormData(), { - params, + params: { ...params, rq_id: rqId }, }, ); if (response.status === 202) { - rqId = response.data.rq_id; setTimeout(requestStatus, 3000); } else { resolve(); diff --git a/cvat-sdk/cvat_sdk/core/uploading.py b/cvat-sdk/cvat_sdk/core/uploading.py index ceacda782ce..be736bc30e5 100644 --- a/cvat-sdk/cvat_sdk/core/uploading.py +++ b/cvat-sdk/cvat_sdk/core/uploading.py @@ -5,6 +5,7 @@ from __future__ import annotations import os +import json from pathlib import Path from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Tuple @@ -89,6 +90,7 @@ def create_url(self): headers["upload-length"] = str(self.file_size) headers["upload-metadata"] = ",".join(self.encode_metadata()) resp = self._api_client.rest_client.POST(self.client.url, headers=headers) + self.metadata['real_filename'] = resp.headers.get('Upload-Filename') url = resp.headers.get("location") if url is None: msg = "Attempt to retrieve create file url with status {}".format(resp.status_code) @@ -179,9 +181,10 @@ def upload_file( assert meta["filename"] self._tus_start_upload(url, query_params=query_params) - self._upload_file_data_with_tus( + metadata = self._upload_file_data_with_tus( url=url, filename=filename, meta=meta, pbar=pbar, logger=logger ) + query_params["filename"] = metadata["real_filename"] return self._tus_finish_upload(url, query_params=query_params, fields=fields) def _wait_for_completion( @@ -233,6 +236,7 @@ def _upload_file_data_with_tus(self, url, filename, *, meta=None, pbar=None, log log_func=logger, ) tus_uploader.upload() + return tus_uploader.metadata def _tus_start_upload(self, url, *, query_params=None): response = self._client.api_client.rest_client.POST( @@ -273,17 +277,20 @@ def upload_file_and_wait( ): url = self._client.api_map.make_endpoint_url(endpoint.path, kwsub=url_params) params = {"format": format_name, "filename": filename.name} - self.upload_file( + response = self.upload_file( url, filename, pbar=pbar, query_params=params, meta={"filename": params["filename"]} ) + rq_id = json.loads(response.data).get('rq_id') + assert rq_id, 'The rq_id was not found in the response' + self._wait_for_completion( url, success_status=201, positive_statuses=[202], status_check_period=status_check_period, query_params=params, - method="POST", + method="PUT", ) diff --git a/cvat/apps/engine/serializers.py b/cvat/apps/engine/serializers.py index 143b3b56eb9..4bcd680dc30 100644 --- a/cvat/apps/engine/serializers.py +++ b/cvat/apps/engine/serializers.py @@ -595,6 +595,9 @@ class RqStatusSerializer(serializers.Serializer): message = serializers.CharField(allow_blank=True, default="") progress = serializers.FloatField(max_value=100, default=0) +class RqIdSerializer(serializers.Serializer): + rq_id = serializers.CharField() + class WriteOnceMixin: """ Adds support for write once fields to serializers. diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 4f4eb0b3e0b..0da3f8a7011 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -275,6 +275,8 @@ def perform_create(self, serializer, **kwargs): OpenApiParameter('use_default_location', description='Use the location that was configured in project to import dataset', location=OpenApiParameter.QUERY, type=OpenApiTypes.BOOL, required=False, default=True), + OpenApiParameter('rq_id', description='rq id', + location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False), ], responses={ '200': OpenApiResponse(OpenApiTypes.BINARY, description='Download of file started'), @@ -303,7 +305,7 @@ def perform_create(self, serializer, **kwargs): resource_type_field_name=None ), responses={ - '202': OpenApiResponse(description='Importing has been started'), + '202': OpenApiResponse(RqIdSerializer, description='Importing has been started'), '400': OpenApiResponse(description='Failed to import dataset'), '405': OpenApiResponse(description='Format is not available'), }) @@ -482,7 +484,7 @@ def annotations(self, request, pk): def export_backup(self, request, pk=None): return self.serialize(request, backup.export) - @extend_schema(summary='Methods create a project from a backup', + @extend_schema(methods=['POST'], summary='Methods create a project from a backup', parameters=[ OpenApiParameter('location', description='Where to import the backup file from', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False, @@ -497,11 +499,17 @@ def export_backup(self, request, pk=None): resource_type_field_name=None ), responses={ - '201': OpenApiResponse(inline_serializer("ImportedProjectIdSerializer", fields={ - "id": serializers.IntegerField(required=True), - }), description='The project has been imported'), + '201': OpenApiResponse(description='The project has been imported'), '202': OpenApiResponse(RqIdSerializer, description='Importing a backup file has been started'), }) + # TODO: for some reason the code generated from schema with different serializers + # contains only one serializer, need to fix that. + # responses={ + # '201': OpenApiResponse(inline_serializer("ImportedProjectIdSerializer", fields={ + # "id": serializers.IntegerField(required=True), + # }), description='The project has been imported'), + # '202': OpenApiResponse(RqIdSerializer, description='Importing a backup file has been started'), + # }) @action(detail=False, methods=['OPTIONS', 'POST'], url_path=r'backup/?$', serializer_class=ProjectFileSerializer(required=False)) def import_backup(self, request, pk=None): @@ -733,11 +741,17 @@ def get_queryset(self): ], request=TaskFileSerializer(required=False), responses={ - '201': OpenApiResponse(inline_serializer("ImportedTaskIdSerializer", fields={ - "id": serializers.IntegerField(required=True), - }), description='The task has been imported'), + '201': OpenApiResponse(description='The task has been imported'), '202': OpenApiResponse(RqIdSerializer, description='Importing a backup file has been started'), }) + # TODO: for some reason the code generated from schema with different serializers + # contains only one serializer, need to fix that. + # responses={ + # '201': OpenApiResponse(inline_serializer("ImportedTaskIdSerializer", fields={ + # "id": serializers.IntegerField(required=True), + # }), description='The project has been imported'), + # '202': OpenApiResponse(RqIdSerializer, description='Importing a backup file has been started'), + # }) @action(detail=False, methods=['OPTIONS', 'POST'], url_path=r'backup/?$', serializer_class=TaskFileSerializer(required=False)) def import_backup(self, request, pk=None): return self.deserialize(request, backup.import_task) @@ -1021,7 +1035,7 @@ def append_data_chunk(self, request, pk, file_id): ), responses={ '201': OpenApiResponse(description='Uploading has finished'), - '202': OpenApiResponse(description='Uploading has been started'), + '202': OpenApiResponse(RqIdSerializer, description='Uploading has been started'), '405': OpenApiResponse(description='Format is not available'), }) @extend_schema(methods=['PATCH'], summary='Method performs a partial update of annotations in a specific task', @@ -1400,7 +1414,7 @@ def upload_finished(self, request): request=AnnotationFileSerializer, responses={ '201': OpenApiResponse(description='Uploading has finished'), - '202': OpenApiResponse(description='Uploading has been started'), + '202': OpenApiResponse(RqIdSerializer, description='Uploading has been started'), '405': OpenApiResponse(description='Format is not available'), }) @extend_schema(methods=['PUT'], summary='Method performs an update of all annotations in a specific job', @@ -2262,7 +2276,7 @@ def _is_there_past_non_deleted_job(): elif not format_desc.ENABLED: return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED) - rq_id = request.data.get('rq_id', rq_id_template.format(db_obj.pk, request.user)) + rq_id = request.query_params.get('rq_id', rq_id_template.format(db_obj.pk, request.user)) queue = django_rq.get_queue(settings.CVAT_QUEUES.IMPORT_DATA.value) rq_job = queue.fetch_job(rq_id) @@ -2323,6 +2337,7 @@ def _is_there_past_non_deleted_job(): result_ttl=IMPORT_CACHE_SUCCESS_TTL, failure_ttl=IMPORT_CACHE_FAILED_TTL ) + return Response({'rq_id': rq_id}, status=status.HTTP_202_ACCEPTED) else: if rq_job.is_finished: rq_job.delete() @@ -2343,7 +2358,7 @@ def _is_there_past_non_deleted_job(): return Response(data=exc_info, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - return Response({'rq_id': rq_id}, status=status.HTTP_202_ACCEPTED) + return Response(status=status.HTTP_202_ACCEPTED) def _export_annotations(db_instance, rq_id, request, format_name, action, callback, filename, location_conf): diff --git a/cvat/schema.yml b/cvat/schema.yml index dbdc1c11f08..598f0bbb91e 100644 --- a/cvat/schema.yml +++ b/cvat/schema.yml @@ -2233,6 +2233,10 @@ paths: '201': description: Uploading has finished '202': + content: + application/vnd.cvat+json: + schema: + $ref: '#/components/schemas/RqId' description: Uploading has been started '405': description: Format is not available @@ -4154,6 +4158,11 @@ paths: schema: type: integer description: Organization identifier + - in: query + name: rq_id + schema: + type: string + description: rq id - in: query name: use_default_location schema: @@ -4263,6 +4272,10 @@ paths: - basicAuth: [] responses: '202': + content: + application/vnd.cvat+json: + schema: + $ref: '#/components/schemas/RqId' description: Importing has been started '400': description: Failed to import dataset @@ -4428,6 +4441,10 @@ paths: '201': description: The project has been imported '202': + content: + application/vnd.cvat+json: + schema: + $ref: '#/components/schemas/RqId' description: Importing a backup file has been started /api/projects/backup/{file_id}: patch: @@ -5260,6 +5277,10 @@ paths: '201': description: Uploading has finished '202': + content: + application/vnd.cvat+json: + schema: + $ref: '#/components/schemas/RqId' description: Uploading has been started '405': description: Format is not available @@ -6065,6 +6086,10 @@ paths: '201': description: The task has been imported '202': + content: + application/vnd.cvat+json: + schema: + $ref: '#/components/schemas/RqId' description: Importing a backup file has been started /api/tasks/backup/{file_id}: patch: @@ -9138,6 +9163,13 @@ components: - maintainer - owner type: string + RqId: + type: object + properties: + rq_id: + type: string + required: + - rq_id RqStatus: type: object properties: diff --git a/tests/python/rest_api/test_projects.py b/tests/python/rest_api/test_projects.py index c899d276495..fcfa40f4807 100644 --- a/tests/python/rest_api/test_projects.py +++ b/tests/python/rest_api/test_projects.py @@ -461,11 +461,13 @@ def _test_import_project(self, username, project_id, format_name, data): _content_type="multipart/form-data", ) assert response.status == HTTPStatus.ACCEPTED + rq_id = json.loads(response.data).get('rq_id') + assert rq_id, 'The rq_id was not found in the response' while True: # TODO: It's better be refactored to a separate endpoint to get request status (_, response) = api_client.projects_api.retrieve_dataset( - project_id, action="import_status" + project_id, action="import_status", rq_id=rq_id ) if response.status == HTTPStatus.CREATED: break diff --git a/tests/python/rest_api/test_resource_import_export.py b/tests/python/rest_api/test_resource_import_export.py index 6ebbf803f26..ec2ffd650b0 100644 --- a/tests/python/rest_api/test_resource_import_export.py +++ b/tests/python/rest_api/test_resource_import_export.py @@ -11,7 +11,7 @@ import pytest -from shared.utils.config import get_method, post_method +from shared.utils.config import get_method, post_method, put_method from shared.utils.s3 import make_client T = TypeVar("T") @@ -86,10 +86,12 @@ def _import_annotations_from_cloud_storage(self, obj_id, obj, *, user, **kwargs) url = f"{obj}/{obj_id}/annotations" response = post_method(user, url, data=None, **kwargs) status = response.status_code + rq_id = response.json().get('rq_id') + assert rq_id, 'The rq_id was not found in the response' while status != HTTPStatus.CREATED: assert status == HTTPStatus.ACCEPTED - response = post_method(user, url, data=None, **kwargs) + response = put_method(user, url, data=None, rq_id=rq_id, **kwargs) status = response.status_code def _import_backup_from_cloud_storage(self, obj_id, obj, *, user, **kwargs): @@ -107,10 +109,12 @@ def _import_dataset_from_cloud_storage(self, obj_id, obj, *, user, **kwargs): url = f"{obj}/{obj_id}/dataset" response = post_method(user, url, data=None, **kwargs) status = response.status_code + rq_id = response.json().get('rq_id') + assert rq_id, 'The rq_id was not found in the response' while status != HTTPStatus.CREATED: assert status == HTTPStatus.ACCEPTED - response = get_method(user, url, action="import_status") + response = get_method(user, url, action="import_status", rq_id=rq_id) status = response.status_code def _export_resource(self, cloud_storage: Dict[str, Any], *args, **kwargs): diff --git a/tests/python/shared/assets/cvat_db/cvat_data.tar.bz2 b/tests/python/shared/assets/cvat_db/cvat_data.tar.bz2 index 0d0748fcb659dcfaaee16d2186f13a3b5050040d..dbb61088b30c0c9092c4c8f4284f45cac0fdccf4 100644 GIT binary patch literal 293246 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%0A`q^2RFvE%4<(MKAV`$;QYh+; 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 Date: Mon, 27 Mar 2023 17:38:19 +0200 Subject: [PATCH 09/68] Fix linters --- cvat-sdk/cvat_sdk/core/uploading.py | 2 +- cvat/apps/engine/views.py | 2 +- tests/python/rest_api/test_projects.py | 4 ++-- tests/python/rest_api/test_resource_import_export.py | 8 ++++---- tests/python/shared/utils/config.py | 2 ++ 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cvat-sdk/cvat_sdk/core/uploading.py b/cvat-sdk/cvat_sdk/core/uploading.py index be736bc30e5..1ff4234478d 100644 --- a/cvat-sdk/cvat_sdk/core/uploading.py +++ b/cvat-sdk/cvat_sdk/core/uploading.py @@ -4,8 +4,8 @@ from __future__ import annotations -import os import json +import os from pathlib import Path from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Tuple diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 0da3f8a7011..7126d5fb25c 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -26,7 +26,7 @@ from drf_spectacular.types import OpenApiTypes from drf_spectacular.utils import ( OpenApiParameter, OpenApiResponse, PolymorphicProxySerializer, - extend_schema_view, extend_schema, inline_serializer + extend_schema_view, extend_schema ) from drf_spectacular.plumbing import build_array_type, build_basic_type diff --git a/tests/python/rest_api/test_projects.py b/tests/python/rest_api/test_projects.py index fcfa40f4807..dd2887ffad5 100644 --- a/tests/python/rest_api/test_projects.py +++ b/tests/python/rest_api/test_projects.py @@ -461,8 +461,8 @@ def _test_import_project(self, username, project_id, format_name, data): _content_type="multipart/form-data", ) assert response.status == HTTPStatus.ACCEPTED - rq_id = json.loads(response.data).get('rq_id') - assert rq_id, 'The rq_id was not found in the response' + rq_id = json.loads(response.data).get("rq_id") + assert rq_id, "The rq_id was not found in the response" while True: # TODO: It's better be refactored to a separate endpoint to get request status diff --git a/tests/python/rest_api/test_resource_import_export.py b/tests/python/rest_api/test_resource_import_export.py index ec2ffd650b0..ae03bf8105f 100644 --- a/tests/python/rest_api/test_resource_import_export.py +++ b/tests/python/rest_api/test_resource_import_export.py @@ -86,8 +86,8 @@ def _import_annotations_from_cloud_storage(self, obj_id, obj, *, user, **kwargs) url = f"{obj}/{obj_id}/annotations" response = post_method(user, url, data=None, **kwargs) status = response.status_code - rq_id = response.json().get('rq_id') - assert rq_id, 'The rq_id was not found in the response' + rq_id = response.json().get("rq_id") + assert rq_id, "The rq_id was not found in the response" while status != HTTPStatus.CREATED: assert status == HTTPStatus.ACCEPTED @@ -109,8 +109,8 @@ def _import_dataset_from_cloud_storage(self, obj_id, obj, *, user, **kwargs): url = f"{obj}/{obj_id}/dataset" response = post_method(user, url, data=None, **kwargs) status = response.status_code - rq_id = response.json().get('rq_id') - assert rq_id, 'The rq_id was not found in the response' + rq_id = response.json().get("rq_id") + assert rq_id, "The rq_id was not found in the response" while status != HTTPStatus.CREATED: assert status == HTTPStatus.ACCEPTED diff --git a/tests/python/shared/utils/config.py b/tests/python/shared/utils/config.py index 0b02f52e27c..066400371da 100644 --- a/tests/python/shared/utils/config.py +++ b/tests/python/shared/utils/config.py @@ -51,9 +51,11 @@ def patch_method(username, endpoint, data, **kwargs): def post_method(username, endpoint, data, **kwargs): return requests.post(get_api_url(endpoint, **kwargs), json=data, auth=(username, USER_PASS)) + def put_method(username, endpoint, data, **kwargs): return requests.put(get_api_url(endpoint, **kwargs), json=data, auth=(username, USER_PASS)) + def post_files_method(username, endpoint, data, files, **kwargs): return requests.post( get_api_url(endpoint, **kwargs), data=data, files=files, auth=(username, USER_PASS) From 7cc12d3df644a2f390c77399d0cb9c4f79799e27 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 27 Mar 2023 17:39:50 +0200 Subject: [PATCH 10/68] Revert used djnago-rq/rq versions --- cvat/apps/engine/backup.py | 4 ++-- cvat/apps/engine/views.py | 2 +- cvat/apps/events/export.py | 2 +- cvat/requirements/base.txt | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cvat/apps/engine/backup.py b/cvat/apps/engine/backup.py index 1643af6e5a0..3c01a2377b2 100644 --- a/cvat/apps/engine/backup.py +++ b/cvat/apps/engine/backup.py @@ -855,7 +855,7 @@ def export(db_instance, request, queue_name): rq_job.delete() else: if rq_job.is_finished: - file_path = rq_job.return_value() + file_path = rq_job.return_value if action == "download" and os.path.exists(file_path): rq_job.delete() @@ -971,7 +971,7 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati ) else: if rq_job.is_finished: - project_id = rq_job.return_value() + project_id = rq_job.return_value rq_job.delete() return Response({'id': project_id}, status=status.HTTP_201_CREATED) elif rq_job.is_failed or \ diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 7126d5fb25c..596f6233f29 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -2389,7 +2389,7 @@ def _export_annotations(db_instance, rq_id, request, format_name, action, callba rq_job.delete() else: if rq_job.is_finished: - file_path = rq_job.return_value() + file_path = rq_job.return_value if action == "download" and osp.exists(file_path): rq_job.delete() diff --git a/cvat/apps/events/export.py b/cvat/apps/events/export.py index f40e609fc7f..3030413590d 100644 --- a/cvat/apps/events/export.py +++ b/cvat/apps/events/export.py @@ -136,7 +136,7 @@ def export(request, filter_query, queue_name): if rq_job: if rq_job.is_finished: - file_path = rq_job.return_value() + file_path = rq_job.return_value if action == "download" and os.path.exists(file_path): rq_job.delete() timestamp = datetime.strftime(datetime.now(), "%Y_%m_%d_%H_%M_%S") diff --git a/cvat/requirements/base.txt b/cvat/requirements/base.txt index 994abe9d0bb..e1a3cf2f500 100644 --- a/cvat/requirements/base.txt +++ b/cvat/requirements/base.txt @@ -11,7 +11,7 @@ django-compressor==2.4 # https://dj-rest-auth.readthedocs.io/en/latest/installation.html#registration-optional django-allauth>=0.52.0 dj-rest-auth[with_social]==2.2.7 -django-rq==2.7.0 +django-rq==2.3.2 EasyProcess==0.3 Pillow==9.3.0 numpy==1.22.0 @@ -22,7 +22,7 @@ rcssmin==1.0.6 redis==3.5.3 rjsmin==1.1.0 requests==2.26.0 -rq==1.13.0 +rq==1.5.2 rq-scheduler==0.10.0 sqlparse==0.4.2 django-sendfile2==0.7.0 From c8f808eabd0b2e55887fe0e680b98805d552cc75 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 27 Mar 2023 19:18:00 +0200 Subject: [PATCH 11/68] Fix server tests --- cvat/apps/dataset_manager/tests/test_formats.py | 6 +++--- cvat/apps/dataset_manager/util.py | 7 ++++--- cvat/apps/engine/tests/test_rest_api.py | 7 ++++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/cvat/apps/dataset_manager/tests/test_formats.py b/cvat/apps/dataset_manager/tests/test_formats.py index 86ef91efc85..bf80011b4cf 100644 --- a/cvat/apps/dataset_manager/tests/test_formats.py +++ b/cvat/apps/dataset_manager/tests/test_formats.py @@ -923,8 +923,8 @@ def _test_can_import_annotations(self, task, import_format): expected_ann = TaskAnnotation(task["id"]) expected_ann.init_from_db() - dm.task.import_task_annotations(task["id"], - file_path, import_format, True) + dm.util.remove_resources(dm.task.import_task_annotations, should_be_deleted=False)(file_path, task["id"], + import_format, True) actual_ann = TaskAnnotation(task["id"]) actual_ann.init_from_db() @@ -976,6 +976,6 @@ def test_can_import_mots_annotations_with_splited_masks(self): task.update() task = self._create_task(task, images) - dm.task.import_task_annotations(task['id'], dataset_path, format_name, True) + dm.util.remove_resources(dm.task.import_task_annotations, should_be_deleted=False)(dataset_path, task['id'], format_name, True) self._test_can_import_annotations(task, format_name) diff --git a/cvat/apps/dataset_manager/util.py b/cvat/apps/dataset_manager/util.py index 739ab135079..0253722097f 100644 --- a/cvat/apps/dataset_manager/util.py +++ b/cvat/apps/dataset_manager/util.py @@ -39,13 +39,14 @@ def bulk_create(db_model, objects, flt_param): return [] -def remove_resources(func): +def remove_resources(func, should_be_deleted=True): @functools.wraps(func) def wrapper(src_file, *args, **kwargs): try: func(src_file, *args, **kwargs) finally: - with suppress(FileNotFoundError): - os.remove(src_file) + if should_be_deleted: + with suppress(FileNotFoundError): + os.remove(src_file) return None return wrapper diff --git a/cvat/apps/engine/tests/test_rest_api.py b/cvat/apps/engine/tests/test_rest_api.py index 00d6d0d48e9..3587bf1ce61 100644 --- a/cvat/apps/engine/tests/test_rest_api.py +++ b/cvat/apps/engine/tests/test_rest_api.py @@ -1880,9 +1880,9 @@ def _run_api_v2_projects_id_dataset_import(self, pid, user, data, f): response = self.client.post("/api/projects/{}/dataset?format={}".format(pid, f), data=data, format="multipart") return response - def _run_api_v2_projects_id_dataset_import_status(self, pid, user): + def _run_api_v2_projects_id_dataset_import_status(self, pid, user, rq_id): with ForceLogin(user, self.client): - response = self.client.get("/api/projects/{}/dataset?action=import_status".format(pid), format="json") + response = self.client.get("/api/projects/{}/dataset?action=import_status&rq_id={}".format(pid, rq_id), format="json") return response def test_api_v2_projects_id_export_import(self): @@ -1911,7 +1911,8 @@ def test_api_v2_projects_id_export_import(self): response = self._run_api_v2_projects_id_dataset_import(pid_import, self.owner, import_data, "CVAT 1.1") self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED) - response = self._run_api_v2_projects_id_dataset_import_status(pid_import, self.owner) + rq_id = response.data.get('rq_id') + response = self._run_api_v2_projects_id_dataset_import_status(pid_import, self.owner, rq_id) self.assertEqual(response.status_code, status.HTTP_201_CREATED) def tearDown(self) -> None: From 29106ae8525029fbc2ff91ff07db5588635398f0 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 27 Mar 2023 19:19:16 +0200 Subject: [PATCH 12/68] Fix method --- cvat/apps/engine/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 596f6233f29..e90dc72650a 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -2251,7 +2251,7 @@ def actions(self, request, pk): def rq_exception_handler(rq_job, exc_type, exc_value, tb): rq_job.meta["formatted_exception"] = "".join( traceback.format_exception_only(exc_type, exc_value)) - rq_job.save() + rq_job.save_meta() return True From 6307318a2835fd1760d3c746981a59e8730d6f39 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 27 Mar 2023 19:21:13 +0200 Subject: [PATCH 13/68] Fix black issue --- cvat-sdk/cvat_sdk/core/uploading.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cvat-sdk/cvat_sdk/core/uploading.py b/cvat-sdk/cvat_sdk/core/uploading.py index 1ff4234478d..6ed1b9c657a 100644 --- a/cvat-sdk/cvat_sdk/core/uploading.py +++ b/cvat-sdk/cvat_sdk/core/uploading.py @@ -90,7 +90,7 @@ def create_url(self): headers["upload-length"] = str(self.file_size) headers["upload-metadata"] = ",".join(self.encode_metadata()) resp = self._api_client.rest_client.POST(self.client.url, headers=headers) - self.metadata['real_filename'] = resp.headers.get('Upload-Filename') + self.metadata["real_filename"] = resp.headers.get("Upload-Filename") url = resp.headers.get("location") if url is None: msg = "Attempt to retrieve create file url with status {}".format(resp.status_code) @@ -281,8 +281,8 @@ def upload_file_and_wait( url, filename, pbar=pbar, query_params=params, meta={"filename": params["filename"]} ) - rq_id = json.loads(response.data).get('rq_id') - assert rq_id, 'The rq_id was not found in the response' + rq_id = json.loads(response.data).get("rq_id") + assert rq_id, "The rq_id was not found in the response" self._wait_for_completion( url, From 7f44abaa007454aaaf2866ca200e554ce976ea94 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 27 Mar 2023 22:28:00 +0200 Subject: [PATCH 14/68] Update DatasetUploader --- cvat-sdk/cvat_sdk/core/uploading.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cvat-sdk/cvat_sdk/core/uploading.py b/cvat-sdk/cvat_sdk/core/uploading.py index 6ed1b9c657a..b11630b8643 100644 --- a/cvat-sdk/cvat_sdk/core/uploading.py +++ b/cvat-sdk/cvat_sdk/core/uploading.py @@ -308,12 +308,17 @@ def upload_file_and_wait( ): url = self._client.api_map.make_endpoint_url(upload_endpoint.path, kwsub=url_params) params = {"format": format_name, "filename": filename.name} - self.upload_file( + response = self.upload_file( url, filename, pbar=pbar, query_params=params, meta={"filename": params["filename"]} ) + rq_id = json.loads(response.data).get("rq_id") + assert rq_id, "The rq_id was not found in the response" url = self._client.api_map.make_endpoint_url(retrieve_endpoint.path, kwsub=url_params) - params = {"action": "import_status"} + params = { + "action": "import_status", + "rq_id": rq_id, + } self._wait_for_completion( url, success_status=201, From c4848a01fbf3b4d50b0ff59c8c31133bf734bb2a Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Tue, 28 Mar 2023 00:41:55 +0200 Subject: [PATCH 15/68] Add test for import task annotations --- cvat-sdk/cvat_sdk/core/proxies/tasks.py | 2 +- tests/python/rest_api/test_tasks.py | 57 +++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/cvat-sdk/cvat_sdk/core/proxies/tasks.py b/cvat-sdk/cvat_sdk/core/proxies/tasks.py index 30c4cd8de15..ab4f2d4f31d 100644 --- a/cvat-sdk/cvat_sdk/core/proxies/tasks.py +++ b/cvat-sdk/cvat_sdk/core/proxies/tasks.py @@ -449,6 +449,6 @@ def create_from_backup( ) task_id = json.loads(response.data)["id"] - self._client.logger.info(f"Task has been imported sucessfully. Task ID: {task_id}") + self._client.logger.info(f"Task has been imported successfully. Task ID: {task_id}") return self.retrieve(task_id) diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index ba52a5dfb11..cedd5dc3134 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -13,6 +13,7 @@ from itertools import chain, product from pathlib import Path from tempfile import TemporaryDirectory +from time import sleep from typing import List import pytest @@ -21,6 +22,7 @@ from cvat_sdk.api_client.api_client import ApiClient, Endpoint from cvat_sdk.core.helpers import get_paginated_collection from cvat_sdk.core.proxies.tasks import ResourceType, Task +from cvat_sdk.core.uploading import Uploader from deepdiff import DeepDiff from PIL import Image @@ -1378,3 +1380,58 @@ def test_move_task_from_one_project_to_another_with_attributes(self, task_id, pr ) == {} ) + + +class TestImportTaskAnnotations: + def _make_client(self) -> Client: + return Client(BASE_URL) + + @pytest.fixture(autouse=True) + def setup(self, restore_db_per_function, tmp_path: Path, admin_user: str): + self.tmp_dir = tmp_path + self.client = self._make_client() + self.user = admin_user + self.format = "COCO 1.0" + + with self.client: + self.client.login((self.user, USER_PASS)) + + def _check_annotations(self, task_id): + with make_api_client(self.user) as api_client: + (_, response) = api_client.tasks_api.retrieve_annotations(id=task_id) + assert response.status == HTTPStatus.OK + annotations = json.loads(response.data)["shapes"] + assert len(annotations) > 0 + + def _delete_annotations(self, task_id): + with make_api_client(self.user) as api_client: + (_, response) = api_client.tasks_api.destroy_annotations(id=task_id) + assert response.status == HTTPStatus.NO_CONTENT + + @pytest.mark.parametrize("task_id", [20]) + def test_can_import_annotations_after_previous_unclear_import(self, task_id): + self._check_annotations(task_id) + + filename = self.tmp_dir / f"task_{task_id}_coco.zip" + task = self.client.tasks.retrieve(task_id) + task.export_dataset(self.format, filename) + + self._delete_annotations(task_id) + + params = {"format": self.format, "filename": filename.name} + url = self.client.api_map.make_endpoint_url( + self.client.api_client.tasks_api.create_annotations_endpoint.path + ).format(id=task_id) + uploader = Uploader(self.client) + + response = uploader.upload_file( + url, filename, meta=params, query_params=params, logger=self.client.logger.debug + ) + + rq_id = json.loads(response.data)["rq_id"] + assert rq_id + sleep(3) + self._check_annotations(task_id) + self._delete_annotations(task_id) + task.import_annotations(self.format, filename) + self._check_annotations(task_id) From 5e196e475fe8ca6a1609041b12b90d968f21e7cf Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Tue, 28 Mar 2023 10:26:54 +0200 Subject: [PATCH 16/68] Fix typo --- tests/python/sdk/test_tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/sdk/test_tasks.py b/tests/python/sdk/test_tasks.py index 3a8faeddef4..59069a4f80c 100644 --- a/tests/python/sdk/test_tasks.py +++ b/tests/python/sdk/test_tasks.py @@ -367,7 +367,7 @@ def _test_can_create_from_backup(self, fxt_new_task: Task, fxt_backup_file: Path assert task.id assert task.id != fxt_new_task.id assert task.size == fxt_new_task.size - assert "imported sucessfully" in self.logger_stream.getvalue() + assert "imported successfully" in self.logger_stream.getvalue() assert "100%" in pbar_out.getvalue().strip("\r").split("\r")[-1] assert self.stdout.getvalue() == "" From 1c8bde84a25af97d97c7dda85fa2874aa09005c6 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Tue, 28 Mar 2023 10:57:05 +0200 Subject: [PATCH 17/68] Fix import job annotations from CS --- cvat/apps/engine/location.py | 4 ++-- cvat/apps/engine/views.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cvat/apps/engine/location.py b/cvat/apps/engine/location.py index fd3fadf01e4..0466b3a948b 100644 --- a/cvat/apps/engine/location.py +++ b/cvat/apps/engine/location.py @@ -1,6 +1,6 @@ from enum import Enum -from cvat.apps.engine.models import Location +from cvat.apps.engine.models import Location, Job class StorageType(str, Enum): TARGET = 'target_storage' @@ -12,7 +12,7 @@ def __str__(self): def get_location_configuration(obj, field_name, use_settings=False): location_conf = dict() if use_settings: - storage = getattr(obj, field_name) + storage = getattr(obj, field_name) if not isinstance(obj, Job) else getattr(obj.segment.task, field_name) if storage is None: location_conf['location'] = Location.LOCAL else: diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index e90dc72650a..a5fd0a5fa70 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -1460,10 +1460,9 @@ def annotations(self, request, pk): elif request.method == 'POST' or request.method == 'OPTIONS': format_name = request.query_params.get('format', '') - # TODO: fix return self.import_annotations( request=request, - db_obj=self._object.segment.task, + db_obj=self._object, import_func=_import_annotations, rq_func=dm.task.import_job_annotations, rq_id_template=self.IMPORT_RQ_ID_TEMPLATE From a62a4e196fd353613ef6398853aa70ebe8bb1918 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Tue, 28 Mar 2023 14:21:51 +0200 Subject: [PATCH 18/68] Fix test --- tests/python/rest_api/test_tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index cedd5dc3134..115017f62b7 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -1384,7 +1384,7 @@ def test_move_task_from_one_project_to_another_with_attributes(self, task_id, pr class TestImportTaskAnnotations: def _make_client(self) -> Client: - return Client(BASE_URL) + return Client(BASE_URL, config=Config(status_check_period=0.01)) @pytest.fixture(autouse=True) def setup(self, restore_db_per_function, tmp_path: Path, admin_user: str): From da08dfde8236395a0ba3330d0abe0011c88ec092 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 31 Mar 2023 20:04:09 +0200 Subject: [PATCH 19/68] Update cvat/apps/engine/mixins.py Co-authored-by: Roman Donchenko --- cvat/apps/engine/mixins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat/apps/engine/mixins.py b/cvat/apps/engine/mixins.py index df8a07d7dc8..e449b0132e6 100644 --- a/cvat/apps/engine/mixins.py +++ b/cvat/apps/engine/mixins.py @@ -184,7 +184,7 @@ def init_tus_upload(self, request): file_exists = os.path.lexists(file_path) if file_exists: - # check whether the rw_job is in progress or has been finished/failed + # check whether the rq_job is in progress or has been finished/failed if import_type != 'backup': object_class_name = self._object.__class__.__name__.lower() template = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format(object_class_name, self._object.pk, import_type, request.user) From 3d10ae9392a89e7903194ea60e6e0b1ca7502dbe Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Tue, 9 May 2023 22:59:46 +0200 Subject: [PATCH 20/68] Move method --- tests/python/shared/utils/config.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/python/shared/utils/config.py b/tests/python/shared/utils/config.py index 066400371da..0e9669fce5d 100644 --- a/tests/python/shared/utils/config.py +++ b/tests/python/shared/utils/config.py @@ -52,16 +52,16 @@ def post_method(username, endpoint, data, **kwargs): return requests.post(get_api_url(endpoint, **kwargs), json=data, auth=(username, USER_PASS)) -def put_method(username, endpoint, data, **kwargs): - return requests.put(get_api_url(endpoint, **kwargs), json=data, auth=(username, USER_PASS)) - - def post_files_method(username, endpoint, data, files, **kwargs): return requests.post( get_api_url(endpoint, **kwargs), data=data, files=files, auth=(username, USER_PASS) ) +def put_method(username, endpoint, data, **kwargs): + return requests.put(get_api_url(endpoint, **kwargs), json=data, auth=(username, USER_PASS)) + + def server_get(username, endpoint, **kwargs): return requests.get(get_server_url(endpoint, **kwargs), auth=(username, USER_PASS)) From 1521b19e06235e7d9c915f0764f7de9be837cd72 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Tue, 9 May 2023 23:07:18 +0200 Subject: [PATCH 21/68] COMMON_IMPORT_RQ_ID_TEMPLATE -> get_import_rq_id --- cvat/apps/engine/backup.py | 6 +++--- cvat/apps/engine/mixins.py | 3 ++- cvat/apps/engine/utils.py | 5 +++++ cvat/apps/engine/views.py | 8 ++++---- cvat/settings/base.py | 3 --- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/cvat/apps/engine/backup.py b/cvat/apps/engine/backup.py index 2429b4559e1..98654ebf0fc 100644 --- a/cvat/apps/engine/backup.py +++ b/cvat/apps/engine/backup.py @@ -39,7 +39,7 @@ LabeledDataSerializer, SegmentSerializer, SimpleJobSerializer, TaskReadSerializer, ProjectReadSerializer, ProjectFileSerializer, TaskFileSerializer) from cvat.apps.engine.utils import ( - av_scan_paths, process_failed_job, configure_dependent_job, get_rq_job_meta + av_scan_paths, process_failed_job, configure_dependent_job, get_rq_job_meta, get_import_rq_id ) from cvat.apps.engine.models import ( StorageChoice, StorageMethodChoice, DataChoice, Task, Project, Location) @@ -1003,7 +1003,7 @@ def import_project(request, queue_name, filename=None): if 'rq_id' in request.data: rq_id = request.data['rq_id'] else: - rq_id = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format('project', uuid.uuid4(), 'backup', request.user) + rq_id = get_import_rq_id('project', uuid.uuid4(), 'backup', request.user) Serializer = ProjectFileSerializer file_field_name = 'project_file' @@ -1029,7 +1029,7 @@ def import_task(request, queue_name, filename=None): if 'rq_id' in request.data: rq_id = request.data['rq_id'] else: - rq_id = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format('task', uuid.uuid4(), 'backup', request.user) + rq_id = get_import_rq_id('task', uuid.uuid4(), 'backup', request.user) Serializer = TaskFileSerializer file_field_name = 'task_file' diff --git a/cvat/apps/engine/mixins.py b/cvat/apps/engine/mixins.py index 28fadfa6533..b60f85f93a0 100644 --- a/cvat/apps/engine/mixins.py +++ b/cvat/apps/engine/mixins.py @@ -21,6 +21,7 @@ from cvat.apps.engine.location import StorageType, get_location_configuration from cvat.apps.engine.models import Location from cvat.apps.engine.serializers import DataSerializer +from cvat.apps.engine.utils import get_import_rq_id class TusFile: @@ -238,7 +239,7 @@ def init_tus_upload(self, request): # check whether the rq_job is in progress or has been finished/failed if import_type != 'backup': object_class_name = self._object.__class__.__name__.lower() - template = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format(object_class_name, self._object.pk, import_type, request.user) + template = get_import_rq_id(object_class_name, self._object.pk, import_type, request.user) queue = django_rq.get_queue(settings.CVAT_QUEUES.IMPORT_DATA.value) finished_job_ids = queue.finished_job_registry.get_job_ids() failed_job_ids = queue.failed_job_registry.get_job_ids() diff --git a/cvat/apps/engine/utils.py b/cvat/apps/engine/utils.py index ca6e9236f6a..a2687aa33aa 100644 --- a/cvat/apps/engine/utils.py +++ b/cvat/apps/engine/utils.py @@ -231,3 +231,8 @@ def get_list_view_name(model): return '%(model_name)s-list' % { 'model_name': model._meta.object_name.lower() } + + +def get_import_rq_id(resource_type: str, resource_id: int, subresource_type: str, user: str) -> str: + # import:---by- + return f"import:{resource_type}-{resource_id}-{subresource_type}-by-{user}" diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index bf92c6b77ee..6845f233915 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -67,7 +67,7 @@ from utils.dataset_manifest import ImageManifestManager from cvat.apps.engine.utils import ( - av_scan_paths, process_failed_job, configure_dependent_job, parse_exception_message, get_rq_job_meta + av_scan_paths, process_failed_job, configure_dependent_job, parse_exception_message, get_rq_job_meta, get_import_rq_id ) from cvat.apps.engine import backup from cvat.apps.engine.mixins import PartialUpdateModelMixin, UploadMixin, AnnotationMixin, SerializeMixin @@ -244,7 +244,7 @@ class ProjectViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, ordering = "-id" lookup_fields = {'owner': 'owner__username', 'assignee': 'assignee__username'} iam_organization_field = 'organization' - IMPORT_RQ_ID_TEMPLATE = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format('project', {}, 'dataset', {}) + IMPORT_RQ_ID_TEMPLATE = get_import_rq_id('project', {}, 'dataset', {}) def get_serializer_class(self): if self.request.method in SAFE_METHODS: @@ -705,7 +705,7 @@ class TaskViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, ordering_fields = list(filter_fields) ordering = "-id" iam_organization_field = 'organization' - IMPORT_RQ_ID_TEMPLATE = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format('task', {}, 'annotations', {}) + IMPORT_RQ_ID_TEMPLATE = get_import_rq_id('task', {}, 'annotations', {}) def get_serializer_class(self): if self.request.method in SAFE_METHODS: @@ -1286,7 +1286,7 @@ class JobViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, 'project_name': 'segment__task__project__name', 'assignee': 'assignee__username' } - IMPORT_RQ_ID_TEMPLATE = settings.COMMON_IMPORT_RQ_ID_TEMPLATE.format('job', {}, 'annotations', {}) + IMPORT_RQ_ID_TEMPLATE = get_import_rq_id('job', {}, 'annotations', {}) def get_queryset(self): queryset = super().get_queryset() diff --git a/cvat/settings/base.py b/cvat/settings/base.py index 538a2221f95..a758a80d533 100644 --- a/cvat/settings/base.py +++ b/cvat/settings/base.py @@ -342,9 +342,6 @@ class CVAT_QUEUES(Enum): 'cvat.apps.events.handlers.handle_rq_exception', ] -# import:---by- -COMMON_IMPORT_RQ_ID_TEMPLATE="import:{}-{}-{}-by-{}" - # JavaScript and CSS compression # https://django-compressor.readthedocs.io From 2f792698b8e90affa0bf83cdba8c2b6c33953222 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Wed, 10 May 2023 00:07:52 +0200 Subject: [PATCH 22/68] Apply part of comments --- cvat-sdk/cvat_sdk/core/uploading.py | 3 +-- cvat/apps/engine/backup.py | 7 ++++--- cvat/apps/engine/views.py | 29 ++++++++++------------------- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/cvat-sdk/cvat_sdk/core/uploading.py b/cvat-sdk/cvat_sdk/core/uploading.py index b11630b8643..28ae11dbf1d 100644 --- a/cvat-sdk/cvat_sdk/core/uploading.py +++ b/cvat-sdk/cvat_sdk/core/uploading.py @@ -281,8 +281,7 @@ def upload_file_and_wait( url, filename, pbar=pbar, query_params=params, meta={"filename": params["filename"]} ) - rq_id = json.loads(response.data).get("rq_id") - assert rq_id, "The rq_id was not found in the response" + assert json.loads(response.data).get("rq_id"), "The rq_id was not found in the response" self._wait_for_completion( url, diff --git a/cvat/apps/engine/backup.py b/cvat/apps/engine/backup.py index 98654ebf0fc..b9d7b5a75b3 100644 --- a/cvat/apps/engine/backup.py +++ b/cvat/apps/engine/backup.py @@ -931,8 +931,8 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati serializer = Serializer(data=request.data) serializer.is_valid(raise_exception=True) payload_file = serializer.validated_data[file_field_name] - filename = NamedTemporaryFile(prefix='cvat_', dir=settings.TMP_FILES_ROOT, delete=False).name - with open(filename, 'wb+') as f: + with NamedTemporaryFile(prefix='cvat_', dir=settings.TMP_FILES_ROOT, delete=False) as f: + filename = f.name for chunk in payload_file.chunks(): f.write(chunk) else: @@ -950,7 +950,8 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati is_default=location_conf['is_default']) key = filename - filename = NamedTemporaryFile(prefix='cvat_', dir=settings.TMP_FILES_ROOT, delete=False).name + with NamedTemporaryFile(prefix='cvat_', dir=settings.TMP_FILES_ROOT, delete=False) as f: + filename = f.name dependent_job = configure_dependent_job( queue=queue, rq_id=rq_id, diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 6845f233915..8b4d7ced7fe 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -496,18 +496,13 @@ def export_backup(self, request, pk=None): serializers=[ProjectFileSerializer, OpenApiTypes.NONE], resource_type_field_name=None ), + # TODO: for some reason the code generated by the openapi generator from schema with different serializers + # contains only one serializer, need to fix that. responses={ + # 201: OpenApiResponse(inline_serializer("ImportedProjectIdSerializer", fields={"id": serializers.IntegerField(required=True)}) '201': OpenApiResponse(description='The project has been imported'), '202': OpenApiResponse(RqIdSerializer, description='Importing a backup file has been started'), }) - # TODO: for some reason the code generated from schema with different serializers - # contains only one serializer, need to fix that. - # responses={ - # '201': OpenApiResponse(inline_serializer("ImportedProjectIdSerializer", fields={ - # "id": serializers.IntegerField(required=True), - # }), description='The project has been imported'), - # '202': OpenApiResponse(RqIdSerializer, description='Importing a backup file has been started'), - # }) @action(detail=False, methods=['OPTIONS', 'POST'], url_path=r'backup/?$', serializer_class=ProjectFileSerializer(required=False), parser_classes=_UPLOAD_PARSER_CLASSES) @@ -733,18 +728,14 @@ def get_queryset(self): location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False), ], request=TaskFileSerializer(required=False), + # TODO: for some reason the code generated by the openapi generator from schema with different serializers + # contains only one serializer, need to fix that. responses={ + # 201: OpenApiResponse(inline_serializer("ImportedTaskIdSerializer", fields={"id": serializers.IntegerField(required=True)}) '201': OpenApiResponse(description='The task has been imported'), '202': OpenApiResponse(RqIdSerializer, description='Importing a backup file has been started'), }) - # TODO: for some reason the code generated from schema with different serializers - # contains only one serializer, need to fix that. - # responses={ - # '201': OpenApiResponse(inline_serializer("ImportedTaskIdSerializer", fields={ - # "id": serializers.IntegerField(required=True), - # }), description='The project has been imported'), - # '202': OpenApiResponse(RqIdSerializer, description='Importing a backup file has been started'), - # }) + @action(detail=False, methods=['OPTIONS', 'POST'], url_path=r'backup/?$', serializer_class=TaskFileSerializer(required=False), parser_classes=_UPLOAD_PARSER_CLASSES) @@ -1313,7 +1304,7 @@ def upload_finished(self, request): format_name = request.query_params.get("format", "") filename = request.query_params.get("filename", "") conv_mask_to_poly = strtobool(request.query_params.get('conv_mask_to_poly', 'True')) - tmp_dir = self._object.get_tmp_dirname() + tmp_dir = self.get_upload_dir() if os.path.isfile(os.path.join(tmp_dir, filename)): annotation_file = os.path.join(tmp_dir, filename) return _import_annotations( @@ -2313,8 +2304,8 @@ def _is_there_past_non_deleted_job(): exc_info = exc_info.replace(import_error_prefix + ': ', '') return Response(data=exc_info, status=status.HTTP_400_BAD_REQUEST) - elif "Failed to find 'coco' dataset" in exc_info: - return Response(data=exc_info, status=status.HTTP_400_BAD_REQUEST) + elif "datumaro.components.errors.DatasetNotFoundError" in exc_info: + return Response(data="The uploaded annotations is incorrect", status=status.HTTP_400_BAD_REQUEST) else: return Response(data=exc_info, status=status.HTTP_500_INTERNAL_SERVER_ERROR) From 38f1730b7bfc5777c6a69a9fa90656c0f3900ea1 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Thu, 11 May 2023 13:16:03 +0200 Subject: [PATCH 23/68] Apply comments --- cvat-sdk/cvat_sdk/core/uploading.py | 10 ++-- cvat/apps/dataset_manager/project.py | 2 - cvat/apps/dataset_manager/task.py | 5 +- .../dataset_manager/tests/test_formats.py | 5 +- cvat/apps/dataset_manager/util.py | 13 ----- cvat/apps/dataset_manager/views.py | 3 -- cvat/apps/engine/backup.py | 54 ++++++------------- cvat/apps/engine/mixins.py | 28 +++++----- cvat/apps/engine/utils.py | 13 ++++- cvat/apps/engine/views.py | 54 ++++++++++++------- cvat/settings/base.py | 4 ++ 11 files changed, 89 insertions(+), 102 deletions(-) diff --git a/cvat-sdk/cvat_sdk/core/uploading.py b/cvat-sdk/cvat_sdk/core/uploading.py index 28ae11dbf1d..19860a24beb 100644 --- a/cvat-sdk/cvat_sdk/core/uploading.py +++ b/cvat-sdk/cvat_sdk/core/uploading.py @@ -90,7 +90,7 @@ def create_url(self): headers["upload-length"] = str(self.file_size) headers["upload-metadata"] = ",".join(self.encode_metadata()) resp = self._api_client.rest_client.POST(self.client.url, headers=headers) - self.metadata["real_filename"] = resp.headers.get("Upload-Filename") + self.real_filename = resp.headers.get("Upload-Filename") url = resp.headers.get("location") if url is None: msg = "Attempt to retrieve create file url with status {}".format(resp.status_code) @@ -181,10 +181,10 @@ def upload_file( assert meta["filename"] self._tus_start_upload(url, query_params=query_params) - metadata = self._upload_file_data_with_tus( + real_filename = self._upload_file_data_with_tus( url=url, filename=filename, meta=meta, pbar=pbar, logger=logger ) - query_params["filename"] = metadata["real_filename"] + query_params["filename"] = real_filename return self._tus_finish_upload(url, query_params=query_params, fields=fields) def _wait_for_completion( @@ -219,7 +219,7 @@ def _make_tus_uploader(api_client: ApiClient, url: str, **kwargs): return _MyTusUploader(client=client, api_client=api_client, **kwargs) - def _upload_file_data_with_tus(self, url, filename, *, meta=None, pbar=None, logger=None): + def _upload_file_data_with_tus(self, url, filename, *, meta=None, pbar=None, logger=None) -> str: file_size = filename.stat().st_size if pbar is None: pbar = NullProgressReporter() @@ -236,7 +236,7 @@ def _upload_file_data_with_tus(self, url, filename, *, meta=None, pbar=None, log log_func=logger, ) tus_uploader.upload() - return tus_uploader.metadata + return tus_uploader.real_filename def _tus_start_upload(self, url, *, query_params=None): response = self._client.api_client.rest_client.POST( diff --git a/cvat/apps/dataset_manager/project.py b/cvat/apps/dataset_manager/project.py index 3cde9e2b3cd..f60005c1288 100644 --- a/cvat/apps/dataset_manager/project.py +++ b/cvat/apps/dataset_manager/project.py @@ -18,7 +18,6 @@ from .annotation import AnnotationIR from .bindings import ProjectData, load_dataset_data from .formats.registry import make_exporter, make_importer -from .util import remove_resources def export_project(project_id, dst_file, format_name, server_url=None, save_images=False): @@ -161,7 +160,6 @@ def data(self) -> dict: raise NotImplementedError() @transaction.atomic -@remove_resources def import_dataset_as_project(src_file, project_id, format_name, conv_mask_to_poly): rq_job = rq.get_current_job() rq_job.meta['status'] = 'Dataset import has been started...' diff --git a/cvat/apps/dataset_manager/task.py b/cvat/apps/dataset_manager/task.py index 0cf93f11586..dfc02aa55e5 100644 --- a/cvat/apps/dataset_manager/task.py +++ b/cvat/apps/dataset_manager/task.py @@ -19,8 +19,7 @@ from .annotation import AnnotationIR, AnnotationManager from .bindings import TaskData, JobData from .formats.registry import make_exporter, make_importer -from .util import bulk_create, remove_resources - +from .util import bulk_create class dotdict(OrderedDict): """dot.notation access to dictionary attributes""" @@ -789,7 +788,6 @@ def export_task(task_id, dst_file, format_name, server_url=None, save_images=Fal task.export(f, exporter, host=server_url, save_images=save_images) @transaction.atomic -@remove_resources def import_task_annotations(src_file, task_id, format_name, conv_mask_to_poly): task = TaskAnnotation(task_id) task.init_from_db() @@ -799,7 +797,6 @@ def import_task_annotations(src_file, task_id, format_name, conv_mask_to_poly): task.import_annotations(f, importer, conv_mask_to_poly=conv_mask_to_poly) @transaction.atomic -@remove_resources def import_job_annotations(src_file, job_id, format_name, conv_mask_to_poly): job = JobAnnotation(job_id) job.init_from_db() diff --git a/cvat/apps/dataset_manager/tests/test_formats.py b/cvat/apps/dataset_manager/tests/test_formats.py index bf80011b4cf..e1fa84d874d 100644 --- a/cvat/apps/dataset_manager/tests/test_formats.py +++ b/cvat/apps/dataset_manager/tests/test_formats.py @@ -923,8 +923,7 @@ def _test_can_import_annotations(self, task, import_format): expected_ann = TaskAnnotation(task["id"]) expected_ann.init_from_db() - dm.util.remove_resources(dm.task.import_task_annotations, should_be_deleted=False)(file_path, task["id"], - import_format, True) + dm.task.import_task_annotations(file_path, task["id"], import_format, True) actual_ann = TaskAnnotation(task["id"]) actual_ann.init_from_db() @@ -976,6 +975,6 @@ def test_can_import_mots_annotations_with_splited_masks(self): task.update() task = self._create_task(task, images) - dm.util.remove_resources(dm.task.import_task_annotations, should_be_deleted=False)(dataset_path, task['id'], format_name, True) + dm.task.import_task_annotations(dataset_path, task['id'], format_name, True) self._test_can_import_annotations(task, format_name) diff --git a/cvat/apps/dataset_manager/util.py b/cvat/apps/dataset_manager/util.py index 0253722097f..c64b9d9caf9 100644 --- a/cvat/apps/dataset_manager/util.py +++ b/cvat/apps/dataset_manager/util.py @@ -37,16 +37,3 @@ def bulk_create(db_model, objects, flt_param): return db_model.objects.bulk_create(objects) return [] - - -def remove_resources(func, should_be_deleted=True): - @functools.wraps(func) - def wrapper(src_file, *args, **kwargs): - try: - func(src_file, *args, **kwargs) - finally: - if should_be_deleted: - with suppress(FileNotFoundError): - os.remove(src_file) - return None - return wrapper diff --git a/cvat/apps/dataset_manager/views.py b/cvat/apps/dataset_manager/views.py index 14147d43f31..5d652bf7285 100644 --- a/cvat/apps/dataset_manager/views.py +++ b/cvat/apps/dataset_manager/views.py @@ -44,9 +44,6 @@ def get_export_cache_dir(db_instance): PROJECT_CACHE_TTL = DEFAULT_CACHE_TTL / 3 JOB_CACHE_TTL = DEFAULT_CACHE_TTL -IMPORT_CACHE_FAILED_TTL = DEFAULT_CACHE_TTL.total_seconds() -IMPORT_CACHE_SUCCESS_TTL = timedelta(hours=1).total_seconds() - def export(dst_format, project_id=None, task_id=None, job_id=None, server_url=None, save_images=False): try: if task_id is not None: diff --git a/cvat/apps/engine/backup.py b/cvat/apps/engine/backup.py index b9d7b5a75b3..9357031fac3 100644 --- a/cvat/apps/engine/backup.py +++ b/cvat/apps/engine/backup.py @@ -9,13 +9,11 @@ import re import shutil import tempfile -import functools from typing import Any, Dict, Iterable import uuid from zipfile import ZipFile from datetime import datetime from tempfile import NamedTemporaryFile -from contextlib import suppress import django_rq from django.conf import settings @@ -29,17 +27,15 @@ from rest_framework.exceptions import ValidationError, PermissionDenied, NotFound from django_sendfile import sendfile from distutils.util import strtobool -from datetime import timedelta -from pathlib import Path import cvat.apps.dataset_manager as dm from cvat.apps.engine import models from cvat.apps.engine.log import slogger from cvat.apps.engine.serializers import (AttributeSerializer, DataSerializer, LabelSerializer, LabeledDataSerializer, SegmentSerializer, SimpleJobSerializer, TaskReadSerializer, - ProjectReadSerializer, ProjectFileSerializer, TaskFileSerializer) + ProjectReadSerializer, ProjectFileSerializer, TaskFileSerializer, RqIdSerializer) from cvat.apps.engine.utils import ( - av_scan_paths, process_failed_job, configure_dependent_job, get_rq_job_meta, get_import_rq_id + av_scan_paths, process_failed_job, configure_dependent_job, get_rq_job_meta, get_import_rq_id, with_clean_up_after ) from cvat.apps.engine.models import ( StorageChoice, StorageMethodChoice, DataChoice, Task, Project, Location) @@ -53,24 +49,6 @@ class Version(Enum): V1 = '1.0' - -IMPORT_CACHE_FAILED_TTL = timedelta(hours=10).total_seconds() -IMPORT_CACHE_SUCCESS_TTL = timedelta(hours=1).total_seconds() - -def remove_resources(func): - @functools.wraps(func) - def wrapper(filename, *args, **kwargs): - try: - result = func(filename, *args, **kwargs) - finally: - with suppress(FileNotFoundError): - os.remove(filename) - tmp_dir = Path(filename).parent - if str(tmp_dir.parent) == get_backup_dirname(): - tmp_dir.rmdir() - return result - return wrapper - def _get_label_mapping(db_labels): label_mapping = {db_label.id: db_label.name for db_label in db_labels} for db_label in db_labels: @@ -649,7 +627,6 @@ def import_task(self): return self._db_task @transaction.atomic -@remove_resources def _import_task(filename, user, org_id): av_scan_paths(filename) task_importer = TaskImporter(filename, user, org_id) @@ -769,7 +746,6 @@ def import_project(self): return self._db_project @transaction.atomic -@remove_resources def _import_project(filename, user, org_id): av_scan_paths(filename) project_importer = ProjectImporter(filename, user, org_id) @@ -921,6 +897,9 @@ def _download_file_from_bucket(db_storage, filename, key): def _import(importer, request, queue, rq_id, Serializer, file_field_name, location_conf, filename=None): rq_job = queue.fetch_job(rq_id) + if (user_id_from_meta := getattr(rq_job, 'meta', {}).get('user', {}).get('id')) and user_id_from_meta != request.user.id: + return Response(status=status.HTTP_403_FORBIDDEN) + if not rq_job: org_id = getattr(request.iam_context['organization'], 'id', None) dependent_job = None @@ -960,21 +939,21 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati filename=filename, key=key, request=request, - result_ttl=IMPORT_CACHE_SUCCESS_TTL, - failure_ttl=IMPORT_CACHE_FAILED_TTL + result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL, + failure_ttl=settings.IMPORT_CACHE_FAILED_TTL ) rq_job = queue.enqueue_call( - func=importer, - args=(filename, request.user.id, org_id), + func=with_clean_up_after, + args=(importer, filename, request.user.id, org_id), job_id=rq_id, meta={ 'tmp_file': filename, **get_rq_job_meta(request=request, db_obj=None) }, depends_on=dependent_job, - result_ttl=IMPORT_CACHE_SUCCESS_TTL, - failure_ttl=IMPORT_CACHE_FAILED_TTL + result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL, + failure_ttl=settings.IMPORT_CACHE_FAILED_TTL ) else: if rq_job.is_finished: @@ -995,7 +974,10 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati return Response(data=exc_info, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - return Response({'rq_id': rq_id}, status=status.HTTP_202_ACCEPTED) + serializer = RqIdSerializer(data={'rq_id': rq_id}) + serializer.is_valid(raise_exception=True) + + return Response(serializer.data, status=status.HTTP_202_ACCEPTED) def get_backup_dirname(): return settings.TMP_FILES_ROOT @@ -1027,10 +1009,8 @@ def import_project(request, queue_name, filename=None): ) def import_task(request, queue_name, filename=None): - if 'rq_id' in request.data: - rq_id = request.data['rq_id'] - else: - rq_id = get_import_rq_id('task', uuid.uuid4(), 'backup', request.user) + rq_id = request.data.get('rq_id', get_import_rq_id('task', uuid.uuid4(), 'backup', request.user)) + Serializer = TaskFileSerializer file_field_name = 'task_file' diff --git a/cvat/apps/engine/mixins.py b/cvat/apps/engine/mixins.py index b60f85f93a0..f86d86ceaf6 100644 --- a/cvat/apps/engine/mixins.py +++ b/cvat/apps/engine/mixins.py @@ -15,8 +15,7 @@ from django.conf import settings from rest_framework import mixins, status from rest_framework.response import Response -from tempfile import mkdtemp -from pathlib import Path +from tempfile import NamedTemporaryFile from cvat.apps.engine.location import StorageType, get_location_configuration from cvat.apps.engine.models import Location @@ -227,25 +226,24 @@ def init_tus_upload(self, request): import_type = request.path.strip('/').split('/')[-1] if import_type == 'backup': - # we need to create unique temp dir here because + # we need to create unique temp file here because # users can try to import backups with the same name at the same time - unique_tmp_dir = Path(mkdtemp(prefix='cvat-', suffix='.backup', dir=self.get_upload_dir())) - filename = os.path.join(unique_tmp_dir.name, filename) + with NamedTemporaryFile(prefix=f'cvat-backup-{filename}-by-{request.user}', suffix='.zip', dir=self.get_upload_dir()) as tmp_file: + filename = tmp_file.name metadata['filename'] = filename file_path = os.path.join(self.get_upload_dir(), filename) - file_exists = os.path.lexists(file_path) + file_exists = os.path.lexists(file_path) and import_type != 'backup' if file_exists: # check whether the rq_job is in progress or has been finished/failed - if import_type != 'backup': - object_class_name = self._object.__class__.__name__.lower() - template = get_import_rq_id(object_class_name, self._object.pk, import_type, request.user) - queue = django_rq.get_queue(settings.CVAT_QUEUES.IMPORT_DATA.value) - finished_job_ids = queue.finished_job_registry.get_job_ids() - failed_job_ids = queue.failed_job_registry.get_job_ids() - if template in finished_job_ids or template in failed_job_ids: - os.remove(file_path) - file_exists = False + object_class_name = self._object.__class__.__name__.lower() + template = get_import_rq_id(object_class_name, self._object.pk, import_type, request.user) + queue = django_rq.get_queue(settings.CVAT_QUEUES.IMPORT_DATA.value) + finished_job_ids = queue.finished_job_registry.get_job_ids() + failed_job_ids = queue.failed_job_registry.get_job_ids() + if template in finished_job_ids or template in failed_job_ids: + os.remove(file_path) + file_exists = False if file_exists: return self._tus_response(status=status.HTTP_409_CONFLICT, diff --git a/cvat/apps/engine/utils.py b/cvat/apps/engine/utils.py index a2687aa33aa..9fd3750be69 100644 --- a/cvat/apps/engine/utils.py +++ b/cvat/apps/engine/utils.py @@ -9,6 +9,7 @@ import importlib import sys import traceback +from contextlib import suppress from typing import Any, Dict, Optional, Callable import subprocess import os @@ -234,5 +235,13 @@ def get_list_view_name(model): def get_import_rq_id(resource_type: str, resource_id: int, subresource_type: str, user: str) -> str: - # import:---by- - return f"import:{resource_type}-{resource_id}-{subresource_type}-by-{user}" + # import: by + return f"import:{resource_type} {resource_id} {subresource_type} by {user}" + +def with_clean_up_after(func, filename, *args, **kwargs): + try: + result = func(filename, *args, **kwargs) + finally: + with suppress(FileNotFoundError): + os.remove(filename) + return result diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 8b4d7ced7fe..cbf62ac8e5b 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -40,7 +40,6 @@ import cvat.apps.dataset_manager as dm import cvat.apps.dataset_manager.views # pylint: disable=unused-import -from cvat.apps.dataset_manager.views import IMPORT_CACHE_FAILED_TTL, IMPORT_CACHE_SUCCESS_TTL from cvat.apps.engine.cloud_provider import db_storage_to_storage_instance from cvat.apps.dataset_manager.bindings import CvatImportError from cvat.apps.dataset_manager.serializers import DatasetFormatsSerializer @@ -67,7 +66,7 @@ from utils.dataset_manifest import ImageManifestManager from cvat.apps.engine.utils import ( - av_scan_paths, process_failed_job, configure_dependent_job, parse_exception_message, get_rq_job_meta, get_import_rq_id + av_scan_paths, process_failed_job, configure_dependent_job, parse_exception_message, get_rq_job_meta, get_import_rq_id, with_clean_up_after ) from cvat.apps.engine import backup from cvat.apps.engine.mixins import PartialUpdateModelMixin, UploadMixin, AnnotationMixin, SerializeMixin @@ -327,7 +326,7 @@ def dataset(self, request, pk): request=request, db_obj=self._object, import_func=_import_project_dataset, - rq_func=dm.project.import_dataset_as_project, + rq_func=dm.project.import_dataset_as_project_with_cleaning_up, rq_id_template=self.IMPORT_RQ_ID_TEMPLATE ) else: @@ -337,6 +336,13 @@ def dataset(self, request, pk): rq_id = request.query_params.get('rq_id') if not rq_id: return Response('The rq_id param should be specified in the query parameters', status=status.HTTP_400_BAD_REQUEST) + + # check that used has access to current rq_job + # We should not return any status of job including "404 not found" for user that has no access for this rq_job + + if self.IMPORT_RQ_ID_TEMPLATE.format(pk, request.user) != rq_id: + return Response(status=status.HTTP_403_FORBIDDEN) + rq_job = queue.fetch_job(rq_id) if rq_job is None: return Response(status=status.HTTP_404_NOT_FOUND) @@ -394,7 +400,7 @@ def upload_finished(self, request): request=request, filename=uploaded_file, rq_id_template=self.IMPORT_RQ_ID_TEMPLATE, - rq_func=dm.project.import_dataset_as_project, + rq_func=dm.project.import_dataset_as_project_with_cleaning_up, db_obj=self._object, format_name=format_name, conv_mask_to_poly=conv_mask_to_poly @@ -2224,11 +2230,17 @@ def _is_there_past_non_deleted_job(): elif not format_desc.ENABLED: return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED) - rq_id = request.query_params.get('rq_id', rq_id_template.format(db_obj.pk, request.user)) + rq_id = request.query_params.get('rq_id') + rq_id_should_be_checked = bool(rq_id) + if not rq_id: + rq_id = rq_id_template.format(db_obj.pk, request.user) queue = django_rq.get_queue(settings.CVAT_QUEUES.IMPORT_DATA.value) rq_job = queue.fetch_job(rq_id) + if rq_id_should_be_checked and rq_id_template.format(db_obj.pk, request.user) != rq_id: + return Response(status=status.HTTP_403_FORBIDDEN) + if _is_there_past_non_deleted_job(): rq_job.delete() rq_job = queue.fetch_job(rq_id) @@ -2272,8 +2284,8 @@ def _is_there_past_non_deleted_job(): filename=filename, key=key, request=request, - result_ttl=IMPORT_CACHE_SUCCESS_TTL, - failure_ttl=IMPORT_CACHE_FAILED_TTL + result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL, + failure_ttl=settings.IMPORT_CACHE_FAILED_TTL ) av_scan_paths(filename) @@ -2281,15 +2293,18 @@ def _is_there_past_non_deleted_job(): 'tmp_file': filename, } rq_job = queue.enqueue_call( - func=rq_func, - args=(filename, db_obj.pk, format_name, conv_mask_to_poly), + func=with_clean_up_after, + args=(rq_func, filename, db_obj.pk, format_name, conv_mask_to_poly), job_id=rq_id, depends_on=dependent_job, meta={**meta, **get_rq_job_meta(request=request, db_obj=db_obj)}, - result_ttl=IMPORT_CACHE_SUCCESS_TTL, - failure_ttl=IMPORT_CACHE_FAILED_TTL + result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL, + failure_ttl=settings.IMPORT_CACHE_FAILED_TTL ) - return Response({'rq_id': rq_id}, status=status.HTTP_202_ACCEPTED) + serializer = RqIdSerializer(data={'rq_id': rq_id}) + serializer.is_valid(raise_exception=True) + + return Response(serializer.data, status=status.HTTP_202_ACCEPTED) else: if rq_job.is_finished: rq_job.delete() @@ -2304,7 +2319,7 @@ def _is_there_past_non_deleted_job(): exc_info = exc_info.replace(import_error_prefix + ': ', '') return Response(data=exc_info, status=status.HTTP_400_BAD_REQUEST) - elif "datumaro.components.errors.DatasetNotFoundError" in exc_info: + elif any([i in exc_info for i in ("DatumaroError", "DatasetImportError", "DatasetNotFoundError")]): return Response(data="The uploaded annotations is incorrect", status=status.HTTP_400_BAD_REQUEST) else: return Response(data=exc_info, @@ -2464,8 +2479,8 @@ def _import_project_dataset(request, rq_id_template, rq_func, db_obj, format_nam filename=filename, key=key, request=request, - result_ttl=IMPORT_CACHE_SUCCESS_TTL, - failure_ttl=IMPORT_CACHE_FAILED_TTL + result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL, + failure_ttl=settings.IMPORT_CACHE_FAILED_TTL ) rq_job = queue.enqueue_call( @@ -2477,10 +2492,13 @@ def _import_project_dataset(request, rq_id_template, rq_func, db_obj, format_nam **get_rq_job_meta(request=request, db_obj=db_obj), }, depends_on=dependent_job, - result_ttl=IMPORT_CACHE_SUCCESS_TTL, - failure_ttl=IMPORT_CACHE_FAILED_TTL + result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL, + failure_ttl=settings.IMPORT_CACHE_FAILED_TTL ) else: return Response(status=status.HTTP_409_CONFLICT, data='Import job already exists') - return Response({'rq_id': rq_id}, status=status.HTTP_202_ACCEPTED) + serializer = RqIdSerializer(data={'rq_id': rq_id}) + serializer.is_valid(raise_exception=True) + + return Response(serializer.data, status=status.HTTP_202_ACCEPTED) diff --git a/cvat/settings/base.py b/cvat/settings/base.py index a758a80d533..fa6af540d59 100644 --- a/cvat/settings/base.py +++ b/cvat/settings/base.py @@ -21,6 +21,7 @@ import shutil import subprocess import sys +from datetime import timedelta from distutils.util import strtobool from enum import Enum @@ -659,3 +660,6 @@ class CVAT_QUEUES(Enum): 'PORT': os.getenv('CVAT_POSTGRES_PORT', 5432), } } + +IMPORT_CACHE_FAILED_TTL = timedelta(hours=10).total_seconds() +IMPORT_CACHE_SUCCESS_TTL = timedelta(hours=1).total_seconds() From a5f51ef0e7be8f201498ecc50e678c99d20fcc22 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 12 May 2023 10:48:19 +0200 Subject: [PATCH 24/68] Fix schema --- cvat/schema.yml | 65 ------------------------------------------------- 1 file changed, 65 deletions(-) diff --git a/cvat/schema.yml b/cvat/schema.yml index 090b1cb52b5..b0883830699 100644 --- a/cvat/schema.yml +++ b/cvat/schema.yml @@ -4075,15 +4075,9 @@ paths: application/json: schema: $ref: '#/components/schemas/BackupWriteRequest' - application/x-www-form-urlencoded: - schema: - $ref: '#/components/schemas/BackupWriteRequest' multipart/form-data: schema: $ref: '#/components/schemas/BackupWriteRequest' - application/offset+octet-stream: - schema: - $ref: '#/components/schemas/BackupWriteRequest' security: - sessionAuth: [] csrfAuth: [] @@ -4099,65 +4093,6 @@ paths: schema: $ref: '#/components/schemas/RqId' description: Importing a backup file has been started - /api/projects/backup/{file_id}: - patch: - operationId: projects_partial_update_backup_file - summary: Allows to upload a file chunk. Implements TUS file uploading protocol. - parameters: - - in: header - name: X-Organization - schema: - type: string - - in: query - name: cloud_storage_id - schema: - type: number - description: Storage id - - in: query - name: filename - schema: - type: string - description: Backup file name - - in: query - name: location - schema: - type: string - enum: - - cloud_storage - - local - default: local - description: Where to import the backup file from - - in: query - name: org - schema: - type: string - description: Organization unique slug - - in: query - name: org_id - schema: - type: integer - description: Organization identifier - tags: - - projects - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/BackupWriteRequest' - multipart/form-data: - schema: - $ref: '#/components/schemas/BackupWriteRequest' - security: - - sessionAuth: [] - csrfAuth: [] - tokenAuth: [] - - signatureAuth: [] - - basicAuth: [] - responses: - '201': - description: The project has been imported - '202': - description: Importing a backup file has been started /api/schema/: get: operationId: schema_retrieve From 047b5b83bcd54716d1a1deec1892a9b8ce974723 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 12 May 2023 10:48:48 +0200 Subject: [PATCH 25/68] Rename function --- cvat/apps/engine/backup.py | 4 ++-- cvat/apps/engine/utils.py | 9 +++++++-- cvat/apps/engine/views.py | 8 ++++---- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/cvat/apps/engine/backup.py b/cvat/apps/engine/backup.py index 9357031fac3..b2d20cf3589 100644 --- a/cvat/apps/engine/backup.py +++ b/cvat/apps/engine/backup.py @@ -35,7 +35,7 @@ LabeledDataSerializer, SegmentSerializer, SimpleJobSerializer, TaskReadSerializer, ProjectReadSerializer, ProjectFileSerializer, TaskFileSerializer, RqIdSerializer) from cvat.apps.engine.utils import ( - av_scan_paths, process_failed_job, configure_dependent_job, get_rq_job_meta, get_import_rq_id, with_clean_up_after + av_scan_paths, process_failed_job, configure_dependent_job, get_rq_job_meta, get_import_rq_id, import_resource_with_clean_up_after ) from cvat.apps.engine.models import ( StorageChoice, StorageMethodChoice, DataChoice, Task, Project, Location) @@ -944,7 +944,7 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati ) rq_job = queue.enqueue_call( - func=with_clean_up_after, + func=import_resource_with_clean_up_after, args=(importer, filename, request.user.id, org_id), job_id=rq_id, meta={ diff --git a/cvat/apps/engine/utils.py b/cvat/apps/engine/utils.py index 9fd3750be69..677acaace65 100644 --- a/cvat/apps/engine/utils.py +++ b/cvat/apps/engine/utils.py @@ -10,7 +10,7 @@ import sys import traceback from contextlib import suppress -from typing import Any, Dict, Optional, Callable +from typing import Any, Dict, Optional, Callable, Union import subprocess import os import urllib.parse @@ -238,7 +238,12 @@ def get_import_rq_id(resource_type: str, resource_id: int, subresource_type: str # import: by return f"import:{resource_type} {resource_id} {subresource_type} by {user}" -def with_clean_up_after(func, filename, *args, **kwargs): +def import_resource_with_clean_up_after( + func: Union[Callable[[str, int, int], int], Callable[[str, int, str, bool], None]], + filename: str, + *args, + **kwargs, +) -> Any: try: result = func(filename, *args, **kwargs) finally: diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index cbf62ac8e5b..de61861039d 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -66,7 +66,7 @@ from utils.dataset_manifest import ImageManifestManager from cvat.apps.engine.utils import ( - av_scan_paths, process_failed_job, configure_dependent_job, parse_exception_message, get_rq_job_meta, get_import_rq_id, with_clean_up_after + av_scan_paths, process_failed_job, configure_dependent_job, parse_exception_message, get_rq_job_meta, get_import_rq_id, import_resource_with_clean_up_after ) from cvat.apps.engine import backup from cvat.apps.engine.mixins import PartialUpdateModelMixin, UploadMixin, AnnotationMixin, SerializeMixin @@ -2293,7 +2293,7 @@ def _is_there_past_non_deleted_job(): 'tmp_file': filename, } rq_job = queue.enqueue_call( - func=with_clean_up_after, + func=import_resource_with_clean_up_after, args=(rq_func, filename, db_obj.pk, format_name, conv_mask_to_poly), job_id=rq_id, depends_on=dependent_job, @@ -2484,8 +2484,8 @@ def _import_project_dataset(request, rq_id_template, rq_func, db_obj, format_nam ) rq_job = queue.enqueue_call( - func=rq_func, - args=(filename, db_obj.pk, format_name, conv_mask_to_poly), + func=import_resource_with_clean_up_after, + args=(rq_func, filename, db_obj.pk, format_name, conv_mask_to_poly), job_id=rq_id, meta={ 'tmp_file': filename, From e4b669b50332d74ede02e7205e28928503e13520 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 12 May 2023 10:49:42 +0200 Subject: [PATCH 26/68] Update test --- tests/python/rest_api/test_tasks.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index bb162cbb64d..0587b376a43 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -11,9 +11,10 @@ from functools import partial from http import HTTPStatus from itertools import chain, product +from math import ceil from pathlib import Path from tempfile import TemporaryDirectory -from time import sleep +from time import sleep, time from typing import List import pytest @@ -1501,6 +1502,7 @@ def test_user_cannot_update_task_with_cloud_storage_without_access( ) assert response.status == HTTPStatus.FORBIDDEN + @pytest.mark.usefixtures("restore_db_per_function") def test_can_report_correct_completed_jobs_count(tasks, jobs, admin_user): # Reproduces https://github.com/opencv/cvat/issues/6098 @@ -1520,6 +1522,7 @@ def test_can_report_correct_completed_jobs_count(tasks, jobs, admin_user): task, _ = api_client.tasks_api.retrieve(task["id"]) assert task.jobs.completed == 1 + class TestImportTaskAnnotations: def _make_client(self) -> Client: return Client(BASE_URL, config=Config(status_check_period=0.01)) @@ -1552,10 +1555,16 @@ def test_can_import_annotations_after_previous_unclear_import(self, task_id): filename = self.tmp_dir / f"task_{task_id}_coco.zip" task = self.client.tasks.retrieve(task_id) - task.export_dataset(self.format, filename) + task.export_dataset(self.format, filename, include_images=False) self._delete_annotations(task_id) + # define time required to upload file with annotations + start_time = time() + task.import_annotations(self.format, filename) + required_time = ceil(time() - start_time) * 2 + self._delete_annotations(task_id) + params = {"format": self.format, "filename": filename.name} url = self.client.api_map.make_endpoint_url( self.client.api_client.tasks_api.create_annotations_endpoint.path @@ -1568,7 +1577,7 @@ def test_can_import_annotations_after_previous_unclear_import(self, task_id): rq_id = json.loads(response.data)["rq_id"] assert rq_id - sleep(3) + sleep(required_time) self._check_annotations(task_id) self._delete_annotations(task_id) task.import_annotations(self.format, filename) From 9e84cf530c3494f4013678f1dca7e4660fcad0da Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 12 May 2023 11:05:14 +0200 Subject: [PATCH 27/68] Fix linters --- cvat-sdk/cvat_sdk/core/uploading.py | 4 +++- cvat/apps/dataset_manager/util.py | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cvat-sdk/cvat_sdk/core/uploading.py b/cvat-sdk/cvat_sdk/core/uploading.py index 19860a24beb..65427c8cf9a 100644 --- a/cvat-sdk/cvat_sdk/core/uploading.py +++ b/cvat-sdk/cvat_sdk/core/uploading.py @@ -219,7 +219,9 @@ def _make_tus_uploader(api_client: ApiClient, url: str, **kwargs): return _MyTusUploader(client=client, api_client=api_client, **kwargs) - def _upload_file_data_with_tus(self, url, filename, *, meta=None, pbar=None, logger=None) -> str: + def _upload_file_data_with_tus( + self, url, filename, *, meta=None, pbar=None, logger=None + ) -> str: file_size = filename.stat().st_size if pbar is None: pbar = NullProgressReporter() diff --git a/cvat/apps/dataset_manager/util.py b/cvat/apps/dataset_manager/util.py index c64b9d9caf9..8c4a4c7ed8e 100644 --- a/cvat/apps/dataset_manager/util.py +++ b/cvat/apps/dataset_manager/util.py @@ -6,8 +6,6 @@ import inspect import os, os.path as osp import zipfile -import functools -from contextlib import suppress from django.conf import settings From 6b1a3875666e5a0250c3deb4546a8c55ace20f8a Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 12 May 2023 12:20:21 +0200 Subject: [PATCH 28/68] Fix project dataset import --- cvat/apps/engine/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index de61861039d..f03da4317e2 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -326,7 +326,7 @@ def dataset(self, request, pk): request=request, db_obj=self._object, import_func=_import_project_dataset, - rq_func=dm.project.import_dataset_as_project_with_cleaning_up, + rq_func=dm.project.import_dataset_as_project, rq_id_template=self.IMPORT_RQ_ID_TEMPLATE ) else: @@ -400,7 +400,7 @@ def upload_finished(self, request): request=request, filename=uploaded_file, rq_id_template=self.IMPORT_RQ_ID_TEMPLATE, - rq_func=dm.project.import_dataset_as_project_with_cleaning_up, + rq_func=dm.project.import_dataset_as_project, db_obj=self._object, format_name=format_name, conv_mask_to_poly=conv_mask_to_poly From cbc384bc4e3761a8129f8b01b1f6329350bba6cb Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 12 May 2023 12:26:53 +0200 Subject: [PATCH 29/68] Increase failed rq job lifetime --- cvat/settings/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat/settings/base.py b/cvat/settings/base.py index fa6af540d59..e4c99dd0d9f 100644 --- a/cvat/settings/base.py +++ b/cvat/settings/base.py @@ -661,5 +661,5 @@ class CVAT_QUEUES(Enum): } } -IMPORT_CACHE_FAILED_TTL = timedelta(hours=10).total_seconds() +IMPORT_CACHE_FAILED_TTL = timedelta(days=90).total_seconds() IMPORT_CACHE_SUCCESS_TTL = timedelta(hours=1).total_seconds() From 6b653e8bfecc7a142f5b3d42f61711ff33696b6b Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 12 May 2023 12:29:38 +0200 Subject: [PATCH 30/68] Use supported symbol --- cvat/apps/engine/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cvat/apps/engine/utils.py b/cvat/apps/engine/utils.py index 677acaace65..e463d5d1f24 100644 --- a/cvat/apps/engine/utils.py +++ b/cvat/apps/engine/utils.py @@ -235,8 +235,8 @@ def get_list_view_name(model): def get_import_rq_id(resource_type: str, resource_id: int, subresource_type: str, user: str) -> str: - # import: by - return f"import:{resource_type} {resource_id} {subresource_type} by {user}" + # import:---by- + return f"import:{resource_type}-{resource_id}-{subresource_type}-by-{user}" def import_resource_with_clean_up_after( func: Union[Callable[[str, int, int], int], Callable[[str, int, str, bool], None]], From e75d4f0501a3834ed703a9301cf889c37f86813f Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 12 May 2023 19:16:50 +0200 Subject: [PATCH 31/68] Fix tests --- .../shared/utils/resource_import_export.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/python/shared/utils/resource_import_export.py b/tests/python/shared/utils/resource_import_export.py index 3dc2282c2c5..9ee8bdec26e 100644 --- a/tests/python/shared/utils/resource_import_export.py +++ b/tests/python/shared/utils/resource_import_export.py @@ -116,8 +116,13 @@ def _import_annotations_from_cloud_storage( url = f"{obj}/{obj_id}/annotations" response = post_method(user, url, data=None, **kwargs) status = response.status_code - rq_id = response.json().get("rq_id") - assert rq_id, "The rq_id was not found in the response" + + # Only the first POST request contains rq_id in response. + # Exclude cases with 403 expected status. + rq_id = None + if status == HTTPStatus.ACCEPTED: + rq_id = response.json().get("rq_id") + assert rq_id, "The rq_id was not found in the response" while status != _expect_status: assert status == HTTPStatus.ACCEPTED @@ -155,8 +160,13 @@ def _import_dataset_from_cloud_storage( url = f"{obj}/{obj_id}/dataset" response = post_method(user, url, data=None, **kwargs) status = response.status_code - rq_id = response.json().get("rq_id") - assert rq_id, "The rq_id was not found in the response" + + # Only the first POST request contains rq_id in response. + # Exclude cases with 403 expected status. + rq_id = None + if status == HTTPStatus.ACCEPTED: + rq_id = response.json().get("rq_id") + assert rq_id, "The rq_id was not found in the response" while status != _expect_status: assert status == HTTPStatus.ACCEPTED From dff240b09719098a2b4f19df4807f2f2491ca389 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Sun, 14 May 2023 12:53:41 +0200 Subject: [PATCH 32/68] Add log files after failed helm tests --- .github/workflows/helm.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/helm.yml b/.github/workflows/helm.yml index 5624ba248ec..6e53c3b2d1c 100644 --- a/.github/workflows/helm.yml +++ b/.github/workflows/helm.yml @@ -78,8 +78,27 @@ jobs: pip3 install --user -r tests/python/requirements.txt - name: REST API and SDK tests + id: run_tests # We don't have external services in Helm tests, so we ignore corresponding cases # They are still tested without Helm run: | kubectl cp tests/mounted_file_share/images $(kubectl get pods -l component=server -o jsonpath='{.items[0].metadata.name}'):/home/django/share pytest --timeout 30 --platform=kube -m "not with_external_services" tests/python + + - name: Creating a log file from cvat containers + if: failure() && steps.run_tests.conclusion == 'failure' + env: + LOGS_DIR: "${{ github.workspace }}/testing" + run: | + mkdir ${LOGS_DIR} + for container_name in "test_cvat_server_1" "test_cvat_worker_export_1" "test_cvat_worker_import_1" "test_cvat_opa_1"; + do + docker logs ${container_name} &> ${LOGS_DIR}/${container_name}.log + done + + - name: Uploading "cvat" container logs as an artifact + if: failure() && steps.run_tests.conclusion == 'failure' + uses: actions/upload-artifact@v3.1.2 + with: + name: rest_api_container_logs + path: "${{ github.workspace }}/testing" From 4bb9e851c079e53a82d6f6004974e0626abc9d4e Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Sun, 14 May 2023 13:05:27 +0200 Subject: [PATCH 33/68] Fix missing parameter --- cvat/apps/engine/views.py | 11 +++++++++-- cvat/schema.yml | 17 ++++++++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index f03da4317e2..69ff209e71a 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -975,6 +975,8 @@ def append_data_chunk(self, request, pk, file_id): parameters=[ OpenApiParameter('format', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False, description='Input format name\nYou can get the list of supported formats at:\n/server/annotation/formats'), + OpenApiParameter('rq_id', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False, + description='rq id'), ], request=PolymorphicProxySerializer('TaskAnnotationsUpdate', serializers=[LabeledDataSerializer, AnnotationFileSerializer, OpenApiTypes.NONE], @@ -986,7 +988,7 @@ def append_data_chunk(self, request, pk, file_id): '405': OpenApiResponse(description='Format is not available'), }) @extend_schema(methods=['POST'], - summary="Method allows to upload task annotations from a local file or a cloud storage", + summary="Method allows to initialize the process of upload task annotations from a local or a cloud storage file", parameters=[ OpenApiParameter('format', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False, description='Input format name\nYou can get the list of supported formats at:\n/server/annotation/formats'), @@ -1040,6 +1042,7 @@ def annotations(self, request, pk): return Response(data="Exporting annotations from a task without data is not allowed", status=status.HTTP_400_BAD_REQUEST) elif request.method == 'POST' or request.method == 'OPTIONS': + # NOTE: initialization process of annotations import format_name = request.query_params.get('format', '') return self.import_annotations( request=request, @@ -1051,6 +1054,7 @@ def annotations(self, request, pk): elif request.method == 'PUT': format_name = request.query_params.get('format', '') if format_name: + # NOTE: continue process of import annotations use_settings = strtobool(str(request.query_params.get('use_default_location', True))) conv_mask_to_poly = strtobool(request.query_params.get('conv_mask_to_poly', 'True')) obj = self._object if use_settings else request.query_params @@ -1359,7 +1363,8 @@ def upload_finished(self, request): '202': OpenApiResponse(description='Exporting has been started'), '405': OpenApiResponse(description='Format is not available'), }) - @extend_schema(methods=['POST'], summary='Method allows to upload job annotations', + @extend_schema(methods=['POST'], + summary='Method allows to initialize the process of the job annotation upload from a local file or a cloud storage', parameters=[ OpenApiParameter('format', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False, description='Input format name\nYou can get the list of supported formats at:\n/server/annotation/formats'), @@ -1384,6 +1389,8 @@ def upload_finished(self, request): parameters=[ OpenApiParameter('format', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False, description='Input format name\nYou can get the list of supported formats at:\n/server/annotation/formats'), + OpenApiParameter('rq_id', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False, + description='rq id'), ], request=PolymorphicProxySerializer( component_name='JobAnnotationsUpdate', diff --git a/cvat/schema.yml b/cvat/schema.yml index b0883830699..6e7f635bea2 100644 --- a/cvat/schema.yml +++ b/cvat/schema.yml @@ -2018,7 +2018,8 @@ paths: description: Format is not available post: operationId: jobs_create_annotations - summary: Method allows to upload job annotations + summary: Method allows to initialize the process of the job annotation upload + from a local file or a cloud storage parameters: - in: header name: X-Organization @@ -2132,6 +2133,11 @@ paths: schema: type: integer description: Organization identifier + - in: query + name: rq_id + schema: + type: string + description: rq id tags: - jobs requestBody: @@ -4773,8 +4779,8 @@ paths: description: Format is not available post: operationId: tasks_create_annotations - summary: Method allows to upload task annotations from a local file or a cloud - storage + summary: Method allows to initialize the process of upload task annotations + from a local or a cloud storage file parameters: - in: header name: X-Organization @@ -4887,6 +4893,11 @@ paths: schema: type: integer description: Organization identifier + - in: query + name: rq_id + schema: + type: string + description: rq id tags: - tasks requestBody: From ef7dc378622971900850f182dc360bd4cf1a4a32 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 15 May 2023 14:28:46 +0200 Subject: [PATCH 34/68] Update cvat/apps/engine/views.py Co-authored-by: Maxim Zhiltsov --- cvat/apps/engine/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index f03da4317e2..1643ae01204 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -337,7 +337,7 @@ def dataset(self, request, pk): if not rq_id: return Response('The rq_id param should be specified in the query parameters', status=status.HTTP_400_BAD_REQUEST) - # check that used has access to current rq_job + # check that the user has access to the current rq_job # We should not return any status of job including "404 not found" for user that has no access for this rq_job if self.IMPORT_RQ_ID_TEMPLATE.format(pk, request.user) != rq_id: From b616024df07bd447343b7897ed5437042e2c2d72 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 19 May 2023 11:00:34 +0200 Subject: [PATCH 35/68] Add handler for deleting cache after interrupted import --- .vscode/launch.json | 23 +++++++++++++++++++ cvat/apps/engine/handlers.py | 22 +++++++++++++++++++ cvat/apps/engine/mixins.py | 24 +++++++++++++++++--- cvat/apps/engine/utils.py | 7 +++++- cvat/apps/engine/views.py | 13 ++++++----- cvat/settings/base.py | 8 +++++++ cvat/settings/rest-api-testing.py | 7 ++++++ docker-compose.yml | 22 +++++++++++++++++++ supervisord/worker.cleaning.conf | 33 ++++++++++++++++++++++++++++ tests/python/rest_api/test_tasks.py | 33 ++++++++++++++++++++++++++-- tests/python/shared/fixtures/init.py | 4 ++-- 11 files changed, 182 insertions(+), 14 deletions(-) create mode 100644 cvat/apps/engine/handlers.py create mode 100644 cvat/settings/rest-api-testing.py create mode 100644 supervisord/worker.cleaning.conf diff --git a/.vscode/launch.json b/.vscode/launch.json index 0b02a0110ca..884ed02c3b6 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -270,6 +270,28 @@ "env": {}, "console": "internalConsole" }, + { + "name": "server: RQ - cleaning", + "type": "python", + "request": "launch", + "stopOnEntry": false, + "justMyCode": false, + "python": "${command:python.interpreterPath}", + "program": "${workspaceRoot}/manage.py", + "args": [ + "rqworker", + "cleaning", + "--worker-class", + "cvat.rqworker.SimpleWorker" + ], + "django": true, + "cwd": "${workspaceFolder}", + "env": { + "DJANGO_LOG_SERVER_HOST": "localhost", + "DJANGO_LOG_SERVER_PORT": "8282" + }, + "console": "internalConsole" + }, { "name": "server: migrate", "type": "python", @@ -433,6 +455,7 @@ "server: RQ - annotation", "server: RQ - webhooks", "server: RQ - scheduler", + "server: RQ - cleaning", "server: git", ] } diff --git a/cvat/apps/engine/handlers.py b/cvat/apps/engine/handlers.py new file mode 100644 index 00000000000..534b4c7bf13 --- /dev/null +++ b/cvat/apps/engine/handlers.py @@ -0,0 +1,22 @@ +# Copyright (C) 2023 CVAT.ai Corporation +# +# SPDX-License-Identifier: MIT + +from pathlib import Path +from time import time +from django.conf import settings +from cvat.apps.engine.log import slogger + + +def clear_import_cache(path: Path, creation_time: float) -> None: + """ + This function checks and removes the import files if they have not been removed from rq import jobs. + This means that for some reason file was uploaded to CVAT server but rq import job was not created. + + Args: + path (Path): path to file + creation_time (float): file creation time + """ + if path.is_file() and (time() - creation_time + 1) >= settings.RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER.total_seconds(): + path.unlink() + slogger.glob.warning(f"The file {str(path)} was removed from cleaning job.") diff --git a/cvat/apps/engine/mixins.py b/cvat/apps/engine/mixins.py index f86d86ceaf6..6d5ca146016 100644 --- a/cvat/apps/engine/mixins.py +++ b/cvat/apps/engine/mixins.py @@ -7,19 +7,22 @@ import json import os import uuid -import django_rq from dataclasses import asdict, dataclass from distutils.util import strtobool +from pathlib import Path +from tempfile import NamedTemporaryFile from unittest import mock +import django_rq from django.conf import settings from rest_framework import mixins, status from rest_framework.response import Response -from tempfile import NamedTemporaryFile from cvat.apps.engine.location import StorageType, get_location_configuration +from cvat.apps.engine.log import slogger from cvat.apps.engine.models import Location from cvat.apps.engine.serializers import DataSerializer +from cvat.apps.engine.handlers import clear_import_cache from cvat.apps.engine.utils import get_import_rq_id @@ -229,7 +232,7 @@ def init_tus_upload(self, request): # we need to create unique temp file here because # users can try to import backups with the same name at the same time with NamedTemporaryFile(prefix=f'cvat-backup-{filename}-by-{request.user}', suffix='.zip', dir=self.get_upload_dir()) as tmp_file: - filename = tmp_file.name + filename = os.path.relpath(tmp_file.name, self.get_upload_dir()) metadata['filename'] = filename file_path = os.path.join(self.get_upload_dir(), filename) file_exists = os.path.lexists(file_path) and import_type != 'backup' @@ -260,6 +263,21 @@ def init_tus_upload(self, request): location = request.build_absolute_uri() if 'HTTP_X_FORWARDED_HOST' not in request.META: location = request.META.get('HTTP_ORIGIN') + request.META.get('PATH_INFO') + + if import_type in ('backup', 'annotations', 'datasets'): + scheduler = django_rq.get_scheduler(settings.CVAT_QUEUES.CLEANING.value) + path = Path(self.get_upload_dir()) / tus_file.filename + cleaning_job = scheduler.enqueue_in(time_delta=settings.RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER, + func=clear_import_cache, + path=path, + creation_time=Path(tus_file.file_path).stat().st_atime + ) + slogger.glob.info( + f'The cleaning job {cleaning_job.id} is queued.' + f'The check that the file {path} is deleted will be carried out after ' + f'{settings.RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER}.' + ) + return self._tus_response( status=status.HTTP_201_CREATED, extra_headers={'Location': '{}{}'.format(location, tus_file.file_id), diff --git a/cvat/apps/engine/utils.py b/cvat/apps/engine/utils.py index e463d5d1f24..413ebfac72c 100644 --- a/cvat/apps/engine/utils.py +++ b/cvat/apps/engine/utils.py @@ -234,7 +234,12 @@ def get_list_view_name(model): } -def get_import_rq_id(resource_type: str, resource_id: int, subresource_type: str, user: str) -> str: +def get_import_rq_id( + resource_type: str, + resource_id: int, + subresource_type: str, + user: str, +) -> str: # import:---by- return f"import:{resource_type}-{resource_id}-{subresource_type}-by-{user}" diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 69ff209e71a..db2a8a1bf71 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -2226,9 +2226,6 @@ def _download_file_from_bucket(db_storage, filename, key): def _import_annotations(request, rq_id_template, rq_func, db_obj, format_name, filename=None, location_conf=None, conv_mask_to_poly=True): - def _is_there_past_non_deleted_job(): - return rq_job and request.method == 'POST' and (rq_job.is_finished or rq_job.is_failed) - format_desc = {f.DISPLAY_NAME: f for f in dm.views.get_import_formats()}.get(format_name) if format_desc is None: @@ -2248,9 +2245,13 @@ def _is_there_past_non_deleted_job(): if rq_id_should_be_checked and rq_id_template.format(db_obj.pk, request.user) != rq_id: return Response(status=status.HTTP_403_FORBIDDEN) - if _is_there_past_non_deleted_job(): - rq_job.delete() - rq_job = queue.fetch_job(rq_id) + if rq_job and request.method == 'POST': + # If there is a previous job that has not been deleted + if rq_job.is_finished or rq_job.is_failed: + rq_job.delete() + rq_job = queue.fetch_job(rq_id) + else: + return Response(status=status.HTTP_409_CONFLICT, data='Import job already exists') if not rq_job: # If filename is specified we consider that file was uploaded via TUS, so it exists in filesystem diff --git a/cvat/settings/base.py b/cvat/settings/base.py index e4c99dd0d9f..ea5b86b2909 100644 --- a/cvat/settings/base.py +++ b/cvat/settings/base.py @@ -295,6 +295,7 @@ class CVAT_QUEUES(Enum): AUTO_ANNOTATION = 'annotation' WEBHOOKS = 'webhooks' NOTIFICATIONS = 'notifications' + CLEANING = 'cleaning' RQ_QUEUES = { CVAT_QUEUES.IMPORT_DATA.value: { @@ -327,6 +328,12 @@ class CVAT_QUEUES(Enum): 'DB': 0, 'DEFAULT_TIMEOUT': '1h' }, + CVAT_QUEUES.CLEANING.value: { + 'HOST': 'localhost', + 'PORT': 6379, + 'DB': 0, + 'DEFAULT_TIMEOUT': '1h' + }, } NUCLIO = { @@ -663,3 +670,4 @@ class CVAT_QUEUES(Enum): IMPORT_CACHE_FAILED_TTL = timedelta(days=90).total_seconds() IMPORT_CACHE_SUCCESS_TTL = timedelta(hours=1).total_seconds() +RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER = timedelta(hours=2) diff --git a/cvat/settings/rest-api-testing.py b/cvat/settings/rest-api-testing.py new file mode 100644 index 00000000000..f6e4742c090 --- /dev/null +++ b/cvat/settings/rest-api-testing.py @@ -0,0 +1,7 @@ +# Copyright (C) 2023 CVAT.ai Corporation +# +# SPDX-License-Identifier: MIT + +from .production import * + +RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER = timedelta(seconds=10) diff --git a/docker-compose.yml b/docker-compose.yml index dfd6fa51b17..de3a146a36c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -178,6 +178,28 @@ services: networks: - cvat + cvat_worker_cleaning: + container_name: cvat_worker_cleaning + image: cvat/server:${CVAT_VERSION:-dev} + restart: always + depends_on: + - cvat_redis + - cvat_db + environment: + CVAT_REDIS_HOST: 'cvat_redis' + CVAT_POSTGRES_HOST: 'cvat_db' + DJANGO_LOG_SERVER_HOST: vector + DJANGO_LOG_SERVER_PORT: 80 + no_proxy: clickhouse,grafana,vector,nuclio,opa,${no_proxy:-} + NUMPROCS: 1 + command: -c supervisord/worker.cleaning.conf + volumes: + - cvat_data:/home/django/data + - cvat_keys:/home/django/keys + - cvat_logs:/home/django/logs + networks: + - cvat + cvat_ui: container_name: cvat_ui image: cvat/ui:${CVAT_VERSION:-dev} diff --git a/supervisord/worker.cleaning.conf b/supervisord/worker.cleaning.conf new file mode 100644 index 00000000000..5aac80f1eac --- /dev/null +++ b/supervisord/worker.cleaning.conf @@ -0,0 +1,33 @@ +[unix_http_server] +file = /tmp/supervisord/supervisor.sock + +[supervisorctl] +serverurl = unix:///tmp/supervisord/supervisor.sock + + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisord] +nodaemon=true +logfile=%(ENV_HOME)s/logs/supervisord.log ; supervisord log file +logfile_maxbytes=50MB ; maximum size of logfile before rotation +logfile_backups=10 ; number of backed up logfiles +loglevel=debug ; info, debug, warn, trace +pidfile=/tmp/supervisord/supervisord.pid ; pidfile location +childlogdir=%(ENV_HOME)s/logs/ ; where child log files will live + +[program:ssh-agent] +command=bash -c "rm /tmp/ssh-agent.sock -f && /usr/bin/ssh-agent -d -a /tmp/ssh-agent.sock" +priority=1 +autorestart=true + +[program:rqworker_cleaning] +command=%(ENV_HOME)s/wait-for-it.sh %(ENV_CVAT_REDIS_HOST)s:6379 -t 0 -- bash -ic " \ + exec python3 %(ENV_HOME)s/manage.py rqworker -v 3 cleaning \ + --worker-class cvat.rqworker.DefaultWorker \ + " +environment=SSH_AUTH_SOCK="/tmp/ssh-agent.sock",VECTOR_EVENT_HANDLER="SynchronousLogstashHandler" +numprocs=%(ENV_NUMPROCS)s +process_name=rqworker_cleaning_%(process_num)s + diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index 0587b376a43..c1d8eac483c 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -1523,6 +1523,7 @@ def test_can_report_correct_completed_jobs_count(tasks, jobs, admin_user): assert task.jobs.completed == 1 +@pytest.mark.usefixtures("restore_cvat_data") class TestImportTaskAnnotations: def _make_client(self) -> Client: return Client(BASE_URL, config=Config(status_check_period=0.01)) @@ -1549,8 +1550,8 @@ def _delete_annotations(self, task_id): (_, response) = api_client.tasks_api.destroy_annotations(id=task_id) assert response.status == HTTPStatus.NO_CONTENT - @pytest.mark.parametrize("task_id", [20]) - def test_can_import_annotations_after_previous_unclear_import(self, task_id): + def test_can_import_annotations_after_previous_unclear_import(self, tasks_with_shapes): + task_id = tasks_with_shapes[0]["id"] self._check_annotations(task_id) filename = self.tmp_dir / f"task_{task_id}_coco.zip" @@ -1582,3 +1583,31 @@ def test_can_import_annotations_after_previous_unclear_import(self, task_id): self._delete_annotations(task_id) task.import_annotations(self.format, filename) self._check_annotations(task_id) + + @pytest.mark.timeout(40) + def test_can_import_annotations_after_previous_interrupted_upload(self, tasks_with_shapes): + task_id = tasks_with_shapes[0]["id"] + self._check_annotations(task_id) + + filename = self.tmp_dir / f"task_{task_id}_coco.zip" + task = self.client.tasks.retrieve(task_id) + task.export_dataset(self.format, filename, include_images=False) + self._delete_annotations(task_id) + + params = {"format": self.format, "filename": filename.name} + url = self.client.api_map.make_endpoint_url( + self.client.api_client.tasks_api.create_annotations_endpoint.path + ).format(id=task_id) + + uploader = Uploader(self.client) + uploader._tus_start_upload(url, query_params=params) + uploader._upload_file_data_with_tus( + url, filename, meta=params, logger=self.client.logger.debug + ) + sleep(30) + assert not int( + subprocess.check_output( + f'docker exec -it test_cvat_server_1 bash -c "ls data/tasks/{task_id}/tmp | wc -l"', + shell=True, + ) + ) diff --git a/tests/python/shared/fixtures/init.py b/tests/python/shared/fixtures/init.py index 769c576d8ed..d9e409c7005 100644 --- a/tests/python/shared/fixtures/init.py +++ b/tests/python/shared/fixtures/init.py @@ -22,14 +22,14 @@ PREFIX = "test" CONTAINER_NAME_FILES = ["docker-compose.tests.yml"] - +OVERRIDE_FILES = ['tests/docker-compose.override.yml'] DC_FILES = [ "docker-compose.dev.yml", "tests/docker-compose.file_share.yml", "tests/docker-compose.minio.yml", "tests/docker-compose.test_servers.yml", -] + CONTAINER_NAME_FILES +] + CONTAINER_NAME_FILES + OVERRIDE_FILES def pytest_addoption(parser): From f8942980c560011f970e590250e1a9e0ffd724b0 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 19 May 2023 14:37:53 +0200 Subject: [PATCH 36/68] Add missed file --- tests/docker-compose.override.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/docker-compose.override.yml diff --git a/tests/docker-compose.override.yml b/tests/docker-compose.override.yml new file mode 100644 index 00000000000..d6345bd9458 --- /dev/null +++ b/tests/docker-compose.override.yml @@ -0,0 +1,8 @@ +services: + cvat_server: + environment: + DJANGO_SETTINGS_MODULE: cvat.settings.rest-api-testing + + cvat_worker_cleaning: + environment: + DJANGO_SETTINGS_MODULE: cvat.settings.rest-api-testing \ No newline at end of file From 4a099c6d09354cee1b4fc4db3ff0b3f5f6a5f10a Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 19 May 2023 14:40:08 +0200 Subject: [PATCH 37/68] Fix attempt to get exec info from non-existent dependent job --- cvat/apps/engine/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat/apps/engine/utils.py b/cvat/apps/engine/utils.py index 413ebfac72c..bfaa04f5871 100644 --- a/cvat/apps/engine/utils.py +++ b/cvat/apps/engine/utils.py @@ -135,7 +135,7 @@ def parse_exception_message(msg): return parsed_msg def process_failed_job(rq_job: Job): - exc_info = str(rq_job.exc_info or rq_job.dependency.exc_info) + exc_info = str(rq_job.exc_info or getattr(rq_job.dependency, 'exc_info', None) or '') if rq_job.dependency: rq_job.dependency.delete() rq_job.delete() From 18663469895b5cd508852a55da761153e287f2c8 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 19 May 2023 14:40:35 +0200 Subject: [PATCH 38/68] Increase timeout --- cvat/settings/rest-api-testing.py | 2 +- tests/python/rest_api/test_tasks.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cvat/settings/rest-api-testing.py b/cvat/settings/rest-api-testing.py index f6e4742c090..7220fd2cf94 100644 --- a/cvat/settings/rest-api-testing.py +++ b/cvat/settings/rest-api-testing.py @@ -4,4 +4,4 @@ from .production import * -RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER = timedelta(seconds=10) +RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER = timedelta(seconds=30) diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index c1d8eac483c..f6ee8c8d02f 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -1584,7 +1584,7 @@ def test_can_import_annotations_after_previous_unclear_import(self, tasks_with_s task.import_annotations(self.format, filename) self._check_annotations(task_id) - @pytest.mark.timeout(40) + @pytest.mark.timeout(45) def test_can_import_annotations_after_previous_interrupted_upload(self, tasks_with_shapes): task_id = tasks_with_shapes[0]["id"] self._check_annotations(task_id) @@ -1604,7 +1604,7 @@ def test_can_import_annotations_after_previous_interrupted_upload(self, tasks_wi uploader._upload_file_data_with_tus( url, filename, meta=params, logger=self.client.logger.debug ) - sleep(30) + sleep(35) assert not int( subprocess.check_output( f'docker exec -it test_cvat_server_1 bash -c "ls data/tasks/{task_id}/tmp | wc -l"', From 24831c380f7ae8d251e3a319ac5daacebacfceb8 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 19 May 2023 14:41:07 +0200 Subject: [PATCH 39/68] Update datumaro version --- cvat/requirements/base.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat/requirements/base.in b/cvat/requirements/base.in index a664fc34332..b30ea76b4cb 100644 --- a/cvat/requirements/base.in +++ b/cvat/requirements/base.in @@ -53,7 +53,7 @@ diskcache==5.4.0 boto3==1.17.61 azure-storage-blob==12.13.0 google-cloud-storage==1.42.0 -git+https://github.com/cvat-ai/datumaro.git@0817144ade1ddc514e182ca1835e322cb9af00a0 +git+https://github.com/cvat-ai/datumaro.git@ff83c00c2c1bc4b8fdfcc55067fcab0a9b5b6b11 urllib3>=1.26.5 # not directly required, pinned by Snyk to avoid a vulnerability natsort==8.0.0 mistune>=2.0.1 # not directly required, pinned by Snyk to avoid a vulnerability From d0169d734d487b4ebada2b9d1a8e344ff191771c Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 19 May 2023 14:48:41 +0200 Subject: [PATCH 40/68] Add endpoints description --- cvat/apps/engine/backup.py | 8 +-- cvat/apps/engine/views.py | 104 +++++++++++++++++++++++++++++++------ cvat/settings/base.py | 4 +- 3 files changed, 94 insertions(+), 22 deletions(-) diff --git a/cvat/apps/engine/backup.py b/cvat/apps/engine/backup.py index b2d20cf3589..6ae3349b058 100644 --- a/cvat/apps/engine/backup.py +++ b/cvat/apps/engine/backup.py @@ -939,8 +939,8 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati filename=filename, key=key, request=request, - result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL, - failure_ttl=settings.IMPORT_CACHE_FAILED_TTL + result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL.total_seconds(), + failure_ttl=settings.IMPORT_CACHE_FAILED_TTL.total_seconds() ) rq_job = queue.enqueue_call( @@ -952,8 +952,8 @@ def _import(importer, request, queue, rq_id, Serializer, file_field_name, locati **get_rq_job_meta(request=request, db_obj=None) }, depends_on=dependent_job, - result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL, - failure_ttl=settings.IMPORT_CACHE_FAILED_TTL + result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL.total_seconds(), + failure_ttl=settings.IMPORT_CACHE_FAILED_TTL.total_seconds() ) else: if rq_job.is_finished: diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index bbfa8f2be1a..b84e131cbd2 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -8,6 +8,7 @@ import os.path as osp import pytz import traceback +import textwrap from datetime import datetime from distutils.util import strtobool from tempfile import NamedTemporaryFile @@ -266,6 +267,14 @@ def perform_create(self, serializer, **kwargs): ) @extend_schema(methods=['GET'], summary='Export project as a dataset in a specific format', + description=textwrap.dedent(""" + To check the status of the process of importing a project dataset from a file: + + After initiating the dataset upload, you will receive an rq_id parameter. + Make sure to include this parameter as a query parameter in your subsequent + GET /api/projects/id/dataset requests to track the status of the dataset import. + Also you should specify action parameter: action=import_status. + """), parameters=[ OpenApiParameter('format', description='Desired output format name\n' 'You can get the list of supported formats at:\n/server/annotation/formats', @@ -291,7 +300,13 @@ def perform_create(self, serializer, **kwargs): '202': OpenApiResponse(description='Exporting has been started'), '405': OpenApiResponse(description='Format is not available'), }) - @extend_schema(methods=['POST'], summary='Import dataset in specific format as a project', + @extend_schema(methods=['POST'], + summary='Import dataset in specific format as a project or check status of dataset import process', + description=textwrap.dedent(""" + The request POST /api/projects/id/dataset will initiate file upload and will create + the rq job on the server in which the process of dataset import from a file + will be carried out. Please, use the GET /api/projects/id/dataset endpoint for checking status of the process. + """), parameters=[ OpenApiParameter('format', description='Desired dataset format name\n' 'You can get the list of supported formats at:\n/server/annotation/formats', @@ -489,6 +504,18 @@ def export_backup(self, request, pk=None): return self.serialize(request, backup.export) @extend_schema(methods=['POST'], summary='Methods create a project from a backup', + description=textwrap.dedent(""" + The backup import process is as follows: + + The first request POST /api/projects/backup will initiate file upload and will create + the rq job on the server in which the process of a project creating from an uploaded backup + will be carried out. + + After initiating the backup upload, you will receive an rq_id parameter. + Make sure to include this parameter as a query parameter in your subsequent requests + to track the status of the project creation. + Once the project has been successfully created, the server will return the id of the newly created project. + """), parameters=[ OpenApiParameter('location', description='Where to import the backup file from', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False, @@ -497,6 +524,8 @@ def export_backup(self, request, pk=None): location=OpenApiParameter.QUERY, type=OpenApiTypes.NUMBER, required=False), OpenApiParameter('filename', description='Backup file name', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False), + OpenApiParameter('rq_id', description='rq id', + location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False), ], request=PolymorphicProxySerializer('BackupWrite', serializers=[ProjectFileSerializer, OpenApiTypes.NONE], @@ -724,6 +753,18 @@ def get_queryset(self): return queryset @extend_schema(summary='Method recreates a task from an attached task backup file', + description=textwrap.dedent(""" + The backup import process is as follows: + + The first request POST /api/tasks/backup will initiate file upload and will create + the rq job on the server in which the process of a task creating from an uploaded backup + will be carried out. + + After initiating the backup upload, you will receive an rq_id parameter. + Make sure to include this parameter as a query parameter in your subsequent requests + to track the status of the task creation. + Once the task has been successfully created, the server will return the id of the newly created task. + """), parameters=[ OpenApiParameter('location', description='Where to import the backup file from', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False, @@ -732,6 +773,8 @@ def get_queryset(self): location=OpenApiParameter.QUERY, type=OpenApiTypes.NUMBER, required=False), OpenApiParameter('filename', description='Backup file name', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False), + OpenApiParameter('rq_id', description='rq id', + location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False), ], request=TaskFileSerializer(required=False), # TODO: for some reason the code generated by the openapi generator from schema with different serializers @@ -971,7 +1014,14 @@ def append_data_chunk(self, request, pk, file_id): '400': OpenApiResponse(description='Exporting without data is not allowed'), '405': OpenApiResponse(description='Format is not available'), }) - @extend_schema(methods=['PUT'], summary='Method allows to upload task annotations', + @extend_schema(methods=['PUT'], summary='Method allows to upload task annotations or edit existing annotations', + description=textwrap.dedent(""" + To check the status of the process of uploading a task annotations from a file: + + After initiating the annotations upload, you will receive an rq_id parameter. + Make sure to include this parameter as a query parameter in your subsequent + PUT /api/tasks/id/annotations requests to track the status of the annotations upload. + """), parameters=[ OpenApiParameter('format', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False, description='Input format name\nYou can get the list of supported formats at:\n/server/annotation/formats'), @@ -989,6 +1039,11 @@ def append_data_chunk(self, request, pk, file_id): }) @extend_schema(methods=['POST'], summary="Method allows to initialize the process of upload task annotations from a local or a cloud storage file", + description=textwrap.dedent(""" + The request POST /api/tasks/id/annotations will initiate file upload and will create + the rq job on the server in which the process of annotations uploading from file + will be carried out. Please, use the PUT /api/tasks/id/annotations endpoint for checking status of the process. + """), parameters=[ OpenApiParameter('format', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False, description='Input format name\nYou can get the list of supported formats at:\n/server/annotation/formats'), @@ -1365,6 +1420,11 @@ def upload_finished(self, request): }) @extend_schema(methods=['POST'], summary='Method allows to initialize the process of the job annotation upload from a local file or a cloud storage', + description=textwrap.dedent(""" + The request POST /api/jobs/id/annotations will initiate file upload and will create + the rq job on the server in which the process of annotations uploading from file + will be carried out. Please, use the PUT /api/jobs/id/annotations endpoint for checking status of the process. + """), parameters=[ OpenApiParameter('format', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False, description='Input format name\nYou can get the list of supported formats at:\n/server/annotation/formats'), @@ -1385,7 +1445,16 @@ def upload_finished(self, request): '202': OpenApiResponse(RqIdSerializer, description='Uploading has been started'), '405': OpenApiResponse(description='Format is not available'), }) - @extend_schema(methods=['PUT'], summary='Method performs an update of all annotations in a specific job', + @extend_schema(methods=['PUT'], + summary='Method performs an update of all annotations in a specific job ' + 'or used for uploading annotations from a file', + description=textwrap.dedent(""" + To check the status of the process of uploading a job annotations from a file: + + After initiating the annotations upload, you will receive an rq_id parameter. + Make sure to include this parameter as a query parameter in your subsequent + PUT /api/jobs/id/annotations requests to track the status of the annotations upload. + """), parameters=[ OpenApiParameter('format', location=OpenApiParameter.QUERY, type=OpenApiTypes.STR, required=False, description='Input format name\nYou can get the list of supported formats at:\n/server/annotation/formats'), @@ -2265,7 +2334,8 @@ def _import_annotations(request, rq_id_template, rq_func, db_obj, format_name, serializer = AnnotationFileSerializer(data=request.data) if serializer.is_valid(raise_exception=True): anno_file = serializer.validated_data['annotation_file'] - filename = NamedTemporaryFile(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT, delete=False).name + with NamedTemporaryFile(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT, delete=False) as f: + filename = f.name with open(filename, 'wb+') as f: for chunk in anno_file.chunks(): f.write(chunk) @@ -2283,7 +2353,8 @@ def _import_annotations(request, rq_id_template, rq_func, db_obj, format_name, is_default=location_conf['is_default']) key = filename - filename = NamedTemporaryFile(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT, delete=False).name + with NamedTemporaryFile(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT, delete=False) as f: + filename = f.name dependent_job = configure_dependent_job( queue=queue, rq_id=rq_id, @@ -2292,8 +2363,8 @@ def _import_annotations(request, rq_id_template, rq_func, db_obj, format_name, filename=filename, key=key, request=request, - result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL, - failure_ttl=settings.IMPORT_CACHE_FAILED_TTL + result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL.total_seconds(), + failure_ttl=settings.IMPORT_CACHE_FAILED_TTL.total_seconds() ) av_scan_paths(filename) @@ -2306,8 +2377,8 @@ def _import_annotations(request, rq_id_template, rq_func, db_obj, format_name, job_id=rq_id, depends_on=dependent_job, meta={**meta, **get_rq_job_meta(request=request, db_obj=db_obj)}, - result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL, - failure_ttl=settings.IMPORT_CACHE_FAILED_TTL + result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL.total_seconds(), + failure_ttl=settings.IMPORT_CACHE_FAILED_TTL.total_seconds() ) serializer = RqIdSerializer(data={'rq_id': rq_id}) serializer.is_valid(raise_exception=True) @@ -2461,8 +2532,8 @@ def _import_project_dataset(request, rq_id_template, rq_func, db_obj, format_nam serializer = DatasetFileSerializer(data=request.data) if serializer.is_valid(raise_exception=True): dataset_file = serializer.validated_data['dataset_file'] - filename = NamedTemporaryFile(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT, delete=False).name - with open(filename, 'wb+') as f: + with NamedTemporaryFile(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT, delete=False) as f: + filename = f.name for chunk in dataset_file.chunks(): f.write(chunk) elif location == Location.CLOUD_STORAGE: @@ -2478,7 +2549,8 @@ def _import_project_dataset(request, rq_id_template, rq_func, db_obj, format_nam is_default=location_conf['is_default']) key = filename - filename = NamedTemporaryFile(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT, delete=False).name + with NamedTemporaryFile(prefix='cvat_{}'.format(db_obj.pk), dir=settings.TMP_FILES_ROOT, delete=False) as f: + filename = f.name dependent_job = configure_dependent_job( queue=queue, rq_id=rq_id, @@ -2487,8 +2559,8 @@ def _import_project_dataset(request, rq_id_template, rq_func, db_obj, format_nam filename=filename, key=key, request=request, - result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL, - failure_ttl=settings.IMPORT_CACHE_FAILED_TTL + result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL.total_seconds(), + failure_ttl=settings.IMPORT_CACHE_FAILED_TTL.total_seconds() ) rq_job = queue.enqueue_call( @@ -2500,8 +2572,8 @@ def _import_project_dataset(request, rq_id_template, rq_func, db_obj, format_nam **get_rq_job_meta(request=request, db_obj=db_obj), }, depends_on=dependent_job, - result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL, - failure_ttl=settings.IMPORT_CACHE_FAILED_TTL + result_ttl=settings.IMPORT_CACHE_SUCCESS_TTL.total_seconds(), + failure_ttl=settings.IMPORT_CACHE_FAILED_TTL.total_seconds() ) else: return Response(status=status.HTTP_409_CONFLICT, data='Import job already exists') diff --git a/cvat/settings/base.py b/cvat/settings/base.py index ea5b86b2909..21528f305c3 100644 --- a/cvat/settings/base.py +++ b/cvat/settings/base.py @@ -668,6 +668,6 @@ class CVAT_QUEUES(Enum): } } -IMPORT_CACHE_FAILED_TTL = timedelta(days=90).total_seconds() -IMPORT_CACHE_SUCCESS_TTL = timedelta(hours=1).total_seconds() +IMPORT_CACHE_FAILED_TTL = timedelta(days=90) +IMPORT_CACHE_SUCCESS_TTL = timedelta(hours=1) RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER = timedelta(hours=2) From 857118b3fea5fbb2f9f99d3909745024f1396c8a Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 19 May 2023 15:39:22 +0200 Subject: [PATCH 41/68] Wrap datumaro errors to CVATImportError --- cvat/apps/dataset_manager/project.py | 8 ++++++-- cvat/apps/dataset_manager/task.py | 13 ++++++++++--- cvat/apps/engine/views.py | 2 -- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cvat/apps/dataset_manager/project.py b/cvat/apps/dataset_manager/project.py index f60005c1288..bf621fff7c9 100644 --- a/cvat/apps/dataset_manager/project.py +++ b/cvat/apps/dataset_manager/project.py @@ -7,6 +7,7 @@ from tempfile import TemporaryDirectory import rq from typing import Any, Callable, List, Mapping, Tuple +from datumaro.components.errors import DatasetError, DatasetImportError, DatasetNotFoundError from django.db import transaction @@ -16,7 +17,7 @@ from cvat.apps.dataset_manager.task import TaskAnnotation from .annotation import AnnotationIR -from .bindings import ProjectData, load_dataset_data +from .bindings import ProjectData, load_dataset_data, CvatImportError from .formats.registry import make_exporter, make_importer def export_project(project_id, dst_file, format_name, @@ -171,4 +172,7 @@ def import_dataset_as_project(src_file, project_id, format_name, conv_mask_to_po importer = make_importer(format_name) with open(src_file, 'rb') as f: - project.import_dataset(f, importer, conv_mask_to_poly=conv_mask_to_poly) + try: + project.import_dataset(f, importer, conv_mask_to_poly=conv_mask_to_poly) + except (DatasetError, DatasetImportError, DatasetNotFoundError) as ex: + raise CvatImportError(str(ex)) diff --git a/cvat/apps/dataset_manager/task.py b/cvat/apps/dataset_manager/task.py index dfc02aa55e5..b95f1a8e441 100644 --- a/cvat/apps/dataset_manager/task.py +++ b/cvat/apps/dataset_manager/task.py @@ -7,6 +7,7 @@ from enum import Enum import os from tempfile import TemporaryDirectory +from datumaro.components.errors import DatasetError, DatasetImportError, DatasetNotFoundError from django.db import transaction from django.db.models.query import Prefetch @@ -17,7 +18,7 @@ from cvat.apps.profiler import silk_profile from .annotation import AnnotationIR, AnnotationManager -from .bindings import TaskData, JobData +from .bindings import TaskData, JobData, CvatImportError from .formats.registry import make_exporter, make_importer from .util import bulk_create @@ -794,7 +795,10 @@ def import_task_annotations(src_file, task_id, format_name, conv_mask_to_poly): importer = make_importer(format_name) with open(src_file, 'rb') as f: - task.import_annotations(f, importer, conv_mask_to_poly=conv_mask_to_poly) + try: + task.import_annotations(f, importer, conv_mask_to_poly=conv_mask_to_poly) + except (DatasetError, DatasetImportError, DatasetNotFoundError) as ex: + raise CvatImportError(str(ex)) @transaction.atomic def import_job_annotations(src_file, job_id, format_name, conv_mask_to_poly): @@ -803,4 +807,7 @@ def import_job_annotations(src_file, job_id, format_name, conv_mask_to_poly): importer = make_importer(format_name) with open(src_file, 'rb') as f: - job.import_annotations(f, importer, conv_mask_to_poly=conv_mask_to_poly) + try: + job.import_annotations(f, importer, conv_mask_to_poly=conv_mask_to_poly) + except (DatasetError, DatasetImportError, DatasetNotFoundError) as ex: + raise CvatImportError(str(ex)) diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index b84e131cbd2..6d5c3c2f913 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -2398,8 +2398,6 @@ def _import_annotations(request, rq_id_template, rq_func, db_obj, format_name, exc_info = exc_info.replace(import_error_prefix + ': ', '') return Response(data=exc_info, status=status.HTTP_400_BAD_REQUEST) - elif any([i in exc_info for i in ("DatumaroError", "DatasetImportError", "DatasetNotFoundError")]): - return Response(data="The uploaded annotations is incorrect", status=status.HTTP_400_BAD_REQUEST) else: return Response(data=exc_info, status=status.HTTP_500_INTERNAL_SERVER_ERROR) From 59b1d0f14682fd7a2e0a7c2e3e09920395514d2a Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 19 May 2023 16:14:20 +0200 Subject: [PATCH 42/68] t --- cvat/apps/engine/views.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 6d5c3c2f913..35692dd6437 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -2394,9 +2394,8 @@ def _import_annotations(request, rq_id_template, rq_func, db_obj, format_name, # RQ adds a prefix with exception class name import_error_prefix = '{}.{}'.format( CvatImportError.__module__, CvatImportError.__name__) - if exc_info.startswith(import_error_prefix): - exc_info = exc_info.replace(import_error_prefix + ': ', '') - return Response(data=exc_info, + if import_error_prefix in exc_info: + return Response(data="The annotations that were uploaded are not correct", status=status.HTTP_400_BAD_REQUEST) else: return Response(data=exc_info, From 2c253fa62d0c335924245ca6573d7876c0030019 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 19 May 2023 16:32:46 +0200 Subject: [PATCH 43/68] Update server schema --- cvat/schema.yml | 79 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/cvat/schema.yml b/cvat/schema.yml index 6e7f635bea2..122ea6cbf7d 100644 --- a/cvat/schema.yml +++ b/cvat/schema.yml @@ -2018,6 +2018,11 @@ paths: description: Format is not available post: operationId: jobs_create_annotations + description: |2 + + The request POST /api/jobs/id/annotations will initiate file upload and will create + the rq job on the server in which the process of annotations uploading from file + will be carried out. Please, use the PUT /api/jobs/id/annotations endpoint for checking status of the process. summary: Method allows to initialize the process of the job annotation upload from a local file or a cloud storage parameters: @@ -2103,7 +2108,15 @@ paths: description: Format is not available put: operationId: jobs_update_annotations - summary: Method performs an update of all annotations in a specific job + description: |2 + + To check the status of the process of uploading a job annotations from a file: + + After initiating the annotations upload, you will receive an rq_id parameter. + Make sure to include this parameter as a query parameter in your subsequent + PUT /api/jobs/id/annotations requests to track the status of the annotations upload. + summary: Method performs an update of all annotations in a specific job or used + for uploading annotations from a file parameters: - in: header name: X-Organization @@ -3824,6 +3837,14 @@ paths: /api/projects/{id}/dataset/: get: operationId: projects_retrieve_dataset + description: |2 + + To check the status of the process of importing a project dataset from a file: + + After initiating the dataset upload, you will receive an rq_id parameter. + Make sure to include this parameter as a query parameter in your subsequent + GET /api/projects/id/dataset requests to track the status of the dataset import. + Also you should specify action parameter: action=import_status. summary: Export project as a dataset in a specific format parameters: - in: header @@ -3916,7 +3937,13 @@ paths: description: Format is not available post: operationId: projects_create_dataset - summary: Import dataset in specific format as a project + description: |2 + + The request POST /api/projects/id/dataset will initiate file upload and will create + the rq job on the server in which the process of dataset import from a file + will be carried out. Please, use the GET /api/projects/id/dataset endpoint for checking status of the process. + summary: Import dataset in specific format as a project or check status of dataset + import process parameters: - in: header name: X-Organization @@ -4039,6 +4066,18 @@ paths: /api/projects/backup/: post: operationId: projects_create_backup + description: |2 + + The backup import process is as follows: + + The first request POST /api/projects/backup will initiate file upload and will create + the rq job on the server in which the process of a project creating from an uploaded backup + will be carried out. + + After initiating the backup upload, you will receive an rq_id parameter. + Make sure to include this parameter as a query parameter in your subsequent requests + to track the status of the project creation. + Once the project has been successfully created, the server will return the id of the newly created project. summary: Methods create a project from a backup parameters: - in: header @@ -4074,6 +4113,11 @@ paths: schema: type: integer description: Organization identifier + - in: query + name: rq_id + schema: + type: string + description: rq id tags: - projects requestBody: @@ -4779,6 +4823,11 @@ paths: description: Format is not available post: operationId: tasks_create_annotations + description: |2 + + The request POST /api/tasks/id/annotations will initiate file upload and will create + the rq job on the server in which the process of annotations uploading from file + will be carried out. Please, use the PUT /api/tasks/id/annotations endpoint for checking status of the process. summary: Method allows to initialize the process of upload task annotations from a local or a cloud storage file parameters: @@ -4863,7 +4912,14 @@ paths: description: Format is not available put: operationId: tasks_update_annotations - summary: Method allows to upload task annotations + description: |2 + + To check the status of the process of uploading a task annotations from a file: + + After initiating the annotations upload, you will receive an rq_id parameter. + Make sure to include this parameter as a query parameter in your subsequent + PUT /api/tasks/id/annotations requests to track the status of the annotations upload. + summary: Method allows to upload task annotations or edit existing annotations parameters: - in: header name: X-Organization @@ -5462,6 +5518,18 @@ paths: /api/tasks/backup/: post: operationId: tasks_create_backup + description: |2 + + The backup import process is as follows: + + The first request POST /api/tasks/backup will initiate file upload and will create + the rq job on the server in which the process of a task creating from an uploaded backup + will be carried out. + + After initiating the backup upload, you will receive an rq_id parameter. + Make sure to include this parameter as a query parameter in your subsequent requests + to track the status of the task creation. + Once the task has been successfully created, the server will return the id of the newly created task. summary: Method recreates a task from an attached task backup file parameters: - in: header @@ -5497,6 +5565,11 @@ paths: schema: type: integer description: Organization identifier + - in: query + name: rq_id + schema: + type: string + description: rq id tags: - tasks requestBody: From a764791cfc360c27382d90fe95830d57be784372 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 19 May 2023 23:30:03 +0200 Subject: [PATCH 44/68] Add comment --- cvat/apps/engine/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cvat/apps/engine/views.py b/cvat/apps/engine/views.py index 35692dd6437..3fb02b7b7ba 100644 --- a/cvat/apps/engine/views.py +++ b/cvat/apps/engine/views.py @@ -533,6 +533,7 @@ def export_backup(self, request, pk=None): ), # TODO: for some reason the code generated by the openapi generator from schema with different serializers # contains only one serializer, need to fix that. + # https://github.com/OpenAPITools/openapi-generator/issues/6126 responses={ # 201: OpenApiResponse(inline_serializer("ImportedProjectIdSerializer", fields={"id": serializers.IntegerField(required=True)}) '201': OpenApiResponse(description='The project has been imported'), @@ -779,6 +780,7 @@ def get_queryset(self): request=TaskFileSerializer(required=False), # TODO: for some reason the code generated by the openapi generator from schema with different serializers # contains only one serializer, need to fix that. + # https://github.com/OpenAPITools/openapi-generator/issues/6126 responses={ # 201: OpenApiResponse(inline_serializer("ImportedTaskIdSerializer", fields={"id": serializers.IntegerField(required=True)}) '201': OpenApiResponse(description='The task has been imported'), From cbe4436262554dbb1225b27e7ca3c3dc81f6ae8e Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Sat, 20 May 2023 01:00:45 +0200 Subject: [PATCH 45/68] Refactoring && debug --- .github/workflows/helm.yml | 19 -------- cvat-sdk/cvat_sdk/core/uploading.py | 4 +- docker-compose.yml | 23 +--------- supervisord/utils.conf | 9 ++++ supervisord/worker.cleaning.conf | 33 -------------- tests/docker-compose.override.yml | 2 +- tests/python/pytest.ini | 2 +- tests/python/rest_api/test_tasks.py | 71 ++++++++++++++++++----------- 8 files changed, 59 insertions(+), 104 deletions(-) delete mode 100644 supervisord/worker.cleaning.conf diff --git a/.github/workflows/helm.yml b/.github/workflows/helm.yml index 6e53c3b2d1c..5624ba248ec 100644 --- a/.github/workflows/helm.yml +++ b/.github/workflows/helm.yml @@ -78,27 +78,8 @@ jobs: pip3 install --user -r tests/python/requirements.txt - name: REST API and SDK tests - id: run_tests # We don't have external services in Helm tests, so we ignore corresponding cases # They are still tested without Helm run: | kubectl cp tests/mounted_file_share/images $(kubectl get pods -l component=server -o jsonpath='{.items[0].metadata.name}'):/home/django/share pytest --timeout 30 --platform=kube -m "not with_external_services" tests/python - - - name: Creating a log file from cvat containers - if: failure() && steps.run_tests.conclusion == 'failure' - env: - LOGS_DIR: "${{ github.workspace }}/testing" - run: | - mkdir ${LOGS_DIR} - for container_name in "test_cvat_server_1" "test_cvat_worker_export_1" "test_cvat_worker_import_1" "test_cvat_opa_1"; - do - docker logs ${container_name} &> ${LOGS_DIR}/${container_name}.log - done - - - name: Uploading "cvat" container logs as an artifact - if: failure() && steps.run_tests.conclusion == 'failure' - uses: actions/upload-artifact@v3.1.2 - with: - name: rest_api_container_logs - path: "${{ github.workspace }}/testing" diff --git a/cvat-sdk/cvat_sdk/core/uploading.py b/cvat-sdk/cvat_sdk/core/uploading.py index 65427c8cf9a..e3ceb523ecc 100644 --- a/cvat-sdk/cvat_sdk/core/uploading.py +++ b/cvat-sdk/cvat_sdk/core/uploading.py @@ -283,7 +283,9 @@ def upload_file_and_wait( url, filename, pbar=pbar, query_params=params, meta={"filename": params["filename"]} ) - assert json.loads(response.data).get("rq_id"), "The rq_id was not found in the response" + rq_id = json.loads(response.data).get("rq_id") + assert rq_id, "The rq_id was not found in the response" + params['rq_id'] = rq_id self._wait_for_completion( url, diff --git a/docker-compose.yml b/docker-compose.yml index de3a146a36c..1cc7f402a1a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -79,6 +79,7 @@ services: DJANGO_LOG_SERVER_HOST: vector DJANGO_LOG_SERVER_PORT: 80 no_proxy: clickhouse,grafana,vector,nuclio,opa,${no_proxy:-} + NUMPROCS: 1 command: -c supervisord/utils.conf volumes: - cvat_data:/home/django/data @@ -178,28 +179,6 @@ services: networks: - cvat - cvat_worker_cleaning: - container_name: cvat_worker_cleaning - image: cvat/server:${CVAT_VERSION:-dev} - restart: always - depends_on: - - cvat_redis - - cvat_db - environment: - CVAT_REDIS_HOST: 'cvat_redis' - CVAT_POSTGRES_HOST: 'cvat_db' - DJANGO_LOG_SERVER_HOST: vector - DJANGO_LOG_SERVER_PORT: 80 - no_proxy: clickhouse,grafana,vector,nuclio,opa,${no_proxy:-} - NUMPROCS: 1 - command: -c supervisord/worker.cleaning.conf - volumes: - - cvat_data:/home/django/data - - cvat_keys:/home/django/keys - - cvat_logs:/home/django/logs - networks: - - cvat - cvat_ui: container_name: cvat_ui image: cvat/ui:${CVAT_VERSION:-dev} diff --git a/supervisord/utils.conf b/supervisord/utils.conf index edea3746c25..b4ee4b15583 100644 --- a/supervisord/utils.conf +++ b/supervisord/utils.conf @@ -41,3 +41,12 @@ command=%(ENV_HOME)s/wait-for-it.sh %(ENV_CVAT_REDIS_HOST)s:6379 -t 0 -- bash -i " environment=VECTOR_EVENT_HANDLER="SynchronousLogstashHandler" numprocs=1 + +[program:rqworker_cleaning] +command=%(ENV_HOME)s/wait-for-it.sh %(ENV_CVAT_REDIS_HOST)s:6379 -t 0 -- bash -ic " \ + exec python3 %(ENV_HOME)s/manage.py rqworker -v 3 cleaning \ + --worker-class cvat.rqworker.DefaultWorker \ + " +environment=SSH_AUTH_SOCK="/tmp/ssh-agent.sock",VECTOR_EVENT_HANDLER="SynchronousLogstashHandler" +numprocs=%(ENV_NUMPROCS)s +process_name=rqworker_cleaning_%(process_num)s \ No newline at end of file diff --git a/supervisord/worker.cleaning.conf b/supervisord/worker.cleaning.conf deleted file mode 100644 index 5aac80f1eac..00000000000 --- a/supervisord/worker.cleaning.conf +++ /dev/null @@ -1,33 +0,0 @@ -[unix_http_server] -file = /tmp/supervisord/supervisor.sock - -[supervisorctl] -serverurl = unix:///tmp/supervisord/supervisor.sock - - -[rpcinterface:supervisor] -supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface - -[supervisord] -nodaemon=true -logfile=%(ENV_HOME)s/logs/supervisord.log ; supervisord log file -logfile_maxbytes=50MB ; maximum size of logfile before rotation -logfile_backups=10 ; number of backed up logfiles -loglevel=debug ; info, debug, warn, trace -pidfile=/tmp/supervisord/supervisord.pid ; pidfile location -childlogdir=%(ENV_HOME)s/logs/ ; where child log files will live - -[program:ssh-agent] -command=bash -c "rm /tmp/ssh-agent.sock -f && /usr/bin/ssh-agent -d -a /tmp/ssh-agent.sock" -priority=1 -autorestart=true - -[program:rqworker_cleaning] -command=%(ENV_HOME)s/wait-for-it.sh %(ENV_CVAT_REDIS_HOST)s:6379 -t 0 -- bash -ic " \ - exec python3 %(ENV_HOME)s/manage.py rqworker -v 3 cleaning \ - --worker-class cvat.rqworker.DefaultWorker \ - " -environment=SSH_AUTH_SOCK="/tmp/ssh-agent.sock",VECTOR_EVENT_HANDLER="SynchronousLogstashHandler" -numprocs=%(ENV_NUMPROCS)s -process_name=rqworker_cleaning_%(process_num)s - diff --git a/tests/docker-compose.override.yml b/tests/docker-compose.override.yml index d6345bd9458..02534b2e8fe 100644 --- a/tests/docker-compose.override.yml +++ b/tests/docker-compose.override.yml @@ -3,6 +3,6 @@ services: environment: DJANGO_SETTINGS_MODULE: cvat.settings.rest-api-testing - cvat_worker_cleaning: + cvat_utils: environment: DJANGO_SETTINGS_MODULE: cvat.settings.rest-api-testing \ No newline at end of file diff --git a/tests/python/pytest.ini b/tests/python/pytest.ini index 653ae999256..91c678fa625 100644 --- a/tests/python/pytest.ini +++ b/tests/python/pytest.ini @@ -8,4 +8,4 @@ timeout = 15 markers = with_external_services: The test requires services extrernal to the default CVAT deployment, e.g. a Git server etc. - + only_docker_test: The test that should only be running when CVAT is deployed in Docker. diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index f6ee8c8d02f..aec0b26c756 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -13,7 +13,7 @@ from itertools import chain, product from math import ceil from pathlib import Path -from tempfile import TemporaryDirectory +from tempfile import TemporaryDirectory, NamedTemporaryFile from time import sleep, time from typing import List @@ -1523,7 +1523,6 @@ def test_can_report_correct_completed_jobs_count(tasks, jobs, admin_user): assert task.jobs.completed == 1 -@pytest.mark.usefixtures("restore_cvat_data") class TestImportTaskAnnotations: def _make_client(self) -> Client: return Client(BASE_URL, config=Config(status_check_period=0.01)) @@ -1550,49 +1549,62 @@ def _delete_annotations(self, task_id): (_, response) = api_client.tasks_api.destroy_annotations(id=task_id) assert response.status == HTTPStatus.NO_CONTENT - def test_can_import_annotations_after_previous_unclear_import(self, tasks_with_shapes): + @pytest.mark.timeout(50) + @pytest.mark.parametrize("successful_upload", [True, False]) + def test_can_import_annotations_after_previous_unclear_import( + self, successful_upload: bool, tasks_with_shapes + ): task_id = tasks_with_shapes[0]["id"] self._check_annotations(task_id) - filename = self.tmp_dir / f"task_{task_id}_coco.zip" + with NamedTemporaryFile() as f: + filename = self.tmp_dir / f"task_{task_id}_{Path(f.name).name}_coco.zip" + task = self.client.tasks.retrieve(task_id) task.export_dataset(self.format, filename, include_images=False) self._delete_annotations(task_id) - # define time required to upload file with annotations - start_time = time() - task.import_annotations(self.format, filename) - required_time = ceil(time() - start_time) * 2 - self._delete_annotations(task_id) - params = {"format": self.format, "filename": filename.name} url = self.client.api_map.make_endpoint_url( self.client.api_client.tasks_api.create_annotations_endpoint.path ).format(id=task_id) uploader = Uploader(self.client) - response = uploader.upload_file( - url, filename, meta=params, query_params=params, logger=self.client.logger.debug - ) + if successful_upload: + # define time required to upload file with annotations + start_time = time() + task.import_annotations(self.format, filename) + required_time = ceil(time() - start_time) * 2 + self._delete_annotations(task_id) + + response = uploader.upload_file( + url, filename, meta=params, query_params=params, logger=self.client.logger.debug + ) + rq_id = json.loads(response.data)["rq_id"] + assert rq_id + else: + required_time = 40 + uploader._tus_start_upload(url, query_params=params) + uploader._upload_file_data_with_tus( + url, filename, meta=params, logger=self.client.logger.debug + ) - rq_id = json.loads(response.data)["rq_id"] - assert rq_id sleep(required_time) - self._check_annotations(task_id) - self._delete_annotations(task_id) + if successful_upload: + self._check_annotations(task_id) + self._delete_annotations(task_id) task.import_annotations(self.format, filename) self._check_annotations(task_id) - @pytest.mark.timeout(45) - def test_can_import_annotations_after_previous_interrupted_upload(self, tasks_with_shapes): + @pytest.mark.only_docker_test + @pytest.mark.timeout(50) + def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_shapes): task_id = tasks_with_shapes[0]["id"] - self._check_annotations(task_id) - - filename = self.tmp_dir / f"task_{task_id}_coco.zip" + with NamedTemporaryFile() as f: + filename = self.tmp_dir / f"task_{task_id}_{Path(f.name).name}_coco.zip" task = self.client.tasks.retrieve(task_id) task.export_dataset(self.format, filename, include_images=False) - self._delete_annotations(task_id) params = {"format": self.format, "filename": filename.name} url = self.client.api_map.make_endpoint_url( @@ -1604,10 +1616,15 @@ def test_can_import_annotations_after_previous_interrupted_upload(self, tasks_wi uploader._upload_file_data_with_tus( url, filename, meta=params, logger=self.client.logger.debug ) - sleep(35) - assert not int( - subprocess.check_output( + sleep(40) + try: + result = subprocess.check_output( f'docker exec -it test_cvat_server_1 bash -c "ls data/tasks/{task_id}/tmp | wc -l"', shell=True, + stderr=subprocess.STDOUT, + ) + assert not int(result) + except subprocess.CalledProcessError as ex: + raise RuntimeError( + f"command '{ex.cmd}' returns with error (code {ex.returncode}): {ex.output}" ) - ) From af76504a9ca7877895f80970412afeeb0a0e3501 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Sat, 20 May 2023 01:02:55 +0200 Subject: [PATCH 46/68] Apply linters comments --- tests/python/rest_api/test_tasks.py | 2 +- tests/python/shared/fixtures/init.py | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index aec0b26c756..b3ace0e75fe 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -13,7 +13,7 @@ from itertools import chain, product from math import ceil from pathlib import Path -from tempfile import TemporaryDirectory, NamedTemporaryFile +from tempfile import NamedTemporaryFile, TemporaryDirectory from time import sleep, time from typing import List diff --git a/tests/python/shared/fixtures/init.py b/tests/python/shared/fixtures/init.py index d9e409c7005..14ff483cf5c 100644 --- a/tests/python/shared/fixtures/init.py +++ b/tests/python/shared/fixtures/init.py @@ -22,14 +22,18 @@ PREFIX = "test" CONTAINER_NAME_FILES = ["docker-compose.tests.yml"] -OVERRIDE_FILES = ['tests/docker-compose.override.yml'] - -DC_FILES = [ - "docker-compose.dev.yml", - "tests/docker-compose.file_share.yml", - "tests/docker-compose.minio.yml", - "tests/docker-compose.test_servers.yml", -] + CONTAINER_NAME_FILES + OVERRIDE_FILES +OVERRIDE_FILES = ["tests/docker-compose.override.yml"] + +DC_FILES = ( + [ + "docker-compose.dev.yml", + "tests/docker-compose.file_share.yml", + "tests/docker-compose.minio.yml", + "tests/docker-compose.test_servers.yml", + ] + + CONTAINER_NAME_FILES + + OVERRIDE_FILES +) def pytest_addoption(parser): From b394620479c10397e8335d6fea729d4940d069e1 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Sat, 20 May 2023 01:04:41 +0200 Subject: [PATCH 47/68] Fix black --- cvat-sdk/cvat_sdk/core/uploading.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cvat-sdk/cvat_sdk/core/uploading.py b/cvat-sdk/cvat_sdk/core/uploading.py index e3ceb523ecc..e4635f69d88 100644 --- a/cvat-sdk/cvat_sdk/core/uploading.py +++ b/cvat-sdk/cvat_sdk/core/uploading.py @@ -285,7 +285,7 @@ def upload_file_and_wait( rq_id = json.loads(response.data).get("rq_id") assert rq_id, "The rq_id was not found in the response" - params['rq_id'] = rq_id + params["rq_id"] = rq_id self._wait_for_completion( url, From c94c2a43699daf12971906867b45b6c256243529 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 22 May 2023 10:09:41 +0200 Subject: [PATCH 48/68] Fix merge --- tests/python/rest_api/test_tasks.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index 5e3e8b36c61..705ea8b0e0c 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -7,6 +7,7 @@ import json import os import os.path as osp +import subprocess from copy import deepcopy from functools import partial from http import HTTPStatus @@ -1735,7 +1736,7 @@ def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_s sleep(40) try: result = subprocess.check_output( - f'docker exec -it test_cvat_server_1 bash -c "ls data/tasks/{task_id}/tmp | wc -l"', + f'docker exec test_cvat_server_1 bash -c "ls data/tasks/{task_id}/tmp | wc -l"', shell=True, stderr=subprocess.STDOUT, ) From 7e7c351a2c9d0dddca9aedb92c84b2ff7286645d Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 22 May 2023 10:54:04 +0200 Subject: [PATCH 49/68] Fix helm --- .github/workflows/helm.yml | 2 +- tests/python/rest_api/test_tasks.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/helm.yml b/.github/workflows/helm.yml index 5624ba248ec..c64e7b5b1ef 100644 --- a/.github/workflows/helm.yml +++ b/.github/workflows/helm.yml @@ -82,4 +82,4 @@ jobs: # They are still tested without Helm run: | kubectl cp tests/mounted_file_share/images $(kubectl get pods -l component=server -o jsonpath='{.items[0].metadata.name}'):/home/django/share - pytest --timeout 30 --platform=kube -m "not with_external_services" tests/python + pytest --timeout 30 --platform=kube -m "not with_external_services and not only_docker_test" tests/python diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index 705ea8b0e0c..8b076b8ec1b 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -1666,7 +1666,7 @@ def _delete_annotations(self, task_id): (_, response) = api_client.tasks_api.destroy_annotations(id=task_id) assert response.status == HTTPStatus.NO_CONTENT - @pytest.mark.timeout(50) + @pytest.mark.timeout(70) @pytest.mark.parametrize("successful_upload", [True, False]) def test_can_import_annotations_after_previous_unclear_import( self, successful_upload: bool, tasks_with_shapes @@ -1701,7 +1701,7 @@ def test_can_import_annotations_after_previous_unclear_import( rq_id = json.loads(response.data)["rq_id"] assert rq_id else: - required_time = 40 + required_time = 60 uploader._tus_start_upload(url, query_params=params) uploader._upload_file_data_with_tus( url, filename, meta=params, logger=self.client.logger.debug @@ -1715,7 +1715,7 @@ def test_can_import_annotations_after_previous_unclear_import( self._check_annotations(task_id) @pytest.mark.only_docker_test - @pytest.mark.timeout(50) + @pytest.mark.timeout(70) def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_shapes): task_id = tasks_with_shapes[0]["id"] with NamedTemporaryFile() as f: @@ -1733,7 +1733,7 @@ def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_s uploader._upload_file_data_with_tus( url, filename, meta=params, logger=self.client.logger.debug ) - sleep(40) + sleep(60) try: result = subprocess.check_output( f'docker exec test_cvat_server_1 bash -c "ls data/tasks/{task_id}/tmp | wc -l"', From c0b0c386407bb3d11627d9ca0f2f917a3261e7a2 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Tue, 23 May 2023 00:19:38 +0200 Subject: [PATCH 50/68] Skip test for helm --- tests/python/rest_api/test_tasks.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index 8b076b8ec1b..feada6dbea0 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -1666,6 +1666,8 @@ def _delete_annotations(self, task_id): (_, response) = api_client.tasks_api.destroy_annotations(id=task_id) assert response.status == HTTPStatus.NO_CONTENT + # skip test in helm because there is not possible to override default settings for this case + @pytest.mark.only_docker_test @pytest.mark.timeout(70) @pytest.mark.parametrize("successful_upload", [True, False]) def test_can_import_annotations_after_previous_unclear_import( From 7fbc5e7f904fda542d3ca474221348b788a17226 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Tue, 23 May 2023 18:02:08 +0200 Subject: [PATCH 51/68] Update code to match develop --- cvat/settings/rest-api-testing.py | 7 ------- cvat/settings/testing_rest.py | 2 ++ tests/docker-compose.override.yml | 8 -------- tests/python/shared/fixtures/init.py | 7 ++----- 4 files changed, 4 insertions(+), 20 deletions(-) delete mode 100644 cvat/settings/rest-api-testing.py delete mode 100644 tests/docker-compose.override.yml diff --git a/cvat/settings/rest-api-testing.py b/cvat/settings/rest-api-testing.py deleted file mode 100644 index 7220fd2cf94..00000000000 --- a/cvat/settings/rest-api-testing.py +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright (C) 2023 CVAT.ai Corporation -# -# SPDX-License-Identifier: MIT - -from .production import * - -RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER = timedelta(seconds=30) diff --git a/cvat/settings/testing_rest.py b/cvat/settings/testing_rest.py index 36bf80dc0a2..a2523ec8827 100644 --- a/cvat/settings/testing_rest.py +++ b/cvat/settings/testing_rest.py @@ -10,3 +10,5 @@ PASSWORD_HASHERS = [ "django.contrib.auth.hashers.MD5PasswordHasher", ] + +RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER = timedelta(seconds=30) diff --git a/tests/docker-compose.override.yml b/tests/docker-compose.override.yml deleted file mode 100644 index 02534b2e8fe..00000000000 --- a/tests/docker-compose.override.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - cvat_server: - environment: - DJANGO_SETTINGS_MODULE: cvat.settings.rest-api-testing - - cvat_utils: - environment: - DJANGO_SETTINGS_MODULE: cvat.settings.rest-api-testing \ No newline at end of file diff --git a/tests/python/shared/fixtures/init.py b/tests/python/shared/fixtures/init.py index 10e04404965..1ad8ef72305 100644 --- a/tests/python/shared/fixtures/init.py +++ b/tests/python/shared/fixtures/init.py @@ -22,7 +22,6 @@ PREFIX = "test" CONTAINER_NAME_FILES = ["docker-compose.tests.yml"] -OVERRIDE_FILES = ["tests/docker-compose.override.yml"] DC_FILES = ( [ @@ -30,9 +29,7 @@ "tests/docker-compose.file_share.yml", "tests/docker-compose.minio.yml", "tests/docker-compose.test_servers.yml", - ] - + CONTAINER_NAME_FILES - + OVERRIDE_FILES + ] + CONTAINER_NAME_FILES ) @@ -215,7 +212,7 @@ def create_compose_files(container_name_files): for service_name, service_config in dc_config["services"].items(): service_config.pop("container_name", None) - if service_name == "cvat_server": + if service_name in ("cvat_server", "cvat_utils"): service_env = service_config["environment"] service_env["DJANGO_SETTINGS_MODULE"] = "cvat.settings.testing_rest" From aae317003cdeb934402758ae22bce898909e4766 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Tue, 23 May 2023 18:04:38 +0200 Subject: [PATCH 52/68] debug --- tests/python/rest_api/test_tasks.py | 4 ++-- tests/values.test.yaml | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index feada6dbea0..a0c8d53048c 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -1667,7 +1667,7 @@ def _delete_annotations(self, task_id): assert response.status == HTTPStatus.NO_CONTENT # skip test in helm because there is not possible to override default settings for this case - @pytest.mark.only_docker_test + # @pytest.mark.only_docker_test @pytest.mark.timeout(70) @pytest.mark.parametrize("successful_upload", [True, False]) def test_can_import_annotations_after_previous_unclear_import( @@ -1716,7 +1716,7 @@ def test_can_import_annotations_after_previous_unclear_import( task.import_annotations(self.format, filename) self._check_annotations(task_id) - @pytest.mark.only_docker_test + # @pytest.mark.only_docker_test @pytest.mark.timeout(70) def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_shapes): task_id = tasks_with_shapes[0]["id"] diff --git a/tests/values.test.yaml b/tests/values.test.yaml index a4d90fc1242..9bdc6c12127 100644 --- a/tests/values.test.yaml +++ b/tests/values.test.yaml @@ -14,6 +14,10 @@ cvat: - mountPath: /home/django/share name: cvat-backend-data subPath: share + utils: + additionalEnv: + - name: DJANGO_SETTINGS_MODULE + value: cvat.settings.testing_rest # Images are already present in the node imagePullPolicy: Never frontend: From b700bdec781534a2b30a8fd37cb1727af3f7392a Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Tue, 23 May 2023 18:06:20 +0200 Subject: [PATCH 53/68] Fix black issue --- tests/python/shared/fixtures/init.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/python/shared/fixtures/init.py b/tests/python/shared/fixtures/init.py index 1ad8ef72305..e606d5ed4bf 100644 --- a/tests/python/shared/fixtures/init.py +++ b/tests/python/shared/fixtures/init.py @@ -23,14 +23,12 @@ CONTAINER_NAME_FILES = ["docker-compose.tests.yml"] -DC_FILES = ( - [ - "docker-compose.dev.yml", - "tests/docker-compose.file_share.yml", - "tests/docker-compose.minio.yml", - "tests/docker-compose.test_servers.yml", - ] + CONTAINER_NAME_FILES -) +DC_FILES = [ + "docker-compose.dev.yml", + "tests/docker-compose.file_share.yml", + "tests/docker-compose.minio.yml", + "tests/docker-compose.test_servers.yml", +] + CONTAINER_NAME_FILES def pytest_addoption(parser): From 06d8f2ea24d8548145126c89d8255dc852eb257e Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Tue, 23 May 2023 18:59:57 +0200 Subject: [PATCH 54/68] Fix values.tests.yaml --- tests/values.test.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/values.test.yaml b/tests/values.test.yaml index 9bdc6c12127..9002c5f3e2c 100644 --- a/tests/values.test.yaml +++ b/tests/values.test.yaml @@ -16,8 +16,8 @@ cvat: subPath: share utils: additionalEnv: - - name: DJANGO_SETTINGS_MODULE - value: cvat.settings.testing_rest + - name: DJANGO_SETTINGS_MODULE + value: cvat.settings.testing_rest # Images are already present in the node imagePullPolicy: Never frontend: From ec2574e1cfb9660827e6547c437bd8c03b806530 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Tue, 23 May 2023 19:00:34 +0200 Subject: [PATCH 55/68] t --- tests/python/rest_api/test_tasks.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index a0c8d53048c..8b076b8ec1b 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -1666,8 +1666,6 @@ def _delete_annotations(self, task_id): (_, response) = api_client.tasks_api.destroy_annotations(id=task_id) assert response.status == HTTPStatus.NO_CONTENT - # skip test in helm because there is not possible to override default settings for this case - # @pytest.mark.only_docker_test @pytest.mark.timeout(70) @pytest.mark.parametrize("successful_upload", [True, False]) def test_can_import_annotations_after_previous_unclear_import( @@ -1716,7 +1714,7 @@ def test_can_import_annotations_after_previous_unclear_import( task.import_annotations(self.format, filename) self._check_annotations(task_id) - # @pytest.mark.only_docker_test + @pytest.mark.only_docker_test @pytest.mark.timeout(70) def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_shapes): task_id = tasks_with_shapes[0]["id"] From 953f577f879be453220e5f21a84a55ff09d2b74e Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Wed, 24 May 2023 09:23:14 +0200 Subject: [PATCH 56/68] Fix helm --- tests/values.test.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/values.test.yaml b/tests/values.test.yaml index 9002c5f3e2c..e281ecb3214 100644 --- a/tests/values.test.yaml +++ b/tests/values.test.yaml @@ -14,10 +14,10 @@ cvat: - mountPath: /home/django/share name: cvat-backend-data subPath: share - utils: - additionalEnv: - - name: DJANGO_SETTINGS_MODULE - value: cvat.settings.testing_rest + utils: + additionalEnv: + - name: DJANGO_SETTINGS_MODULE + value: cvat.settings.testing_rest # Images are already present in the node imagePullPolicy: Never frontend: From 8f94f70918e4cf5d5fbe2b238c21f500296eba3a Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Wed, 24 May 2023 11:09:29 +0200 Subject: [PATCH 57/68] Update requirements --- cvat/requirements/base.txt | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/cvat/requirements/base.txt b/cvat/requirements/base.txt index 59339e0dd9a..e30aa845185 100644 --- a/cvat/requirements/base.txt +++ b/cvat/requirements/base.txt @@ -1,4 +1,4 @@ -# SHA1:53feeaa402abed516aad4a640244c5fd1bff765a +# SHA1:d1435558d66ec49d0c691492b2f3798960ca3bba # # This file is autogenerated by pip-compile-multi # To update, run: @@ -12,7 +12,7 @@ absl-py==1.4.0 # via # tensorboard # tensorflow -asgiref==3.6.0 +asgiref==3.7.1 # via django astunparse==1.6.3 # via tensorflow @@ -29,6 +29,8 @@ azure-core==1.26.4 # msrest azure-storage-blob==12.13.0 # via -r cvat/requirements/base.in +backports-zoneinfo==0.2.1 + # via django boto3==1.17.61 # via -r cvat/requirements/base.in botocore==1.20.112 @@ -66,7 +68,7 @@ cryptography==40.0.2 # pyjwt cycler==0.11.0 # via matplotlib -datumaro @ git+https://github.com/cvat-ai/datumaro.git@0817144ade1ddc514e182ca1835e322cb9af00a0 +datumaro @ git+https://github.com/cvat-ai/datumaro.git@ff83c00c2c1bc4b8fdfcc55067fcab0a9b5b6b11 # via -r cvat/requirements/base.in defusedxml==0.7.1 # via @@ -181,7 +183,11 @@ h5py==3.6.0 idna==3.4 # via requests importlib-resources==5.12.0 - # via limits + # via + # jsonschema + # limits + # matplotlib + # nibabel inflection==0.5.1 # via drf-spectacular isodate==0.6.1 @@ -234,7 +240,7 @@ opt-einsum==3.3.0 # via tensorflow orderedmultidict==1.0.1 # via furl -orjson==3.8.12 +orjson==3.8.13 # via datumaro packaging==23.1 # via @@ -249,6 +255,8 @@ patool==1.12 # via -r cvat/requirements/base.in pdf2image==1.14.0 # via -r cvat/requirements/base.in +pkgutil-resolve-name==1.3.10 + # via jsonschema protobuf==3.19.6 # via # google-api-core @@ -390,8 +398,9 @@ tensorflow-io-gcs-filesystem==0.32.0 # via tensorflow termcolor==2.3.0 # via tensorflow -typing-extensions==4.5.0 +typing-extensions==4.6.1 # via + # asgiref # azure-core # datumaro # limits @@ -402,7 +411,7 @@ uritemplate==4.1.1 # via # coreapi # drf-spectacular -urllib3==1.26.15 +urllib3==1.26.16 # via # -r cvat/requirements/base.in # botocore @@ -420,6 +429,8 @@ wrapt==1.15.0 # via # deprecated # tensorflow +zipp==3.15.0 + # via importlib-resources zstandard==0.21.0 # via clickhouse-connect From ab678cd7cde965bc40fbb4fb6f6ee6cea4632318 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Wed, 24 May 2023 11:21:03 +0200 Subject: [PATCH 58/68] keep only datumaro --- cvat/requirements/base.txt | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/cvat/requirements/base.txt b/cvat/requirements/base.txt index e30aa845185..6da356090ca 100644 --- a/cvat/requirements/base.txt +++ b/cvat/requirements/base.txt @@ -1,4 +1,4 @@ -# SHA1:d1435558d66ec49d0c691492b2f3798960ca3bba +# SHA1:53feeaa402abed516aad4a640244c5fd1bff765a # # This file is autogenerated by pip-compile-multi # To update, run: @@ -12,7 +12,7 @@ absl-py==1.4.0 # via # tensorboard # tensorflow -asgiref==3.7.1 +asgiref==3.6.0 # via django astunparse==1.6.3 # via tensorflow @@ -29,8 +29,6 @@ azure-core==1.26.4 # msrest azure-storage-blob==12.13.0 # via -r cvat/requirements/base.in -backports-zoneinfo==0.2.1 - # via django boto3==1.17.61 # via -r cvat/requirements/base.in botocore==1.20.112 @@ -183,11 +181,7 @@ h5py==3.6.0 idna==3.4 # via requests importlib-resources==5.12.0 - # via - # jsonschema - # limits - # matplotlib - # nibabel + # via limits inflection==0.5.1 # via drf-spectacular isodate==0.6.1 @@ -240,7 +234,7 @@ opt-einsum==3.3.0 # via tensorflow orderedmultidict==1.0.1 # via furl -orjson==3.8.13 +orjson==3.8.12 # via datumaro packaging==23.1 # via @@ -255,8 +249,6 @@ patool==1.12 # via -r cvat/requirements/base.in pdf2image==1.14.0 # via -r cvat/requirements/base.in -pkgutil-resolve-name==1.3.10 - # via jsonschema protobuf==3.19.6 # via # google-api-core @@ -398,9 +390,8 @@ tensorflow-io-gcs-filesystem==0.32.0 # via tensorflow termcolor==2.3.0 # via tensorflow -typing-extensions==4.6.1 +typing-extensions==4.5.0 # via - # asgiref # azure-core # datumaro # limits @@ -411,7 +402,7 @@ uritemplate==4.1.1 # via # coreapi # drf-spectacular -urllib3==1.26.16 +urllib3==1.26.15 # via # -r cvat/requirements/base.in # botocore @@ -429,8 +420,6 @@ wrapt==1.15.0 # via # deprecated # tensorflow -zipp==3.15.0 - # via importlib-resources zstandard==0.21.0 # via clickhouse-connect From 123afca97f9efd3cb14291d88ce69d70f2d05cf1 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Wed, 24 May 2023 12:18:18 +0200 Subject: [PATCH 59/68] Fix requirements --- cvat/requirements/base.txt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cvat/requirements/base.txt b/cvat/requirements/base.txt index 6da356090ca..7ba2830784e 100644 --- a/cvat/requirements/base.txt +++ b/cvat/requirements/base.txt @@ -1,4 +1,4 @@ -# SHA1:53feeaa402abed516aad4a640244c5fd1bff765a +# SHA1:d1435558d66ec49d0c691492b2f3798960ca3bba # # This file is autogenerated by pip-compile-multi # To update, run: @@ -12,7 +12,7 @@ absl-py==1.4.0 # via # tensorboard # tensorflow -asgiref==3.6.0 +asgiref==3.7.1 # via django astunparse==1.6.3 # via tensorflow @@ -234,7 +234,7 @@ opt-einsum==3.3.0 # via tensorflow orderedmultidict==1.0.1 # via furl -orjson==3.8.12 +orjson==3.8.13 # via datumaro packaging==23.1 # via @@ -390,8 +390,9 @@ tensorflow-io-gcs-filesystem==0.32.0 # via tensorflow termcolor==2.3.0 # via tensorflow -typing-extensions==4.5.0 +typing-extensions==4.6.1 # via + # asgiref # azure-core # datumaro # limits @@ -402,7 +403,7 @@ uritemplate==4.1.1 # via # coreapi # drf-spectacular -urllib3==1.26.15 +urllib3==1.26.16 # via # -r cvat/requirements/base.in # botocore From f6b3d52c8ef6a15651981776c2ec76b8d97b2695 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Fri, 26 May 2023 11:25:58 +0200 Subject: [PATCH 60/68] fix --- tests/python/rest_api/test_tasks.py | 30 +++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index 8b076b8ec1b..eb8072f8b85 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -1733,15 +1733,21 @@ def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_s uploader._upload_file_data_with_tus( url, filename, meta=params, logger=self.client.logger.debug ) - sleep(60) - try: - result = subprocess.check_output( - f'docker exec test_cvat_server_1 bash -c "ls data/tasks/{task_id}/tmp | wc -l"', - shell=True, - stderr=subprocess.STDOUT, - ) - assert not int(result) - except subprocess.CalledProcessError as ex: - raise RuntimeError( - f"command '{ex.cmd}' returns with error (code {ex.returncode}): {ex.output}" - ) + number_of_files = 1 + sleep(30) # wait when the cleaning job from rq worker will be started + for _ in range(15): + sleep(2) + try: + result = subprocess.check_output( + f'docker exec test_cvat_server_1 bash -c "ls data/tasks/{task_id}/tmp | wc -l"', + shell=True, + stderr=subprocess.STDOUT, + ) + number_of_files = int(result) + if not number_of_files: + break + except subprocess.CalledProcessError as ex: + raise RuntimeError( + f"command '{ex.cmd}' returns with error (code {ex.returncode}): {ex.output}" + ) + assert not number_of_files From 555cc3106d734fb5cba267328f99f4312ab899f0 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 29 May 2023 10:05:07 +0200 Subject: [PATCH 61/68] Use docker_exec_cvat and kube_exec_cvat --- tests/python/pytest.ini | 1 - tests/python/rest_api/test_tasks.py | 28 +++++++++++----------------- tests/python/shared/fixtures/init.py | 4 ++-- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/tests/python/pytest.ini b/tests/python/pytest.ini index 91c678fa625..05cda52273d 100644 --- a/tests/python/pytest.ini +++ b/tests/python/pytest.ini @@ -8,4 +8,3 @@ timeout = 15 markers = with_external_services: The test requires services extrernal to the default CVAT deployment, e.g. a Git server etc. - only_docker_test: The test that should only be running when CVAT is deployed in Docker. diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index a7d3a23c1c6..60f61cd7104 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -7,7 +7,6 @@ import json import os import os.path as osp -import subprocess from copy import deepcopy from functools import partial from http import HTTPStatus @@ -29,6 +28,7 @@ from PIL import Image import shared.utils.s3 as s3 +from shared.fixtures.init import docker_exec_cvat, kube_exec_cvat from shared.utils.config import ( BASE_URL, USER_PASS, @@ -1809,9 +1809,8 @@ def test_can_import_annotations_after_previous_unclear_import( task.import_annotations(self.format, filename) self._check_annotations(task_id) - @pytest.mark.only_docker_test @pytest.mark.timeout(70) - def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_shapes): + def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_shapes, request): task_id = tasks_with_shapes[0]["id"] with NamedTemporaryFile() as f: filename = self.tmp_dir / f"task_{task_id}_{Path(f.name).name}_coco.zip" @@ -1829,20 +1828,15 @@ def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_s url, filename, meta=params, logger=self.client.logger.debug ) number_of_files = 1 - sleep(30) # wait when the cleaning job from rq worker will be started + sleep(30) # wait when the cleaning job from rq worker will be started + command = ["bash", "-c", f"ls data/tasks/{task_id}/tmp | wc -l"] + platform = request.config.getoption("--platform") + assert platform in ("kube", "local") + func = docker_exec_cvat if platform == "local" else kube_exec_cvat for _ in range(15): sleep(2) - try: - result = subprocess.check_output( - f'docker exec test_cvat_server_1 bash -c "ls data/tasks/{task_id}/tmp | wc -l"', - shell=True, - stderr=subprocess.STDOUT, - ) - number_of_files = int(result) - if not number_of_files: - break - except subprocess.CalledProcessError as ex: - raise RuntimeError( - f"command '{ex.cmd}' returns with error (code {ex.returncode}): {ex.output}" - ) + result, _ = func(command) + number_of_files = int(result) + if not number_of_files: + break assert not number_of_files diff --git a/tests/python/shared/fixtures/init.py b/tests/python/shared/fixtures/init.py index e606d5ed4bf..de48d468eb0 100644 --- a/tests/python/shared/fixtures/init.py +++ b/tests/python/shared/fixtures/init.py @@ -120,12 +120,12 @@ def kube_cp(source, target): def docker_exec_cvat(command): - _run(f"docker exec {PREFIX}_cvat_server_1 {command}") + return _run(f"docker exec {PREFIX}_cvat_server_1 {command}") def kube_exec_cvat(command): pod_name = _kube_get_server_pod_name() - _run(f"kubectl exec {pod_name} -- {command}") + return _run(f"kubectl exec {pod_name} -- {command}") def docker_exec_cvat_db(command): From cc1a58172e7c26e43dc0231e446eccb7f21852ec Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 29 May 2023 11:18:13 +0200 Subject: [PATCH 62/68] d --- tests/python/shared/fixtures/init.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/shared/fixtures/init.py b/tests/python/shared/fixtures/init.py index de48d468eb0..cd4b6d099f2 100644 --- a/tests/python/shared/fixtures/init.py +++ b/tests/python/shared/fixtures/init.py @@ -84,7 +84,7 @@ def _run(command, capture_output=True): proc = run(_command, check=True) # nosec return stdout, stderr except CalledProcessError as exc: - stderr = exc.stderr.decode() if capture_output else "see above" + stderr = exc.stderr.decode() or exc.stdout.decode() if capture_output else "see above" pytest.exit( f"Command failed: {command}.\n" f"Error message: {stderr}.\n" From 9b2167d5ae7ffc7c2e22c995958bebcd830ce523 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 29 May 2023 12:17:34 +0200 Subject: [PATCH 63/68] Fix tests --- tests/python/rest_api/test_tasks.py | 2 +- tests/python/shared/fixtures/init.py | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index 60f61cd7104..e0b8ccad908 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -1829,7 +1829,7 @@ def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_s ) number_of_files = 1 sleep(30) # wait when the cleaning job from rq worker will be started - command = ["bash", "-c", f"ls data/tasks/{task_id}/tmp | wc -l"] + command = ["/bin/bash", "-c", f"ls data/tasks/{task_id}/tmp | wc -l"] platform = request.config.getoption("--platform") assert platform in ("kube", "local") func = docker_exec_cvat if platform == "local" else kube_exec_cvat diff --git a/tests/python/shared/fixtures/init.py b/tests/python/shared/fixtures/init.py index cd4b6d099f2..34c34379a9c 100644 --- a/tests/python/shared/fixtures/init.py +++ b/tests/python/shared/fixtures/init.py @@ -8,6 +8,7 @@ from pathlib import Path from subprocess import PIPE, CalledProcessError, run from time import sleep +from typing import Union, List import pytest import requests @@ -119,13 +120,17 @@ def kube_cp(source, target): _run(f"kubectl cp {source} {target}") -def docker_exec_cvat(command): - return _run(f"docker exec {PREFIX}_cvat_server_1 {command}") +def docker_exec_cvat(command: Union[List[str], str]): + base = f"docker exec {PREFIX}_cvat_server_1" + _command = f"{base} {command}" if isinstance(command, str) else base.split() + command + return _run(_command) -def kube_exec_cvat(command): +def kube_exec_cvat(command: Union[List[str], str]): pod_name = _kube_get_server_pod_name() - return _run(f"kubectl exec {pod_name} -- {command}") + base = f"kubectl exec {pod_name} --" + _command = f"{base} {command}" if isinstance(command, str) else base.split() + command + return _run(_command) def docker_exec_cvat_db(command): From 2e715dabae96d955d35736f6dd525a6a19cc27a3 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 29 May 2023 12:22:40 +0200 Subject: [PATCH 64/68] Rename RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER to IMPORT_CACHE_CLEAN_DELAY --- cvat/apps/engine/handlers.py | 2 +- cvat/apps/engine/mixins.py | 4 ++-- cvat/settings/base.py | 2 +- cvat/settings/testing_rest.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cvat/apps/engine/handlers.py b/cvat/apps/engine/handlers.py index 534b4c7bf13..3253957dd3e 100644 --- a/cvat/apps/engine/handlers.py +++ b/cvat/apps/engine/handlers.py @@ -17,6 +17,6 @@ def clear_import_cache(path: Path, creation_time: float) -> None: path (Path): path to file creation_time (float): file creation time """ - if path.is_file() and (time() - creation_time + 1) >= settings.RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER.total_seconds(): + if path.is_file() and (time() - creation_time + 1) >= settings.IMPORT_CACHE_CLEAN_DELAY.total_seconds(): path.unlink() slogger.glob.warning(f"The file {str(path)} was removed from cleaning job.") diff --git a/cvat/apps/engine/mixins.py b/cvat/apps/engine/mixins.py index 92d1f0c7354..1906da6c990 100644 --- a/cvat/apps/engine/mixins.py +++ b/cvat/apps/engine/mixins.py @@ -267,7 +267,7 @@ def init_tus_upload(self, request): if import_type in ('backup', 'annotations', 'datasets'): scheduler = django_rq.get_scheduler(settings.CVAT_QUEUES.CLEANING.value) path = Path(self.get_upload_dir()) / tus_file.filename - cleaning_job = scheduler.enqueue_in(time_delta=settings.RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER, + cleaning_job = scheduler.enqueue_in(time_delta=settings.IMPORT_CACHE_CLEAN_DELAY, func=clear_import_cache, path=path, creation_time=Path(tus_file.file_path).stat().st_ctime @@ -275,7 +275,7 @@ def init_tus_upload(self, request): slogger.glob.info( f'The cleaning job {cleaning_job.id} is queued.' f'The check that the file {path} is deleted will be carried out after ' - f'{settings.RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER}.' + f'{settings.IMPORT_CACHE_CLEAN_DELAY}.' ) return self._tus_response( diff --git a/cvat/settings/base.py b/cvat/settings/base.py index 1fe62871594..4b04ea8d79e 100644 --- a/cvat/settings/base.py +++ b/cvat/settings/base.py @@ -677,4 +677,4 @@ class CVAT_QUEUES(Enum): IMPORT_CACHE_FAILED_TTL = timedelta(days=90) IMPORT_CACHE_SUCCESS_TTL = timedelta(hours=1) -RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER = timedelta(hours=2) +IMPORT_CACHE_CLEAN_DELAY = timedelta(hours=2) diff --git a/cvat/settings/testing_rest.py b/cvat/settings/testing_rest.py index a2523ec8827..5fb329732f2 100644 --- a/cvat/settings/testing_rest.py +++ b/cvat/settings/testing_rest.py @@ -11,4 +11,4 @@ "django.contrib.auth.hashers.MD5PasswordHasher", ] -RUN_CLEAN_IMPORT_CACHE_FUNC_AFTER = timedelta(seconds=30) +IMPORT_CACHE_CLEAN_DELAY = timedelta(seconds=30) From c42faf8413c8d040bdec17ec2e5f7677e568d595 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 29 May 2023 12:56:10 +0200 Subject: [PATCH 65/68] Try to reduce timeout --- tests/python/rest_api/test_tasks.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index e0b8ccad908..aa1923bc175 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -1761,7 +1761,7 @@ def _delete_annotations(self, task_id): (_, response) = api_client.tasks_api.destroy_annotations(id=task_id) assert response.status == HTTPStatus.NO_CONTENT - @pytest.mark.timeout(70) + @pytest.mark.timeout(60) @pytest.mark.parametrize("successful_upload", [True, False]) def test_can_import_annotations_after_previous_unclear_import( self, successful_upload: bool, tasks_with_shapes @@ -1796,7 +1796,7 @@ def test_can_import_annotations_after_previous_unclear_import( rq_id = json.loads(response.data)["rq_id"] assert rq_id else: - required_time = 60 + required_time = 50 uploader._tus_start_upload(url, query_params=params) uploader._upload_file_data_with_tus( url, filename, meta=params, logger=self.client.logger.debug @@ -1809,7 +1809,7 @@ def test_can_import_annotations_after_previous_unclear_import( task.import_annotations(self.format, filename) self._check_annotations(task_id) - @pytest.mark.timeout(70) + @pytest.mark.timeout(60) def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_shapes, request): task_id = tasks_with_shapes[0]["id"] with NamedTemporaryFile() as f: From 8bf7f42fe38d5cf0b1164734743e196ecd03fc9d Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 29 May 2023 12:57:47 +0200 Subject: [PATCH 66/68] Fix isort issue --- tests/python/shared/fixtures/init.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/shared/fixtures/init.py b/tests/python/shared/fixtures/init.py index 34c34379a9c..792fe36825f 100644 --- a/tests/python/shared/fixtures/init.py +++ b/tests/python/shared/fixtures/init.py @@ -8,7 +8,7 @@ from pathlib import Path from subprocess import PIPE, CalledProcessError, run from time import sleep -from typing import Union, List +from typing import List, Union import pytest import requests From 335dbd20b4bc3b69c1f3e3c4a56f42ab2f50f17f Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Mon, 29 May 2023 12:58:47 +0100 Subject: [PATCH 67/68] increase timeout --- tests/python/rest_api/test_tasks.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/python/rest_api/test_tasks.py b/tests/python/rest_api/test_tasks.py index aa1923bc175..2d4d666229e 100644 --- a/tests/python/rest_api/test_tasks.py +++ b/tests/python/rest_api/test_tasks.py @@ -1761,7 +1761,7 @@ def _delete_annotations(self, task_id): (_, response) = api_client.tasks_api.destroy_annotations(id=task_id) assert response.status == HTTPStatus.NO_CONTENT - @pytest.mark.timeout(60) + @pytest.mark.timeout(64) @pytest.mark.parametrize("successful_upload", [True, False]) def test_can_import_annotations_after_previous_unclear_import( self, successful_upload: bool, tasks_with_shapes @@ -1796,7 +1796,7 @@ def test_can_import_annotations_after_previous_unclear_import( rq_id = json.loads(response.data)["rq_id"] assert rq_id else: - required_time = 50 + required_time = 54 uploader._tus_start_upload(url, query_params=params) uploader._upload_file_data_with_tus( url, filename, meta=params, logger=self.client.logger.debug @@ -1809,7 +1809,7 @@ def test_can_import_annotations_after_previous_unclear_import( task.import_annotations(self.format, filename) self._check_annotations(task_id) - @pytest.mark.timeout(60) + @pytest.mark.timeout(64) def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_shapes, request): task_id = tasks_with_shapes[0]["id"] with NamedTemporaryFile() as f: @@ -1833,7 +1833,7 @@ def test_check_import_cache_after_previous_interrupted_upload(self, tasks_with_s platform = request.config.getoption("--platform") assert platform in ("kube", "local") func = docker_exec_cvat if platform == "local" else kube_exec_cvat - for _ in range(15): + for _ in range(12): sleep(2) result, _ = func(command) number_of_files = int(result) From 651837663b2815e48ea4d972390a63ab08ad0f33 Mon Sep 17 00:00:00 2001 From: Maria Khrustaleva Date: Thu, 1 Jun 2023 10:23:06 +0100 Subject: [PATCH 68/68] Update changelog --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26608ea2d1a..363130ed983 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support task creation with any type of data supported by the server by default from cloud storage without use_cache option () - Support task creation with cloud storage data and without use_cache option () +- Cleaning worker to check that the uploaded resource has been deleted or delete otherwise () ### Changed - Resource links are opened from any organization/sandbox if available for user () @@ -31,6 +32,12 @@ without use_cache option () ### Fixed - Skeletons dumping on created tasks/projects () - Fix saving annotations for skeleton tracks () +- Wrong location of tmp file when importing job annotations () +- Removing uploaded file with annotations/backups when rq job was created +but no next requests for checking status were not made () +- Removing uploaded file with annotations/backups after file was uploaded to the server by tus protocol +but rq job has not yet been created () +- Tasks/projects creation from backups with the same name at the same time by different users () ### Security - TDB