diff --git a/pyproject.toml b/pyproject.toml index d881deb..b89d892 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ dependencies = [ "cryptography>=45.0.7", "django==5.2.6", "django-allauth>=65.10.0", + "django-auditlog>=3.2.1", "django-fernet-encrypted-fields>=0.3.0", "django-jsonform>=2.23.2", "django-scopes>=2.0.0", diff --git a/src/servala/core/admin.py b/src/servala/core/admin.py index ed07574..149635c 100644 --- a/src/servala/core/admin.py +++ b/src/servala/core/admin.py @@ -272,8 +272,8 @@ class ControlPlaneCRDAdmin(admin.ModelAdmin): @admin.register(ServiceInstance) class ServiceInstanceAdmin(admin.ModelAdmin): - list_display = ("name", "organization", "context", "created_by", "is_deleted") - list_filter = ("organization", "context", "is_deleted") + list_display = ("name", "organization", "context", "created_by") + list_filter = ("organization", "context") search_fields = ( "name", "organization__name", @@ -296,9 +296,6 @@ class ServiceInstanceAdmin(admin.ModelAdmin): "organization", "context", "created_by", - "is_deleted", - "deleted_at", - "deleted_by", ) }, ), diff --git a/src/servala/core/migrations/0006_remove_service_instance_soft_delete.py b/src/servala/core/migrations/0006_remove_service_instance_soft_delete.py new file mode 100644 index 0000000..0fcc02a --- /dev/null +++ b/src/servala/core/migrations/0006_remove_service_instance_soft_delete.py @@ -0,0 +1,25 @@ +# Generated by Django 5.2.4 on 2025-09-03 23:08 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0005_organization_sale_order_fields"), + ] + + operations = [ + migrations.RemoveField( + model_name="serviceinstance", + name="deleted_at", + ), + migrations.RemoveField( + model_name="serviceinstance", + name="deleted_by", + ), + migrations.RemoveField( + model_name="serviceinstance", + name="is_deleted", + ), + ] diff --git a/src/servala/core/models/service.py b/src/servala/core/models/service.py index a06db4e..6944750 100644 --- a/src/servala/core/models/service.py +++ b/src/servala/core/models/service.py @@ -6,11 +6,11 @@ import re import kubernetes import rules import urlman +from auditlog.registry import auditlog from django.conf import settings from django.core.cache import cache from django.core.exceptions import ValidationError from django.db import IntegrityError, models, transaction -from django.utils import timezone from django.utils.functional import cached_property from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ @@ -571,16 +571,6 @@ class ServiceInstance(ServalaModelMixin, models.Model): on_delete=models.PROTECT, ) - is_deleted = models.BooleanField(default=False) - deleted_at = models.DateTimeField(null=True, blank=True) - deleted_by = models.ForeignKey( - to="core.User", - on_delete=models.SET_NULL, - null=True, - blank=True, - related_name="+", - ) - class Meta: verbose_name = _("Service instance") verbose_name_plural = _("Service instances") @@ -794,14 +784,10 @@ class ServiceInstance(ServalaModelMixin, models.Model): raise ValidationError(self.organization.add_support_message(message)) @transaction.atomic - def delete_instance(self, user): + def delete(self, using=None, keep_parents=False, user=None): """ - Soft deletes the instance in Django and initiates deletion of the - corresponding Kubernetes custom resource. + Deletes the Django instance and the corresponding Kubernetes custom resource. """ - if self.is_deleted: - return - if ( self.spec.get("parameters", {}) .get("security", {}) @@ -825,19 +811,13 @@ class ServiceInstance(ServalaModelMixin, models.Model): if e.status != 404: # 404 is fine, the object was deleted already. raise - self.is_deleted = True - self.deleted_at = timezone.now() - self.deleted_by = user - self.save( - update_fields=["is_deleted", "deleted_at", "deleted_by", "updated_at"] - ) + self._clear_kubernetes_caches() + return super().delete(using=using, keep_parents=keep_parents) @cached_property def kubernetes_object(self): """Fetch the Kubernetes custom resource object""" - if self.is_deleted: - return try: api_instance = client.CustomObjectsApi( self.context.control_plane.get_kubernetes_client() @@ -942,3 +922,6 @@ class ServiceInstance(ServalaModelMixin, models.Model): return {"error": str(e)} except Exception as e: return {"error": str(e)} + + +auditlog.register(ServiceInstance, exclude_fields=["updated_at"], serialize_data=True) diff --git a/src/servala/frontend/forms/service.py b/src/servala/frontend/forms/service.py index ca84ab3..5dd78a7 100644 --- a/src/servala/frontend/forms/service.py +++ b/src/servala/frontend/forms/service.py @@ -64,14 +64,6 @@ class ServiceInstanceFilterForm(forms.Form): required=False, label=_("Service Provider Zone"), ) - status = forms.ChoiceField( - choices=( - ("active", _("Active")), - ("deleted", _("Deleted")), - ), - required=False, - label=_("Status"), - ) def filter_queryset(self, queryset): if self.is_valid(): @@ -88,11 +80,6 @@ class ServiceInstanceFilterForm(forms.Form): ) if data.get("control_plane"): queryset = queryset.filter(context__control_plane=data["control_plane"]) - status = data.get("status") - if status == "active": - queryset = queryset.filter(is_deleted=False) - elif status == "deleted": - queryset = queryset.filter(is_deleted=True) return queryset diff --git a/src/servala/frontend/templates/frontend/organizations/dashboard.html b/src/servala/frontend/templates/frontend/organizations/dashboard.html index b0dd273..01faa69 100644 --- a/src/servala/frontend/templates/frontend/organizations/dashboard.html +++ b/src/servala/frontend/templates/frontend/organizations/dashboard.html @@ -112,13 +112,6 @@ {{ instance.context.service_offering.service.name }} -