diff --git a/backend/ciso_assistant/settings.py b/backend/ciso_assistant/settings.py index 181be77f7..57a49361b 100644 --- a/backend/ciso_assistant/settings.py +++ b/backend/ciso_assistant/settings.py @@ -286,6 +286,9 @@ def set_ciso_assistant_url(_, __, event_dict): "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": BASE_DIR / "db/ciso-assistant.sqlite3", + "OPTIONS": { + 'timeout': 120, + }, } } logger.info("DATABASE ENGINE: %s", DATABASES["default"]["ENGINE"]) diff --git a/backend/library/utils.py b/backend/library/utils.py index 673635e17..c8f337798 100644 --- a/backend/library/utils.py +++ b/backend/library/utils.py @@ -1,4 +1,5 @@ import json +import time import os from pathlib import Path import re @@ -19,6 +20,7 @@ from django.db import transaction from iam.models import Folder +from django.db.utils import OperationalError import structlog logger = structlog.get_logger(__name__) @@ -205,7 +207,6 @@ def import_requirement_node(self, framework_object: Framework): ReferenceControl.objects.get(urn=reference_control.lower()) ) - # The couple (URN, locale) is unique. ===> Check it in the future class FrameworkImporter: REQUIRED_FIELDS = {"ref_id", "urn"} @@ -577,6 +578,16 @@ def import_objects(self, library_object): for risk_matrix in self._risk_matrices: risk_matrix.import_risk_matrix(library_object) + @transaction.atomic + def _import_library(self) : + library_object = self.create_or_update_library() + self.import_objects(library_object) + library_object.dependencies.set( + Library.objects.filter( + urn__in=self._library_data.get("dependencies", []) + ) + ) + def import_library(self): """Main method to import a library.""" if (error_message := self.init()) is not None: @@ -584,20 +595,19 @@ def import_library(self): self.check_and_import_dependencies() - try: - with transaction.atomic(): - library_object = self.create_or_update_library() - self.import_objects(library_object) - library_object.dependencies.set( - Library.objects.filter( - urn__in=self._library_data.get("dependencies", []) - ) - ) - except Exception as e: - # TODO: Switch to proper logging - print(f"Library import exception: {e}") - raise - + for _ in range(10) : + try: + self._import_library() + break + except OperationalError as e : + if e.args and e.args[0] == 'database is locked' : + time.sleep(1) + else : + raise e + except Exception as e : + # TODO: Switch to proper logging + print(f"Library import exception: {e}") + raise e def import_library_view(library: dict) -> Union[str, None]: """ diff --git a/backend/library/views.py b/backend/library/views.py index 24e9073b4..54baf8d51 100644 --- a/backend/library/views.py +++ b/backend/library/views.py @@ -66,7 +66,8 @@ def destroy(self, request, *args, pk, **kwargs): if library is None: return Response(data="Library not found.", status=status.HTTP_404_NOT_FOUND) - if library["reference_count"] != 0: + # "reference_count" is not always defined (is this normal ?) + if library.get("reference_count",0) != 0 : return Response( data="Library cannot be deleted because it has references.", status=status.HTTP_400_BAD_REQUEST, @@ -119,7 +120,6 @@ def import_library(self, request, pk=None): import_library_view(library) return Response({"status": "success"}) except Exception as e: - print(e) return Response( { "error": "Failed to load library, please check if it has dependencies"